mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 13:02:07 +03:00
Merge ordered and unordered comparators (#5845)
Merge _ordered_ and _unordered_ comparators into a single one. # Important Notes Comparator is now required to have only `compare` method: ``` type Comparator comapre : T -> T -> (Ordering|Nothing) hash : T -> Integer ```
This commit is contained in:
parent
a7f1ba96a9
commit
5f7a4a5a39
@ -614,6 +614,7 @@
|
|||||||
- [Update to GraalVM 22.3.1][5602]
|
- [Update to GraalVM 22.3.1][5602]
|
||||||
- [Cache library bindings to optimize import/export resolution][5700]
|
- [Cache library bindings to optimize import/export resolution][5700]
|
||||||
- [Comparators support partial ordering][5778]
|
- [Comparators support partial ordering][5778]
|
||||||
|
- [Merge ordered and unordered comparators][5845]
|
||||||
- [Use SHA-1 for calculating hashes of modules' IR and bindings][5791]
|
- [Use SHA-1 for calculating hashes of modules' IR and bindings][5791]
|
||||||
|
|
||||||
[3227]: https://github.com/enso-org/enso/pull/3227
|
[3227]: https://github.com/enso-org/enso/pull/3227
|
||||||
@ -713,6 +714,7 @@
|
|||||||
[5602]: https://github.com/enso-org/enso/pull/5602
|
[5602]: https://github.com/enso-org/enso/pull/5602
|
||||||
[5700]: https://github.com/enso-org/enso/pull/5700
|
[5700]: https://github.com/enso-org/enso/pull/5700
|
||||||
[5778]: https://github.com/enso-org/enso/pull/5778
|
[5778]: https://github.com/enso-org/enso/pull/5778
|
||||||
|
[5845]: https://github.com/enso-org/enso/pull/5845
|
||||||
[5791]: https://github.com/enso-org/enso/pull/5791
|
[5791]: https://github.com/enso-org/enso/pull/5791
|
||||||
|
|
||||||
# Enso 2.0.0-alpha.18 (2021-10-12)
|
# Enso 2.0.0-alpha.18 (2021-10-12)
|
||||||
|
@ -108,26 +108,19 @@ type Any
|
|||||||
== self that =
|
== self that =
|
||||||
# If there is No_Such_Conversion, then `self` and `that` are probably
|
# If there is No_Such_Conversion, then `self` and `that` are probably
|
||||||
# host or polyglot values, so we just compare them with the default comparator.
|
# host or polyglot values, so we just compare them with the default comparator.
|
||||||
eq_self = Panic.catch No_Such_Conversion (Comparable.from self) _-> Default_Unordered_Comparator
|
eq_self = Panic.catch No_Such_Conversion (Comparable.from self) _-> Default_Comparator
|
||||||
eq_that = Panic.catch No_Such_Conversion (Comparable.from that) _-> Default_Unordered_Comparator
|
eq_that = Panic.catch No_Such_Conversion (Comparable.from that) _-> Default_Comparator
|
||||||
case Meta.is_same_object eq_self Incomparable of
|
similar_type = Meta.is_same_object eq_self eq_that
|
||||||
True -> False
|
case similar_type of
|
||||||
False ->
|
False -> False
|
||||||
similar_type = Meta.is_same_object eq_self eq_that
|
True ->
|
||||||
case similar_type of
|
case Meta.is_same_object eq_self Default_Comparator of
|
||||||
False -> False
|
# Shortcut for objects with Default_Comparator, because of the performance.
|
||||||
True ->
|
True -> Comparable.equals_builtin self that
|
||||||
case eq_self.is_ordered of
|
False ->
|
||||||
True ->
|
case eq_self.compare self that of
|
||||||
res = eq_self.compare self that
|
Ordering.Equal -> True
|
||||||
case res of
|
_ -> False
|
||||||
Ordering.Equal -> True
|
|
||||||
_ -> False
|
|
||||||
False ->
|
|
||||||
res = eq_self.equals self that
|
|
||||||
case res of
|
|
||||||
Nothing -> False
|
|
||||||
_ -> res
|
|
||||||
|
|
||||||
## ALIAS Inequality
|
## ALIAS Inequality
|
||||||
|
|
||||||
@ -159,8 +152,10 @@ type Any
|
|||||||
Arguments:
|
Arguments:
|
||||||
- that: The value to compare `self` against.
|
- that: The value to compare `self` against.
|
||||||
|
|
||||||
To have `>` properly defined, a type must have an associated ordered comparator.
|
To be comparable, a custom object must have an associated comparator
|
||||||
See `Ordering.enso` for information how comparators work.
|
which will return `Ordering.Less/Greater` for unequal values. Otherwise,
|
||||||
|
this will raise `Incomparable_Values` error. See `Ordering.enso` for
|
||||||
|
information how comparators work.
|
||||||
|
|
||||||
> Example
|
> Example
|
||||||
Checking if the variable `a` is greater than `147`.
|
Checking if the variable `a` is greater than `147`.
|
||||||
@ -172,7 +167,7 @@ type Any
|
|||||||
a > 147
|
a > 147
|
||||||
> : Any -> Boolean ! Incomparable_Values
|
> : Any -> Boolean ! Incomparable_Values
|
||||||
> self that =
|
> self that =
|
||||||
assert_ordered_comparators self that <|
|
assert_same_comparators self that <|
|
||||||
case (Comparable.from self).compare self that of
|
case (Comparable.from self).compare self that of
|
||||||
Ordering.Greater -> True
|
Ordering.Greater -> True
|
||||||
Nothing -> Error.throw (Incomparable_Values.Error self that)
|
Nothing -> Error.throw (Incomparable_Values.Error self that)
|
||||||
@ -185,8 +180,6 @@ type Any
|
|||||||
Arguments:
|
Arguments:
|
||||||
- that: The value to compare `self` against.
|
- that: The value to compare `self` against.
|
||||||
|
|
||||||
To have `>=` defined, a type must define both `>` and `==`.
|
|
||||||
|
|
||||||
! Implementing Greater Than or Equal
|
! Implementing Greater Than or Equal
|
||||||
While it is often possible to implement a more efficient version of this
|
While it is often possible to implement a more efficient version of this
|
||||||
operation for complex types, care must be taken to ensure that your
|
operation for complex types, care must be taken to ensure that your
|
||||||
@ -203,12 +196,12 @@ type Any
|
|||||||
a >= 147
|
a >= 147
|
||||||
>= : Any -> Boolean ! Incomparable_Values
|
>= : Any -> Boolean ! Incomparable_Values
|
||||||
>= self that =
|
>= self that =
|
||||||
assert_ordered_comparators self that <|
|
assert_same_comparators self that <|
|
||||||
case (Comparable.from self).compare self that of
|
case (Comparable.from self).compare self that of
|
||||||
Ordering.Less -> False
|
|
||||||
Ordering.Equal -> True
|
Ordering.Equal -> True
|
||||||
Ordering.Greater -> True
|
Ordering.Greater -> True
|
||||||
Nothing -> Error.throw (Incomparable_Values.Error self that)
|
Nothing -> Error.throw (Incomparable_Values.Error self that)
|
||||||
|
_ -> False
|
||||||
|
|
||||||
## ALIAS Less Than
|
## ALIAS Less Than
|
||||||
|
|
||||||
@ -217,8 +210,10 @@ type Any
|
|||||||
Arguments:
|
Arguments:
|
||||||
- that: The value to compare `self` against.
|
- that: The value to compare `self` against.
|
||||||
|
|
||||||
To have `<` properly defined, a type must have an associated ordered comparator.
|
To be comparable, a custom object must have an associated comparator
|
||||||
See `Ordering.enso` for information how comparators work.
|
which will return `Ordering.Less/Greater` for unequal values. Otherwise,
|
||||||
|
this will raise `Incomparable_Values` error. See `Ordering.enso` for
|
||||||
|
information how comparators work.
|
||||||
|
|
||||||
> Example
|
> Example
|
||||||
Checking if the variable `a` is less than `147`.
|
Checking if the variable `a` is less than `147`.
|
||||||
@ -230,7 +225,7 @@ type Any
|
|||||||
a < 147
|
a < 147
|
||||||
< : Any -> Boolean ! Incomparable_Values
|
< : Any -> Boolean ! Incomparable_Values
|
||||||
< self that =
|
< self that =
|
||||||
assert_ordered_comparators self that <|
|
assert_same_comparators self that <|
|
||||||
case (Comparable.from self).compare self that of
|
case (Comparable.from self).compare self that of
|
||||||
Ordering.Less -> True
|
Ordering.Less -> True
|
||||||
Nothing -> Error.throw (Incomparable_Values.Error self that)
|
Nothing -> Error.throw (Incomparable_Values.Error self that)
|
||||||
@ -261,12 +256,12 @@ type Any
|
|||||||
a < 147
|
a < 147
|
||||||
<= : Any -> Boolean ! Incomparable_Values
|
<= : Any -> Boolean ! Incomparable_Values
|
||||||
<= self that =
|
<= self that =
|
||||||
assert_ordered_comparators self that <|
|
assert_same_comparators self that <|
|
||||||
case (Comparable.from self).compare self that of
|
case (Comparable.from self).compare self that of
|
||||||
Ordering.Less -> True
|
|
||||||
Ordering.Equal -> True
|
Ordering.Equal -> True
|
||||||
Ordering.Greater -> False
|
Ordering.Less -> True
|
||||||
Nothing -> Error.throw (Incomparable_Values.Error self that)
|
Nothing -> Error.throw (Incomparable_Values.Error self that)
|
||||||
|
_ -> False
|
||||||
|
|
||||||
## Checks if the type is an instance of `Nothing`.
|
## Checks if the type is an instance of `Nothing`.
|
||||||
|
|
||||||
@ -456,13 +451,12 @@ type Any
|
|||||||
|
|
||||||
|
|
||||||
## PRIVATE
|
## PRIVATE
|
||||||
Checks if both comparators of the given objects are both of same type and ordered.
|
Checks if the comparators for the given objects are both of the same type. If so,
|
||||||
If they are not of same type, a `Type_Error` is thrown.
|
proceeds with the given action, and if not, throws `Type_Error`.
|
||||||
If the comparators are either `Incomparable`, or unordered, `False` is returned.
|
assert_same_comparators : Any -> Any -> (Any -> Any) -> Any ! Type_Error
|
||||||
assert_ordered_comparators : Any -> (Any -> Any) -> Any ! (Type_Error | Incomparable_Values)
|
assert_same_comparators this that ~action =
|
||||||
assert_ordered_comparators this that ~action =
|
|
||||||
comp_this = Comparable.from this
|
comp_this = Comparable.from this
|
||||||
comp_that = Comparable.from that
|
comp_that = Comparable.from that
|
||||||
if (Meta.is_same_object comp_this comp_that).not then Error.throw (Type_Error.Error (Meta.type_of comp_this) comp_that "comp_that") else
|
case Meta.is_same_object comp_this comp_that of
|
||||||
if Meta.is_same_object comp_this Incomparable || comp_this.is_ordered.not then Error.throw (Incomparable_Values.Error this that) else
|
True -> action
|
||||||
action
|
False -> Error.throw (Type_Error.Error (Meta.type_of comp_this) comp_that "comp_that")
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import project.Any.Any
|
import project.Any.Any
|
||||||
import project.Data.Ordering.Ordering
|
import project.Data.Ordering.Ordering
|
||||||
import project.Data.Ordering.Comparable
|
import project.Data.Ordering.Comparable
|
||||||
import project.Data.Ordering.Default_Ordered_Comparator
|
|
||||||
import project.Nothing.Nothing
|
import project.Nothing.Nothing
|
||||||
|
|
||||||
from project.Data.Boolean.Boolean import True, False
|
from project.Data.Boolean.Boolean import True, False
|
||||||
@ -90,5 +89,3 @@ type Boolean
|
|||||||
if_then : Any -> Any | Nothing
|
if_then : Any -> Any | Nothing
|
||||||
if_then self ~on_true = @Builtin_Method "Boolean.if_then"
|
if_then self ~on_true = @Builtin_Method "Boolean.if_then"
|
||||||
|
|
||||||
|
|
||||||
Comparable.from (_:Boolean) = Default_Ordered_Comparator
|
|
||||||
|
@ -185,15 +185,13 @@ type JS_Object
|
|||||||
|
|
||||||
## PRIVATE
|
## PRIVATE
|
||||||
type JS_Object_Comparator
|
type JS_Object_Comparator
|
||||||
is_ordered : Boolean
|
compare : JS_Object -> JS_Object -> (Ordering|Nothing)
|
||||||
is_ordered = False
|
compare obj1 obj2 =
|
||||||
|
|
||||||
equals : JS_Object -> JS_Object -> Boolean
|
|
||||||
equals obj1 obj2 =
|
|
||||||
obj1_keys = obj1.field_names
|
obj1_keys = obj1.field_names
|
||||||
obj2_keys = obj2.field_names
|
obj2_keys = obj2.field_names
|
||||||
obj1_keys.length == obj2_keys.length && obj1_keys.all key->
|
same_values = obj1_keys.length == obj2_keys.length && obj1_keys.all key->
|
||||||
(obj1.get key == obj2.at key).catch No_Such_Key _->False
|
(obj1.get key == obj2.at key).catch No_Such_Key _->False
|
||||||
|
if same_values then Ordering.Equal else Nothing
|
||||||
|
|
||||||
hash : JS_Object -> Integer
|
hash : JS_Object -> Integer
|
||||||
hash obj =
|
hash obj =
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
import project.Data.Ordering.Ordering
|
|
||||||
import project.Data.Ordering.Comparable
|
|
||||||
import project.Data.Ordering.Incomparable
|
|
||||||
import project.Data.Ordering.Default_Ordered_Comparator
|
|
||||||
import project.Data.Text.Text
|
import project.Data.Text.Text
|
||||||
import project.Data.Locale.Locale
|
import project.Data.Locale.Locale
|
||||||
import project.Error.Common.Arithmetic_Error
|
import project.Error.Common.Arithmetic_Error
|
||||||
@ -941,8 +937,6 @@ type Integer
|
|||||||
|
|
||||||
parse_builtin text radix = @Builtin_Method "Integer.parse"
|
parse_builtin text radix = @Builtin_Method "Integer.parse"
|
||||||
|
|
||||||
Comparable.from (_:Number) = Default_Ordered_Comparator
|
|
||||||
|
|
||||||
## UNSTABLE
|
## UNSTABLE
|
||||||
|
|
||||||
A syntax error when parsing a double.
|
A syntax error when parsing a double.
|
||||||
|
@ -23,42 +23,29 @@ from project.Data.Boolean import all
|
|||||||
|
|
||||||
Should there be a need to redefine the default implementation, here is a way:
|
Should there be a need to redefine the default implementation, here is a way:
|
||||||
Define conversion function `Comparable.from` for your `type` and return pointer to
|
Define conversion function `Comparable.from` for your `type` and return pointer to
|
||||||
another `type` that satisfies either of the following two definitions:
|
another `type` that satisfies the following definition:
|
||||||
|
|
||||||
```
|
```
|
||||||
type Ordered_Comparator T
|
type Comparator T
|
||||||
is_ordered = True
|
|
||||||
compare : T -> T -> (Ordering|Nothing)
|
compare : T -> T -> (Ordering|Nothing)
|
||||||
hash : T -> Integer
|
hash : T -> Integer
|
||||||
|
|
||||||
type Unordered_Comparator T
|
|
||||||
is_ordered = False
|
|
||||||
equals : T -> T -> (Boolean|Nothing)
|
|
||||||
hash : T -> Integer
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Or `Incomparable` in case that the type `T` should not be compared at all.
|
Every type must provide exactly one comparator, i.e., the method of form
|
||||||
|
`Comparable.from (_:My_Type)` must return the same comparator type for every
|
||||||
|
value. Note that there is an implicit `Default_Comparator` assigned for every
|
||||||
|
type by default.
|
||||||
|
|
||||||
Every type must provide exactly one comparator, i.e., any method of form
|
A comparator has to implement `compare` and `hash` methods. `compare x y` method
|
||||||
`Comparable.from (_:My_Type)` must always return the same comparator type.
|
returns `Ordering.Less` if x is ordered before y, `Ordering.Equal` if x is equal
|
||||||
Note that if there is an implicit `Default_Unordered_Comparator` assigned
|
to y, `Ordering.Greater` if x is ordered after y, and `Nothing` if x and y are
|
||||||
for every type by default.
|
not equal, and their relative ordering cannot be determined.
|
||||||
|
|
||||||
Note that there has to be `is_ordered` method defined which returns a Boolean
|
The signature of the `compare` method is designed so that it enables comparators
|
||||||
indicating that the comparator is ordered. This is currently needed as there is
|
to provide a _partial ordering_ for a specific type.
|
||||||
no way to define interfaces in Enso.
|
|
||||||
|
|
||||||
An _unordered comparator_ has to implement both `equals` and `hash` to define
|
A hash code must be provided for all the objects, therefore, the type signature
|
||||||
a _partial_ custom equality. By _partial_, we mean that every instance of the type
|
of `hash` method does not allow `Nothing` as a return value.
|
||||||
has to be either equal, not equal, or undefined, which is represented by the type signature
|
|
||||||
of `equals` - when a `Boolean` is returned, the two instances are either equal
|
|
||||||
or not equal, when `Nothing` is returned, the instances are incomparable.
|
|
||||||
|
|
||||||
An _ordered comparator_ has `compare` method instead of `equals` method, that is
|
|
||||||
expected to return `Ordering` signaling that an instance of the type is either
|
|
||||||
less than, equal to, or greater than the other instance, or `Nothing` signaling
|
|
||||||
that the two instances are incomparable. This relation may also be _partial_, meaning
|
|
||||||
that some of the instances may be incomparable.
|
|
||||||
|
|
||||||
The runtime expects the following semantics for all the comparators:
|
The runtime expects the following semantics for all the comparators:
|
||||||
- Hash consistency:
|
- Hash consistency:
|
||||||
@ -85,12 +72,10 @@ from project.Data.Boolean import all
|
|||||||
Value x y
|
Value x y
|
||||||
|
|
||||||
type UPair_Comparator
|
type UPair_Comparator
|
||||||
is_ordered = False
|
compare pair1 pair2 =
|
||||||
|
if pair1.x == pair2.x && pair1.y == pair2.y then Ordering.Equal else
|
||||||
equals pair1 pair2 =
|
if pair1.x == pair2.y && pair1.y == pair2.x then Ordering.Equal else
|
||||||
if pair1.x == pair2.x && pair1.y == pair2.y then True else
|
Nothing
|
||||||
if pair1.x == pair2.y && pair1.y == pair2.x then True else
|
|
||||||
False
|
|
||||||
|
|
||||||
hash upair =
|
hash upair =
|
||||||
x_comp = Comparable.from upair.x
|
x_comp = Comparable.from upair.x
|
||||||
@ -111,7 +96,6 @@ from project.Data.Boolean import all
|
|||||||
Comparable.from (_:Rational) = Rational_Ordering
|
Comparable.from (_:Rational) = Rational_Ordering
|
||||||
|
|
||||||
type Rational_Ordering
|
type Rational_Ordering
|
||||||
is_ordered = True
|
|
||||||
compare self r1 r2 =
|
compare self r1 r2 =
|
||||||
v1 = r1.numerator * r2.denominator
|
v1 = r1.numerator * r2.denominator
|
||||||
v2 = r2.numerator * r1.denominator
|
v2 = r2.numerator * r1.denominator
|
||||||
@ -124,19 +108,12 @@ from project.Data.Boolean import all
|
|||||||
By defining the `Rational_Ordering` and making it available via
|
By defining the `Rational_Ordering` and making it available via
|
||||||
`Comparable.from (_:Rational)` method, all parts of the Enso system will use
|
`Comparable.from (_:Rational)` method, all parts of the Enso system will use
|
||||||
the custom comparator whenever equality or hash code is needed.
|
the custom comparator whenever equality or hash code is needed.
|
||||||
|
|
||||||
The equality check of two objects:
|
|
||||||
- verifies both objects share the same type of `comparator`
|
|
||||||
- consults their `compare`, or `equals` method, based on whether the comparator is
|
|
||||||
ordered or unordered.
|
|
||||||
- if the result is `Ordering.Equal` the system also checks that both instances have the same `hash`
|
|
||||||
- the `hash` code check may be done only from time to time to speed things up
|
|
||||||
@Builtin_Type
|
@Builtin_Type
|
||||||
type Comparable
|
type Comparable
|
||||||
## PRIVATE
|
## PRIVATE
|
||||||
Called as a callback from internal engine code for an atom with a custom
|
Called as a callback from internal engine code for an atom with a custom
|
||||||
comparator. It is assumed that the given atom has a custom comparator, that is
|
comparator. It is assumed that the given atom has a custom comparator, that is
|
||||||
a comparator different than `Default_Unordered_Comparator`.
|
a comparator different than `Default_Comparator`.
|
||||||
hash_callback : Atom -> Integer
|
hash_callback : Atom -> Integer
|
||||||
hash_callback atom = (Comparable.from atom).hash atom
|
hash_callback atom = (Comparable.from atom).hash atom
|
||||||
|
|
||||||
@ -146,52 +123,30 @@ type Comparable
|
|||||||
has_custom_comparator : Atom -> Boolean
|
has_custom_comparator : Atom -> Boolean
|
||||||
has_custom_comparator atom =
|
has_custom_comparator atom =
|
||||||
comp = Comparable.from atom
|
comp = Comparable.from atom
|
||||||
(comp.is_a Default_Unordered_Comparator).not && (comp.is_a Default_Ordered_Comparator).not
|
(comp.is_a Default_Comparator).not
|
||||||
|
|
||||||
## Singleton denoting that values of certain type are not comparable.
|
## Default implementation of a _comparator_.
|
||||||
type Incomparable
|
|
||||||
Singleton
|
|
||||||
|
|
||||||
## Default implementation of unordered comparator.
|
|
||||||
@Builtin_Type
|
@Builtin_Type
|
||||||
type Default_Unordered_Comparator
|
type Default_Comparator
|
||||||
is_ordered = False
|
|
||||||
|
|
||||||
equals : Any -> Any -> (Boolean|Nothing)
|
|
||||||
equals x y = Comparable.equals_builtin x y
|
|
||||||
|
|
||||||
hash : Any -> Integer
|
|
||||||
hash object = Comparable.hash_builtin object
|
|
||||||
|
|
||||||
|
|
||||||
## Default implementation of an ordered _comparator_. Handles only primitive types,
|
|
||||||
does not handle atoms, or vectors. Any type that requires an ordering, must
|
|
||||||
define its own ordered comparator.
|
|
||||||
@Builtin_Type
|
|
||||||
type Default_Ordered_Comparator
|
|
||||||
is_ordered = True
|
|
||||||
|
|
||||||
## Handles only primitive types, not atoms or vectors.
|
|
||||||
compare : Any -> Any -> (Ordering|Nothing)
|
compare : Any -> Any -> (Ordering|Nothing)
|
||||||
compare x y =
|
compare x y =
|
||||||
case Comparable.less_than_builtin x y of
|
case Comparable.equals_builtin x y of
|
||||||
Nothing -> Nothing
|
True -> Ordering.Equal
|
||||||
True -> Ordering.Less
|
|
||||||
False ->
|
False ->
|
||||||
case Comparable.equals_builtin x y of
|
case Comparable.less_than_builtin x y of
|
||||||
Nothing -> Nothing
|
Nothing -> Nothing
|
||||||
True -> Ordering.Equal
|
True -> Ordering.Less
|
||||||
False ->
|
False ->
|
||||||
case Comparable.less_than_builtin y x of
|
case Comparable.less_than_builtin y x of
|
||||||
Nothing -> Nothing
|
Nothing -> Nothing
|
||||||
True -> Ordering.Greater
|
True -> Ordering.Greater
|
||||||
False -> Panic.throw (Illegal_State.Error "Unreachable")
|
False -> Nothing
|
||||||
|
|
||||||
hash : Number -> Integer
|
hash : Number -> Integer
|
||||||
hash x = Comparable.hash_builtin x
|
hash x = Comparable.hash_builtin x
|
||||||
|
|
||||||
|
|
||||||
Comparable.from (_:Any) = Default_Unordered_Comparator
|
Comparable.from (_:Any) = Default_Comparator
|
||||||
|
|
||||||
|
|
||||||
## Types representing the ordering of values.
|
## Types representing the ordering of values.
|
||||||
@ -250,7 +205,6 @@ type Ordering
|
|||||||
if sign > 0 then Ordering.Greater else Ordering.Less
|
if sign > 0 then Ordering.Greater else Ordering.Less
|
||||||
|
|
||||||
type Ordering_Comparator
|
type Ordering_Comparator
|
||||||
is_ordered = True
|
|
||||||
compare x y = (Comparable.from x.to_sign).compare x.to_sign y.to_sign
|
compare x y = (Comparable.from x.to_sign).compare x.to_sign y.to_sign
|
||||||
hash x = x.to_sign
|
hash x = x.to_sign
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import project.Error.Common.Type_Error
|
|||||||
import project.Error.Error
|
import project.Error.Error
|
||||||
import project.Meta
|
import project.Meta
|
||||||
|
|
||||||
from project.Data.Ordering import all
|
|
||||||
from project.Data.Boolean import Boolean, True, False
|
from project.Data.Boolean import Boolean, True, False
|
||||||
|
|
||||||
polyglot java import org.enso.base.Text_Utils
|
polyglot java import org.enso.base.Text_Utils
|
||||||
@ -118,5 +117,3 @@ type Text
|
|||||||
Conversion to Text that overrides the default `to_text` behavior.
|
Conversion to Text that overrides the default `to_text` behavior.
|
||||||
to_text : Text
|
to_text : Text
|
||||||
to_text self = self
|
to_text self = self
|
||||||
|
|
||||||
Comparable.from (_:Text) = Default_Ordered_Comparator
|
|
||||||
|
@ -4,7 +4,6 @@ import project.Data.Locale.Locale
|
|||||||
import project.Data.Numbers.Integer
|
import project.Data.Numbers.Integer
|
||||||
import project.Data.Ordering.Ordering
|
import project.Data.Ordering.Ordering
|
||||||
import project.Data.Ordering.Comparable
|
import project.Data.Ordering.Comparable
|
||||||
import project.Data.Ordering.Default_Ordered_Comparator
|
|
||||||
import project.Data.Text.Text
|
import project.Data.Text.Text
|
||||||
import project.Data.Time.Date_Period.Date_Period
|
import project.Data.Time.Date_Period.Date_Period
|
||||||
import project.Data.Time.Date_Time.Date_Time
|
import project.Data.Time.Date_Time.Date_Time
|
||||||
@ -627,6 +626,3 @@ is_weekend date =
|
|||||||
## PRIVATE
|
## PRIVATE
|
||||||
fits_in_range start end date =
|
fits_in_range start end date =
|
||||||
(start <= date) && (date < end)
|
(start <= date) && (date < end)
|
||||||
|
|
||||||
|
|
||||||
Comparable.from (_:Date) = Default_Ordered_Comparator
|
|
||||||
|
@ -4,7 +4,6 @@ import project.Data.Locale.Locale
|
|||||||
import project.Data.Numbers.Integer
|
import project.Data.Numbers.Integer
|
||||||
import project.Data.Ordering.Ordering
|
import project.Data.Ordering.Ordering
|
||||||
import project.Data.Ordering.Comparable
|
import project.Data.Ordering.Comparable
|
||||||
import project.Data.Ordering.Default_Ordered_Comparator
|
|
||||||
import project.Data.Text.Text
|
import project.Data.Text.Text
|
||||||
import project.Data.Time.Date.Date
|
import project.Data.Time.Date.Date
|
||||||
import project.Data.Time.Date_Period.Date_Period
|
import project.Data.Time.Date_Period.Date_Period
|
||||||
@ -687,5 +686,3 @@ type Date_Time
|
|||||||
format : Text -> Text
|
format : Text -> Text
|
||||||
format self pattern = @Builtin_Method "Date_Time.format"
|
format self pattern = @Builtin_Method "Date_Time.format"
|
||||||
|
|
||||||
|
|
||||||
Comparable.from (_:Date_Time) = Default_Ordered_Comparator
|
|
||||||
|
@ -3,7 +3,6 @@ import project.Data.Json.JS_Object
|
|||||||
import project.Data.Numbers.Decimal
|
import project.Data.Numbers.Decimal
|
||||||
import project.Data.Numbers.Integer
|
import project.Data.Numbers.Integer
|
||||||
import project.Data.Ordering.Comparable
|
import project.Data.Ordering.Comparable
|
||||||
import project.Data.Ordering.Default_Ordered_Comparator
|
|
||||||
import project.Data.Pair.Pair
|
import project.Data.Pair.Pair
|
||||||
import project.Data.Time.Date_Time.Date_Time
|
import project.Data.Time.Date_Time.Date_Time
|
||||||
import project.Data.Time.Period.Period
|
import project.Data.Time.Period.Period
|
||||||
@ -294,5 +293,3 @@ type Duration
|
|||||||
example_is_empty = Duration.zero.is_empty
|
example_is_empty = Duration.zero.is_empty
|
||||||
is_empty : Boolean
|
is_empty : Boolean
|
||||||
is_empty self = self.to_vector . all (==0)
|
is_empty self = self.to_vector . all (==0)
|
||||||
|
|
||||||
Comparable.from (_:Duration) = Default_Ordered_Comparator
|
|
||||||
|
@ -3,7 +3,6 @@ import project.Data.Numbers.Integer
|
|||||||
import project.Data.Time.Date.Date
|
import project.Data.Time.Date.Date
|
||||||
import project.Data.Time.Duration.Duration
|
import project.Data.Time.Duration.Duration
|
||||||
import project.Data.Ordering.Comparable
|
import project.Data.Ordering.Comparable
|
||||||
import project.Data.Ordering.Incomparable
|
|
||||||
import project.Data.Text.Text
|
import project.Data.Text.Text
|
||||||
import project.Error.Error
|
import project.Error.Error
|
||||||
import project.Error.Illegal_Argument.Illegal_Argument
|
import project.Error.Illegal_Argument.Illegal_Argument
|
||||||
|
@ -3,7 +3,6 @@ import project.Data.Json.JS_Object
|
|||||||
import project.Data.Locale.Locale
|
import project.Data.Locale.Locale
|
||||||
import project.Data.Numbers.Integer
|
import project.Data.Numbers.Integer
|
||||||
import project.Data.Ordering.Comparable
|
import project.Data.Ordering.Comparable
|
||||||
import project.Data.Ordering.Default_Ordered_Comparator
|
|
||||||
import project.Data.Text.Text
|
import project.Data.Text.Text
|
||||||
import project.Data.Time.Date.Date
|
import project.Data.Time.Date.Date
|
||||||
import project.Data.Time.Date_Time.Date_Time
|
import project.Data.Time.Date_Time.Date_Time
|
||||||
@ -356,5 +355,3 @@ type Time_Of_Day
|
|||||||
example_format = Time_Of_Day.new 16 21 10 . format "'hour:'h"
|
example_format = Time_Of_Day.new 16 21 10 . format "'hour:'h"
|
||||||
format : Text -> Text
|
format : Text -> Text
|
||||||
format self pattern = @Builtin_Method "Time_Of_Day.format"
|
format self pattern = @Builtin_Method "Time_Of_Day.format"
|
||||||
|
|
||||||
Comparable.from (_:Time_Of_Day) = Default_Ordered_Comparator
|
|
||||||
|
@ -77,8 +77,7 @@ import project.Data.Noise
|
|||||||
import project.Data.Ordering.Natural_Order
|
import project.Data.Ordering.Natural_Order
|
||||||
import project.Data.Ordering.Ordering
|
import project.Data.Ordering.Ordering
|
||||||
import project.Data.Ordering.Comparable
|
import project.Data.Ordering.Comparable
|
||||||
import project.Data.Ordering.Incomparable
|
import project.Data.Ordering.Default_Comparator
|
||||||
import project.Data.Ordering.Default_Ordered_Comparator
|
|
||||||
import project.Data.Ordering.Sort_Direction.Sort_Direction
|
import project.Data.Ordering.Sort_Direction.Sort_Direction
|
||||||
import project.Data.Pair.Pair
|
import project.Data.Pair.Pair
|
||||||
import project.Data.Range.Range
|
import project.Data.Range.Range
|
||||||
@ -131,8 +130,7 @@ export project.Data.Maybe.Maybe
|
|||||||
export project.Data.Ordering.Natural_Order
|
export project.Data.Ordering.Natural_Order
|
||||||
export project.Data.Ordering.Ordering
|
export project.Data.Ordering.Ordering
|
||||||
export project.Data.Ordering.Comparable
|
export project.Data.Ordering.Comparable
|
||||||
export project.Data.Ordering.Incomparable
|
export project.Data.Ordering.Default_Comparator
|
||||||
export project.Data.Ordering.Default_Ordered_Comparator
|
|
||||||
export project.Data.Ordering.Sort_Direction.Sort_Direction
|
export project.Data.Ordering.Sort_Direction.Sort_Direction
|
||||||
export project.Data.Pair.Pair
|
export project.Data.Pair.Pair
|
||||||
export project.Data.Range.Range
|
export project.Data.Range.Range
|
||||||
|
@ -24,7 +24,6 @@ type Bits
|
|||||||
Bits.Bits_64 -> 64
|
Bits.Bits_64 -> 64
|
||||||
|
|
||||||
type Bits_Comparator
|
type Bits_Comparator
|
||||||
is_ordered = True
|
|
||||||
compare x y = Comparable.from x.to_bits . compare x.to_bits y.to_bits
|
compare x y = Comparable.from x.to_bits . compare x.to_bits y.to_bits
|
||||||
hash x = Comparable.from x.to_bits . hash x.to_bits
|
hash x = Comparable.from x.to_bits . hash x.to_bits
|
||||||
|
|
||||||
|
@ -46,17 +46,18 @@ import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
|||||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
import org.enso.polyglot.MethodNames;
|
|
||||||
|
|
||||||
@BuiltinMethod(
|
@BuiltinMethod(
|
||||||
type = "Comparable",
|
type = "Comparable",
|
||||||
name = "equals_builtin",
|
name = "equals_builtin",
|
||||||
description = """
|
description = """
|
||||||
Compares self with other object and returns True iff `self` is exactly the same as
|
Compares self with other object and returns True iff `self` is exactly the same as
|
||||||
the other object, including all its transitively accessible properties or fields.
|
the other object, including all its transitively accessible properties or fields,
|
||||||
|
False otherwise.
|
||||||
|
|
||||||
Can handle arbitrary objects, including all foreign objects.
|
Can handle arbitrary objects, including all foreign objects.
|
||||||
|
|
||||||
Does not throw exceptions.
|
Does not throw dataflow errors or panics.
|
||||||
|
|
||||||
Note that this is different than `Meta.is_same_object`, which checks whether two
|
Note that this is different than `Meta.is_same_object`, which checks whether two
|
||||||
references point to the same object on the heap.
|
references point to the same object on the heap.
|
||||||
@ -65,13 +66,11 @@ import org.enso.polyglot.MethodNames;
|
|||||||
@GenerateUncached
|
@GenerateUncached
|
||||||
public abstract class EqualsNode extends Node {
|
public abstract class EqualsNode extends Node {
|
||||||
|
|
||||||
protected static String EQUALS_MEMBER_NAME = MethodNames.Function.EQUALS;
|
|
||||||
|
|
||||||
public static EqualsNode build() {
|
public static EqualsNode build() {
|
||||||
return EqualsNodeGen.create();
|
return EqualsNodeGen.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Object execute(@AcceptsError Object left, @AcceptsError Object right);
|
public abstract boolean execute(@AcceptsError Object left, @AcceptsError Object right);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Primitive values
|
* Primitive values
|
||||||
@ -134,18 +133,14 @@ public abstract class EqualsNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
Object equalsDoubleDouble(double self, double other) {
|
boolean equalsDoubleDouble(double self, double other) {
|
||||||
if (Double.isNaN(self) || Double.isNaN(other)) {
|
if (Double.isNaN(self) || Double.isNaN(other)) {
|
||||||
return nothing();
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return self == other;
|
return self == other;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object nothing() {
|
|
||||||
return EnsoContext.get(this).getBuiltins().nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
boolean equalsDoubleLong(double self, long other) {
|
boolean equalsDoubleLong(double self, long other) {
|
||||||
return self == (double) other;
|
return self == (double) other;
|
||||||
@ -268,26 +263,26 @@ public abstract class EqualsNode extends Node {
|
|||||||
boolean equalsUnresolvedSymbols(UnresolvedSymbol self, UnresolvedSymbol otherSymbol,
|
boolean equalsUnresolvedSymbols(UnresolvedSymbol self, UnresolvedSymbol otherSymbol,
|
||||||
@Cached EqualsNode equalsNode) {
|
@Cached EqualsNode equalsNode) {
|
||||||
return self.getName().equals(otherSymbol.getName())
|
return self.getName().equals(otherSymbol.getName())
|
||||||
&& (boolean) equalsNode.execute(self.getScope(), otherSymbol.getScope());
|
&& equalsNode.execute(self.getScope(), otherSymbol.getScope());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
boolean equalsUnresolvedConversion(UnresolvedConversion selfConversion, UnresolvedConversion otherConversion,
|
boolean equalsUnresolvedConversion(UnresolvedConversion selfConversion, UnresolvedConversion otherConversion,
|
||||||
@Cached EqualsNode equalsNode) {
|
@Cached EqualsNode equalsNode) {
|
||||||
return (boolean) equalsNode.execute(selfConversion.getScope(), otherConversion.getScope());
|
return equalsNode.execute(selfConversion.getScope(), otherConversion.getScope());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
boolean equalsModuleScopes(ModuleScope selfModuleScope, ModuleScope otherModuleScope,
|
boolean equalsModuleScopes(ModuleScope selfModuleScope, ModuleScope otherModuleScope,
|
||||||
@Cached EqualsNode equalsNode) {
|
@Cached EqualsNode equalsNode) {
|
||||||
return (boolean) equalsNode.execute(selfModuleScope.getModule(), otherModuleScope.getModule());
|
return equalsNode.execute(selfModuleScope.getModule(), otherModuleScope.getModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
boolean equalsModules(Module selfModule, Module otherModule,
|
boolean equalsModules(Module selfModule, Module otherModule,
|
||||||
@Cached EqualsNode equalsNode) {
|
@Cached EqualsNode equalsNode) {
|
||||||
return (boolean) equalsNode.execute(selfModule.getName().toString(), otherModule.getName().toString());
|
return equalsNode.execute(selfModule.getName().toString(), otherModule.getName().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
@ -298,7 +293,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* There is no specialization for {@link TypesLibrary#hasType(Object)}, because also
|
* There is no specialization for {@link TypesLibrary#hasType(Object)}, because also
|
||||||
* primitive values would fall into that specialization and it would be too complicated
|
* primitive values would fall into that specialization, and it would be too complicated
|
||||||
* to make that specialization disjunctive. So we rather specialize directly for
|
* to make that specialization disjunctive. So we rather specialize directly for
|
||||||
* {@link Type types}.
|
* {@link Type types}.
|
||||||
*/
|
*/
|
||||||
@ -309,7 +304,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
boolean equalsTypes(Type selfType, Type otherType,
|
boolean equalsTypes(Type selfType, Type otherType,
|
||||||
@Cached EqualsNode equalsNode,
|
@Cached EqualsNode equalsNode,
|
||||||
@CachedLibrary(limit = "5") TypesLibrary typesLib) {
|
@CachedLibrary(limit = "5") TypesLibrary typesLib) {
|
||||||
return (boolean) equalsNode.execute(
|
return equalsNode.execute(
|
||||||
selfType.getQualifiedName().toString(),
|
selfType.getQualifiedName().toString(),
|
||||||
otherType.getQualifiedName().toString()
|
otherType.getQualifiedName().toString()
|
||||||
);
|
);
|
||||||
@ -322,7 +317,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
@Specialization(guards = {
|
@Specialization(guards = {
|
||||||
"selfWarnLib.hasWarnings(selfWithWarnings) || otherWarnLib.hasWarnings(otherWithWarnings)"
|
"selfWarnLib.hasWarnings(selfWithWarnings) || otherWarnLib.hasWarnings(otherWithWarnings)"
|
||||||
}, limit = "3")
|
}, limit = "3")
|
||||||
Object equalsWithWarnings(Object selfWithWarnings, Object otherWithWarnings,
|
boolean equalsWithWarnings(Object selfWithWarnings, Object otherWithWarnings,
|
||||||
@CachedLibrary("selfWithWarnings") WarningsLibrary selfWarnLib,
|
@CachedLibrary("selfWithWarnings") WarningsLibrary selfWarnLib,
|
||||||
@CachedLibrary("otherWithWarnings") WarningsLibrary otherWarnLib,
|
@CachedLibrary("otherWithWarnings") WarningsLibrary otherWarnLib,
|
||||||
@Cached EqualsNode equalsNode
|
@Cached EqualsNode equalsNode
|
||||||
@ -530,7 +525,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
for (long i = 0; i < selfSize; i++) {
|
for (long i = 0; i < selfSize; i++) {
|
||||||
Object selfElem = selfInterop.readArrayElement(selfArray, i);
|
Object selfElem = selfInterop.readArrayElement(selfArray, i);
|
||||||
Object otherElem = otherInterop.readArrayElement(otherArray, i);
|
Object otherElem = otherInterop.readArrayElement(otherArray, i);
|
||||||
Object elemsAreEqual;
|
boolean elemsAreEqual;
|
||||||
if (selfElem instanceof Atom selfAtomElem
|
if (selfElem instanceof Atom selfAtomElem
|
||||||
&& otherElem instanceof Atom otherAtomElem
|
&& otherElem instanceof Atom otherAtomElem
|
||||||
&& hasCustomComparatorNode.execute(selfAtomElem)) {
|
&& hasCustomComparatorNode.execute(selfAtomElem)) {
|
||||||
@ -538,7 +533,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
} else {
|
} else {
|
||||||
elemsAreEqual = equalsNode.execute(selfElem, otherElem);
|
elemsAreEqual = equalsNode.execute(selfElem, otherElem);
|
||||||
}
|
}
|
||||||
if (!(elemsAreEqual instanceof Boolean elemsAreEqualBool && elemsAreEqualBool)) {
|
if (!elemsAreEqual) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -573,8 +568,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
if (otherInterop.isHashEntryExisting(otherHashMap, key)
|
if (otherInterop.isHashEntryExisting(otherHashMap, key)
|
||||||
&& otherInterop.isHashEntryReadable(otherHashMap, key)) {
|
&& otherInterop.isHashEntryReadable(otherHashMap, key)) {
|
||||||
Object otherValue = otherInterop.readHashValue(otherHashMap, key);
|
Object otherValue = otherInterop.readHashValue(otherHashMap, key);
|
||||||
Object res = equalsNode.execute(selfValue, otherValue);
|
if (!equalsNode.execute(selfValue, otherValue)) {
|
||||||
if (!(res instanceof Boolean resBool && resBool)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -610,8 +604,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
for (int i = 0; i < membersSize; i++) {
|
for (int i = 0; i < membersSize; i++) {
|
||||||
String selfMemberName = interop.asString(interop.readArrayElement(selfMembers, i));
|
String selfMemberName = interop.asString(interop.readArrayElement(selfMembers, i));
|
||||||
String otherMemberName = interop.asString(interop.readArrayElement(otherMembers, i));
|
String otherMemberName = interop.asString(interop.readArrayElement(otherMembers, i));
|
||||||
Object res = equalsNode.execute(selfMemberName, otherMemberName);
|
if (!equalsNode.execute(selfMemberName, otherMemberName)) {
|
||||||
if (!(res instanceof Boolean resBool && resBool)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memberNames[i] = selfMemberName;
|
memberNames[i] = selfMemberName;
|
||||||
@ -623,8 +616,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
interop.isMemberReadable(otherObject, memberNames[i])) {
|
interop.isMemberReadable(otherObject, memberNames[i])) {
|
||||||
Object selfMember = interop.readMember(selfObject, memberNames[i]);
|
Object selfMember = interop.readMember(selfObject, memberNames[i]);
|
||||||
Object otherMember = interop.readMember(otherObject, memberNames[i]);
|
Object otherMember = interop.readMember(otherObject, memberNames[i]);
|
||||||
Object res = equalsNode.execute(selfMember, otherMember);
|
if (!equalsNode.execute(selfMember, otherMember)) {
|
||||||
if (!(res instanceof Boolean resBool && resBool)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -646,11 +638,6 @@ public abstract class EqualsNode extends Node {
|
|||||||
return selfConstructor == otherConstructor;
|
return selfConstructor == otherConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* How many {@link EqualsNode} should be created for fields in specialization for atoms.
|
|
||||||
*/
|
|
||||||
static final int equalsNodeCountForFields = 10;
|
|
||||||
|
|
||||||
static EqualsNode[] createEqualsNodes(int size) {
|
static EqualsNode[] createEqualsNodes(int size) {
|
||||||
EqualsNode[] nodes = new EqualsNode[size];
|
EqualsNode[] nodes = new EqualsNode[size];
|
||||||
Arrays.fill(nodes, EqualsNode.build());
|
Arrays.fill(nodes, EqualsNode.build());
|
||||||
@ -693,15 +680,10 @@ public abstract class EqualsNode extends Node {
|
|||||||
// custom comparators. EqualsNode cannot deal with custom comparators.
|
// custom comparators. EqualsNode cannot deal with custom comparators.
|
||||||
fieldsAreEqual = invokeAnyEqualsNode.execute(selfAtomField, otherAtomField);
|
fieldsAreEqual = invokeAnyEqualsNode.execute(selfAtomField, otherAtomField);
|
||||||
} else {
|
} else {
|
||||||
Object res = fieldEqualsNodes[i].execute(
|
fieldsAreEqual = fieldEqualsNodes[i].execute(
|
||||||
selfFields[i],
|
selfFields[i],
|
||||||
otherFields[i]
|
otherFields[i]
|
||||||
);
|
);
|
||||||
if (res instanceof Boolean resBool) {
|
|
||||||
fieldsAreEqual = resBool;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!fieldsAreEqual) {
|
if (!fieldsAreEqual) {
|
||||||
return false;
|
return false;
|
||||||
@ -728,12 +710,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
&& HasCustomComparatorNode.getUncached().execute(selfFieldAtom)) {
|
&& HasCustomComparatorNode.getUncached().execute(selfFieldAtom)) {
|
||||||
areFieldsSame = InvokeAnyEqualsNode.getUncached().execute(selfFieldAtom, otherFieldAtom);
|
areFieldsSame = InvokeAnyEqualsNode.getUncached().execute(selfFieldAtom, otherFieldAtom);
|
||||||
} else {
|
} else {
|
||||||
Object res = EqualsNodeGen.getUncached().execute(selfFields[i], otherFields[i]);
|
areFieldsSame = EqualsNodeGen.getUncached().execute(selfFields[i], otherFields[i]);
|
||||||
if (res instanceof Boolean resBool) {
|
|
||||||
areFieldsSame = resBool;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!areFieldsSame) {
|
if (!areFieldsSame) {
|
||||||
return false;
|
return false;
|
||||||
@ -766,7 +743,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
"isHostFunction(selfHostFunc)",
|
"isHostFunction(selfHostFunc)",
|
||||||
"isHostFunction(otherHostFunc)"
|
"isHostFunction(otherHostFunc)"
|
||||||
})
|
})
|
||||||
Object equalsHostFunctions(Object selfHostFunc, Object otherHostFunc,
|
boolean equalsHostFunctions(Object selfHostFunc, Object otherHostFunc,
|
||||||
@CachedLibrary(limit = "5") InteropLibrary interop,
|
@CachedLibrary(limit = "5") InteropLibrary interop,
|
||||||
@Cached EqualsNode equalsNode) {
|
@Cached EqualsNode equalsNode) {
|
||||||
Object selfFuncStrRepr = interop.toDisplayString(selfHostFunc);
|
Object selfFuncStrRepr = interop.toDisplayString(selfHostFunc);
|
||||||
@ -843,7 +820,7 @@ public abstract class EqualsNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true iff object is a primitive value used in some of the specializations
|
* Return true iff object is a primitive value used in some specializations
|
||||||
* guard. By primitive value we mean any value that can be present in Enso, so,
|
* guard. By primitive value we mean any value that can be present in Enso, so,
|
||||||
* for example, not Integer, as that cannot be present in Enso.
|
* for example, not Integer, as that cannot be present in Enso.
|
||||||
* All the primitive types should be handled in their corresponding specializations.
|
* All the primitive types should be handled in their corresponding specializations.
|
||||||
@ -918,10 +895,6 @@ public abstract class EqualsNode extends Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isAtom(Object object) {
|
|
||||||
return object instanceof Atom;
|
|
||||||
}
|
|
||||||
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
boolean isHostObject(Object object) {
|
boolean isHostObject(Object object) {
|
||||||
return EnsoContext.get(this).getEnvironment().isHostObject(object);
|
return EnsoContext.get(this).getEnvironment().isHostObject(object);
|
||||||
|
@ -4,4 +4,4 @@ import org.enso.interpreter.dsl.BuiltinType;
|
|||||||
import org.enso.interpreter.node.expression.builtin.Builtin;
|
import org.enso.interpreter.node.expression.builtin.Builtin;
|
||||||
|
|
||||||
@BuiltinType
|
@BuiltinType
|
||||||
public class DefaultOrderedComparator extends Builtin {}
|
public class DefaultComparator extends Builtin {}
|
@ -1,7 +0,0 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin.ordering;
|
|
||||||
|
|
||||||
import org.enso.interpreter.dsl.BuiltinType;
|
|
||||||
import org.enso.interpreter.node.expression.builtin.Builtin;
|
|
||||||
|
|
||||||
@BuiltinType
|
|
||||||
public class DefaultUnorderedComparator extends Builtin {}
|
|
@ -31,8 +31,7 @@ public abstract class HasCustomComparatorNode extends Node {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given atom has a custom comparator, that is a comparator that is different
|
* Returns true if the given atom has a custom comparator, that is a comparator that is different
|
||||||
* than the default (internal) ones. The default comparators are {@code
|
* than the default (internal) ones.
|
||||||
* Default_Unordered_Comparator} and {@code Default_Ordered_Comparator}.
|
|
||||||
*
|
*
|
||||||
* @param atom Atom for which we check whether it has custom comparator
|
* @param atom Atom for which we check whether it has custom comparator
|
||||||
* @return true iff the given atom has a custom comparator
|
* @return true iff the given atom has a custom comparator
|
||||||
|
@ -27,7 +27,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
|||||||
type = "Comparable",
|
type = "Comparable",
|
||||||
name = "less_than_builtin",
|
name = "less_than_builtin",
|
||||||
description = """
|
description = """
|
||||||
Returns true if self is less than `other`. Or throw an error if the values are
|
Returns true if self is less than `other`. Or return Nothing if the values are
|
||||||
not comparable.
|
not comparable.
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
@ -328,11 +328,6 @@ public abstract class LessThanNode extends Node {
|
|||||||
return nothing();
|
return nothing();
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataflowError dataflowError(Object left, Object right) {
|
|
||||||
var typeError = EnsoContext.get(this).getBuiltins().error().makeTypeError(left, right, "right");
|
|
||||||
return DataflowError.withoutTrace(typeError, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object nothing() {
|
private Object nothing() {
|
||||||
return EnsoContext.get(this).getNothing();
|
return EnsoContext.get(this).getNothing();
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,7 @@ import org.enso.interpreter.node.expression.builtin.mutable.Array;
|
|||||||
import org.enso.interpreter.node.expression.builtin.mutable.Ref;
|
import org.enso.interpreter.node.expression.builtin.mutable.Ref;
|
||||||
import org.enso.interpreter.node.expression.builtin.immutable.Vector;
|
import org.enso.interpreter.node.expression.builtin.immutable.Vector;
|
||||||
import org.enso.interpreter.node.expression.builtin.ordering.Comparable;
|
import org.enso.interpreter.node.expression.builtin.ordering.Comparable;
|
||||||
import org.enso.interpreter.node.expression.builtin.ordering.DefaultOrderedComparator;
|
import org.enso.interpreter.node.expression.builtin.ordering.DefaultComparator;
|
||||||
import org.enso.interpreter.node.expression.builtin.ordering.DefaultUnorderedComparator;
|
|
||||||
import org.enso.interpreter.node.expression.builtin.ordering.Ordering;
|
import org.enso.interpreter.node.expression.builtin.ordering.Ordering;
|
||||||
import org.enso.interpreter.node.expression.builtin.resource.ManagedResource;
|
import org.enso.interpreter.node.expression.builtin.resource.ManagedResource;
|
||||||
import org.enso.interpreter.node.expression.builtin.text.Text;
|
import org.enso.interpreter.node.expression.builtin.text.Text;
|
||||||
@ -86,8 +85,7 @@ public class Builtins {
|
|||||||
private final Boolean bool;
|
private final Boolean bool;
|
||||||
private final Ordering ordering;
|
private final Ordering ordering;
|
||||||
private final Comparable comparable;
|
private final Comparable comparable;
|
||||||
private final DefaultOrderedComparator defaultOrderedComparator;
|
private final DefaultComparator defaultComparator;
|
||||||
private final DefaultUnorderedComparator defaultUnorderedComparator;
|
|
||||||
private final System system;
|
private final System system;
|
||||||
private final Special special;
|
private final Special special;
|
||||||
|
|
||||||
@ -135,8 +133,7 @@ public class Builtins {
|
|||||||
error = new Error(this, context);
|
error = new Error(this, context);
|
||||||
ordering = getBuiltinType(Ordering.class);
|
ordering = getBuiltinType(Ordering.class);
|
||||||
comparable = getBuiltinType(Comparable.class);
|
comparable = getBuiltinType(Comparable.class);
|
||||||
defaultUnorderedComparator = getBuiltinType(DefaultUnorderedComparator.class);
|
defaultComparator = getBuiltinType(DefaultComparator.class);
|
||||||
defaultOrderedComparator = getBuiltinType(DefaultOrderedComparator.class);
|
|
||||||
system = new System(this);
|
system = new System(this);
|
||||||
number = new Number(this);
|
number = new Number(this);
|
||||||
bool = this.getBuiltinType(Boolean.class);
|
bool = this.getBuiltinType(Boolean.class);
|
||||||
@ -598,12 +595,8 @@ public class Builtins {
|
|||||||
return comparable;
|
return comparable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultOrderedComparator defaultOrderedComparator() {
|
public DefaultComparator defaultComparator() {
|
||||||
return defaultOrderedComparator;
|
return defaultComparator;
|
||||||
}
|
|
||||||
|
|
||||||
public DefaultUnorderedComparator defaultUnorderedComparator() {
|
|
||||||
return defaultUnorderedComparator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the container for the dataflow error-related builtins */
|
/** @return the container for the dataflow error-related builtins */
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.enso.interpreter.test;
|
package org.enso.interpreter.test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertSame;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
@ -14,8 +13,6 @@ import java.util.stream.Collectors;
|
|||||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
|
import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
|
||||||
import org.enso.interpreter.node.expression.builtin.meta.EqualsNode;
|
import org.enso.interpreter.node.expression.builtin.meta.EqualsNode;
|
||||||
import org.enso.interpreter.node.expression.builtin.meta.EqualsNodeGen;
|
import org.enso.interpreter.node.expression.builtin.meta.EqualsNodeGen;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.Value;
|
import org.graalvm.polyglot.Value;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
@ -92,17 +89,9 @@ public class EqualsTest extends TestBase {
|
|||||||
executeInContext(
|
executeInContext(
|
||||||
context,
|
context,
|
||||||
() -> {
|
() -> {
|
||||||
Object firstResult = equalsNode.execute(firstValue, secondValue);
|
boolean firstResult = equalsNode.execute(firstValue, secondValue);
|
||||||
Object secondResult = equalsNode.execute(secondValue, firstValue);
|
boolean secondResult = equalsNode.execute(secondValue, firstValue);
|
||||||
if (firstResult instanceof Boolean firstResultBool && secondResult instanceof Boolean secondResultBool) {
|
assertEquals("equals should be symmetric", firstResult, secondResult);
|
||||||
assertEquals("equals should be symmetric", firstResultBool, secondResultBool);
|
|
||||||
} else {
|
|
||||||
var nothing = EnsoContext.get(null).getBuiltins().nothing();
|
|
||||||
assertTrue(
|
|
||||||
"equals should be symmetric - Nothing returned just in one case",
|
|
||||||
nothing == firstResult && nothing == secondResult
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -146,7 +135,7 @@ public class EqualsTest extends TestBase {
|
|||||||
executeInContext(
|
executeInContext(
|
||||||
context,
|
context,
|
||||||
() -> {
|
() -> {
|
||||||
assertTrue((Boolean) equalsNode.execute(ensoDate, javaDate));
|
assertTrue(equalsNode.execute(ensoDate, javaDate));
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -164,7 +153,7 @@ public class EqualsTest extends TestBase {
|
|||||||
executeInContext(
|
executeInContext(
|
||||||
context,
|
context,
|
||||||
() -> {
|
() -> {
|
||||||
assertTrue((Boolean) equalsNode.execute(ensoTime, javaDate));
|
assertTrue(equalsNode.execute(ensoTime, javaDate));
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -187,7 +176,7 @@ public class EqualsTest extends TestBase {
|
|||||||
executeInContext(
|
executeInContext(
|
||||||
context,
|
context,
|
||||||
() -> {
|
() -> {
|
||||||
assertTrue((Boolean) equalsNode.execute(ensoDateTime, javaDateTime));
|
assertTrue(equalsNode.execute(ensoDateTime, javaDateTime));
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -200,26 +189,8 @@ public class EqualsTest extends TestBase {
|
|||||||
executeInContext(
|
executeInContext(
|
||||||
context,
|
context,
|
||||||
() -> {
|
() -> {
|
||||||
assertTrue((Boolean) equalsNode.execute(ensoVector, javaVector));
|
assertTrue(equalsNode.execute(ensoVector, javaVector));
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* NaN is a special value of Decimal type that is not comparable.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testNanEquality() {
|
|
||||||
Object nan = unwrapValue(context, createValue(context, "Number.nan", "import Standard.Base.Data.Numbers.Number"));
|
|
||||||
Object decimal = unwrapValue(context, createValue(context, "15.56"));
|
|
||||||
executeInContext(
|
|
||||||
context,
|
|
||||||
() -> {
|
|
||||||
Object res = equalsNode.execute(nan, decimal);
|
|
||||||
Type nothing = EnsoContext.get(null).getNothing();
|
|
||||||
assertSame("Comparison of NaN and other decimal should return Nothing", nothing, res);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,6 @@ type My
|
|||||||
Data x
|
Data x
|
||||||
|
|
||||||
type My_Comparator
|
type My_Comparator
|
||||||
is_ordered = True
|
|
||||||
|
|
||||||
compare my_1 my_2 =
|
compare my_1 my_2 =
|
||||||
comparator = Comparable.from my_2.x
|
comparator = Comparable.from my_2.x
|
||||||
comparator.compare my_2.x my_1.x
|
comparator.compare my_2.x my_1.x
|
||||||
|
@ -16,8 +16,6 @@ type My_Type
|
|||||||
Value x y
|
Value x y
|
||||||
|
|
||||||
type My_Type_Comparator
|
type My_Type_Comparator
|
||||||
is_ordered = True
|
|
||||||
|
|
||||||
compare my_1 my_2 =
|
compare my_1 my_2 =
|
||||||
comp = Comparable.from my_1.x
|
comp = Comparable.from my_1.x
|
||||||
comp.compare (my_1.x + my_1.y) (my_2.x + my_2.y)
|
comp.compare (my_1.x + my_1.y) (my_2.x + my_2.y)
|
||||||
|
@ -30,8 +30,6 @@ type My
|
|||||||
My.Data x1 y1 -> My.Data y1 x1
|
My.Data x1 y1 -> My.Data y1 x1
|
||||||
|
|
||||||
type My_Comparator
|
type My_Comparator
|
||||||
is_ordered = True
|
|
||||||
|
|
||||||
compare left right =
|
compare left right =
|
||||||
left_sum = left.x + left.y
|
left_sum = left.x + left.y
|
||||||
right_sum = right.x + right.y
|
right_sum = right.x + right.y
|
||||||
|
@ -3,7 +3,6 @@ import Standard.Base.Error.Illegal_Argument.Illegal_Argument
|
|||||||
import Standard.Base.Error.No_Such_Key.No_Such_Key
|
import Standard.Base.Error.No_Such_Key.No_Such_Key
|
||||||
import Standard.Base.Data.Time.Date_Time.Date_Time
|
import Standard.Base.Data.Time.Date_Time.Date_Time
|
||||||
from Standard.Base.Data.Map import Map
|
from Standard.Base.Data.Map import Map
|
||||||
from Standard.Base.Data.Ordering import Default_Unordered_Comparator
|
|
||||||
|
|
||||||
from Standard.Test import Test, Test_Suite, Problems
|
from Standard.Test import Test, Test_Suite, Problems
|
||||||
import Standard.Test.Extensions
|
import Standard.Test.Extensions
|
||||||
@ -76,10 +75,10 @@ spec =
|
|||||||
empty_map.is_empty . should_be_true
|
empty_map.is_empty . should_be_true
|
||||||
non_empty.is_empty . should_be_false
|
non_empty.is_empty . should_be_false
|
||||||
|
|
||||||
Test.specify "should get default unordered comparator for polyglot maps" <|
|
Test.specify "should get the default comparator for polyglot maps" <|
|
||||||
Comparable.from (Map.empty) . should_equal Default_Unordered_Comparator
|
Comparable.from (Map.empty) . should_equal Default_Comparator
|
||||||
Comparable.from (js_empty_dict) . should_equal Default_Unordered_Comparator
|
Comparable.from (js_empty_dict) . should_equal Default_Comparator
|
||||||
Comparable.from (JavaMap.of "A" 1 "B" 2) . should_equal Default_Unordered_Comparator
|
Comparable.from (JavaMap.of "A" 1 "B" 2) . should_equal Default_Comparator
|
||||||
|
|
||||||
Test.specify "should compare two hash maps" <|
|
Test.specify "should compare two hash maps" <|
|
||||||
(Map.singleton "a" 1).should_equal (Map.singleton "a" 1)
|
(Map.singleton "a" 1).should_equal (Map.singleton "a" 1)
|
||||||
|
@ -385,7 +385,7 @@ spec =
|
|||||||
(very_negative >= hundred_factorial).should_be_false
|
(very_negative >= hundred_factorial).should_be_false
|
||||||
(very_negative >= Nothing).should_fail_with Type_Error
|
(very_negative >= Nothing).should_fail_with Type_Error
|
||||||
|
|
||||||
Test.specify "should be ordered by Default_Ordered_Comparator" <|
|
Test.specify "should be ordered by the default comparator" <|
|
||||||
Ordering.compare 1 2 . should_equal Ordering.Less
|
Ordering.compare 1 2 . should_equal Ordering.Less
|
||||||
Ordering.compare 1 1 . should_equal Ordering.Equal
|
Ordering.compare 1 1 . should_equal Ordering.Equal
|
||||||
Ordering.compare 1 0 . should_equal Ordering.Greater
|
Ordering.compare 1 0 . should_equal Ordering.Greater
|
||||||
|
@ -15,7 +15,6 @@ type Ord
|
|||||||
|
|
||||||
# The comparison is reverted, i.e., `x < y` gives result for `y.number < x.number`.
|
# The comparison is reverted, i.e., `x < y` gives result for `y.number < x.number`.
|
||||||
type Ord_Comparator
|
type Ord_Comparator
|
||||||
is_ordered = True
|
|
||||||
compare x y = (Comparable.from y.number) . compare y.number x.number
|
compare x y = (Comparable.from y.number) . compare y.number x.number
|
||||||
hash x = (Comparable.from x.number) . hash x.number
|
hash x = (Comparable.from x.number) . hash x.number
|
||||||
|
|
||||||
@ -24,7 +23,11 @@ Comparable.from (_:Ord) = Ord_Comparator
|
|||||||
type No_Ord
|
type No_Ord
|
||||||
Value number
|
Value number
|
||||||
|
|
||||||
Comparable.from (_:No_Ord) = Incomparable
|
type No_Ord_Comparator
|
||||||
|
compare x y = Nothing
|
||||||
|
hash x = 0
|
||||||
|
|
||||||
|
Comparable.from (_:No_Ord) = No_Ord_Comparator
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
|
|
||||||
@ -67,7 +70,7 @@ spec = Test.group "Object Comparator" <|
|
|||||||
((default_comparator (Ord.Value 1) (Ord.Value 1)) == 0) . should_equal True
|
((default_comparator (Ord.Value 1) (Ord.Value 1)) == 0) . should_equal True
|
||||||
|
|
||||||
Test.specify "should fail gracefully for incomparable items" <|
|
Test.specify "should fail gracefully for incomparable items" <|
|
||||||
(default_comparator 1 True).catch . should_equal (Incomparable_Values.Error 1 True)
|
(default_comparator 1 True) . should_fail_with Incomparable_Values
|
||||||
(default_comparator (No_Ord.Value 1) (No_Ord.Value 2)).should_fail_with Incomparable_Values
|
(default_comparator (No_Ord.Value 1) (No_Ord.Value 2)).should_fail_with Incomparable_Values
|
||||||
|
|
||||||
main = Test_Suite.run_main spec
|
main = Test_Suite.run_main spec
|
||||||
|
@ -11,7 +11,6 @@ type Ord
|
|||||||
Value number
|
Value number
|
||||||
|
|
||||||
type Ord_Comparator
|
type Ord_Comparator
|
||||||
is_ordered = True
|
|
||||||
compare x y = (Comparable.from x.number) . compare x.number y.number
|
compare x y = (Comparable.from x.number) . compare x.number y.number
|
||||||
hash x = (Comparable.from x.number) . hash x.number
|
hash x = (Comparable.from x.number) . hash x.number
|
||||||
|
|
||||||
@ -22,12 +21,10 @@ type UPair
|
|||||||
Value x y
|
Value x y
|
||||||
|
|
||||||
type UPair_Comparator
|
type UPair_Comparator
|
||||||
is_ordered = False
|
compare pair1 pair2 =
|
||||||
|
if pair1.x == pair2.x && pair1.y == pair2.y then Ordering.Equal else
|
||||||
equals pair1 pair2 =
|
if pair1.x == pair2.y && pair1.y == pair2.x then Ordering.Equal else
|
||||||
if pair1.x == pair2.x && pair1.y == pair2.y then True else
|
Nothing
|
||||||
if pair1.x == pair2.y && pair1.y == pair2.x then True else
|
|
||||||
False
|
|
||||||
|
|
||||||
hash upair =
|
hash upair =
|
||||||
x_comp = Comparable.from upair.x
|
x_comp = Comparable.from upair.x
|
||||||
@ -42,24 +39,17 @@ type Parent
|
|||||||
# === The Tests ===
|
# === The Tests ===
|
||||||
|
|
||||||
spec =
|
spec =
|
||||||
Test.group "Default ordered comparator" <|
|
Test.group "Default comparator" <|
|
||||||
Test.specify "should support custom ordered comparator" <|
|
Test.specify "should support custom comparator" <|
|
||||||
Ordering.compare (Ord.Value 1) (Ord.Value 2) . should_equal Ordering.Less
|
Ordering.compare (Ord.Value 1) (Ord.Value 2) . should_equal Ordering.Less
|
||||||
Ordering.compare (Ord.Value 1) (Ord.Value 1) . should_equal Ordering.Equal
|
Ordering.compare (Ord.Value 1) (Ord.Value 1) . should_equal Ordering.Equal
|
||||||
Ordering.compare (Ord.Value 20) (Ord.Value 1) . should_equal Ordering.Greater
|
Ordering.compare (Ord.Value 20) (Ord.Value 1) . should_equal Ordering.Greater
|
||||||
|
Ordering.compare (UPair.Value 1 2) (UPair.Value 2 1) . should_equal Ordering.Equal
|
||||||
|
|
||||||
Test.specify "should support equality for custom ordered comparators in atom field" <|
|
Test.specify "should support equality for custom comparators in atom field" <|
|
||||||
((Parent.Value (Ord.Value 1)) == (Parent.Value (Ord.Value 1))) . should_be_true
|
((Parent.Value (Ord.Value 1)) == (Parent.Value (Ord.Value 1))) . should_be_true
|
||||||
((Parent.Value (Ord.Value 1)) == (Parent.Value (Ord.Value 22))) . should_be_false
|
((Parent.Value (Ord.Value 1)) == (Parent.Value (Ord.Value 22))) . should_be_false
|
||||||
|
|
||||||
Test.specify "should throw Incomparable_Values when comparing types with unordered comparator" <|
|
|
||||||
val1 = (UPair.Value 1 2)
|
|
||||||
val2 = (UPair.Value 2 1)
|
|
||||||
err = Ordering.compare val1 val2
|
|
||||||
err.should_fail_with Incomparable_Values
|
|
||||||
Meta.is_same_object err.catch.left val1 . should_be_true
|
|
||||||
Meta.is_same_object err.catch.right val2 . should_be_true
|
|
||||||
|
|
||||||
Test.specify "should throw Type_Error when comparing different types" <|
|
Test.specify "should throw Type_Error when comparing different types" <|
|
||||||
Ordering.compare (UPair.Value 1 2) (Ord.Value 2) . should_fail_with Type_Error
|
Ordering.compare (UPair.Value 1 2) (Ord.Value 2) . should_fail_with Type_Error
|
||||||
Ordering.compare 1 Nothing . should_fail_with Type_Error
|
Ordering.compare 1 Nothing . should_fail_with Type_Error
|
||||||
|
@ -12,7 +12,6 @@ type Ord
|
|||||||
Value number
|
Value number
|
||||||
|
|
||||||
type Ord_Comparator
|
type Ord_Comparator
|
||||||
is_ordered = True
|
|
||||||
compare x y = (Comparable.from x.number) . compare x.number y.number
|
compare x y = (Comparable.from x.number) . compare x.number y.number
|
||||||
hash x = (Comparable.from x.number) . hash x.number
|
hash x = (Comparable.from x.number) . hash x.number
|
||||||
|
|
||||||
@ -21,7 +20,11 @@ Comparable.from (_:Ord) = Ord_Comparator
|
|||||||
type No_Ord
|
type No_Ord
|
||||||
Value number
|
Value number
|
||||||
|
|
||||||
Comparable.from (_:No_Ord) = Incomparable
|
type No_Ord_Comparator
|
||||||
|
compare x y = Nothing
|
||||||
|
hash x = 0
|
||||||
|
|
||||||
|
Comparable.from (_:No_Ord) = No_Ord_Comparator
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import Standard.Base.Data.Text.Regex_2.No_Such_Group
|
|||||||
import Standard.Base.Data.Text.Regex_2.Regex_Syntax_Error
|
import Standard.Base.Data.Text.Regex_2.Regex_Syntax_Error
|
||||||
import Standard.Base.Data.Text.Span.Span
|
import Standard.Base.Data.Text.Span.Span
|
||||||
import Standard.Base.Error.Common.Index_Out_Of_Bounds
|
import Standard.Base.Error.Common.Index_Out_Of_Bounds
|
||||||
|
import Standard.Base.Error.Common.Incomparable_Values
|
||||||
import Standard.Base.Error.Common.Type_Error
|
import Standard.Base.Error.Common.Type_Error
|
||||||
import Standard.Base.Error.Illegal_Argument.Illegal_Argument
|
import Standard.Base.Error.Illegal_Argument.Illegal_Argument
|
||||||
|
|
||||||
@ -120,8 +121,8 @@ spec =
|
|||||||
# Handling of Nothing
|
# Handling of Nothing
|
||||||
(accent_1 == Nothing) . should_be_false
|
(accent_1 == Nothing) . should_be_false
|
||||||
(accent_1 != Nothing) . should_be_true
|
(accent_1 != Nothing) . should_be_true
|
||||||
Ordering.compare accent_1 Nothing . should_fail_with Type_Error
|
Ordering.compare accent_1 Nothing . should_fail_with Incomparable_Values
|
||||||
(accent_1 > Nothing) . should_fail_with Type_Error
|
(accent_1 > Nothing) . should_fail_with Incomparable_Values
|
||||||
accent_1 . compare_to_ignore_case Nothing . should_fail_with Type_Error
|
accent_1 . compare_to_ignore_case Nothing . should_fail_with Type_Error
|
||||||
|
|
||||||
earlier_suffix = "aooooz"
|
earlier_suffix = "aooooz"
|
||||||
|
@ -123,9 +123,6 @@ spec_with name create_new_date parse_date =
|
|||||||
result ->
|
result ->
|
||||||
Test.fail ("Unexpected result: " + result.to_text)
|
Test.fail ("Unexpected result: " + result.to_text)
|
||||||
|
|
||||||
Test.specify "should get default ordered comparator for dates" <|
|
|
||||||
Comparable.from (create_new_date 2023 2 3) . should_equal Default_Ordered_Comparator
|
|
||||||
|
|
||||||
Test.specify "should be comparable" <|
|
Test.specify "should be comparable" <|
|
||||||
date_1 = parse_date "2021-01-02"
|
date_1 = parse_date "2021-01-02"
|
||||||
date_2 = parse_date "2021-01-01"
|
date_2 = parse_date "2021-01-01"
|
||||||
|
@ -315,10 +315,10 @@ spec_with name create_new_datetime parse_datetime nanoseconds_loss_in_precision=
|
|||||||
time . nanosecond . should_equal 0
|
time . nanosecond . should_equal 0
|
||||||
time . zone . zone_id . should_equal Time_Zone.utc.zone_id
|
time . zone . zone_id . should_equal Time_Zone.utc.zone_id
|
||||||
|
|
||||||
Test.specify "should get default ordered comparator for datetimes" <|
|
Test.specify "should get the default comparator for datetimes" <|
|
||||||
Comparable.from (create_new_datetime 2023 2 3 23 59) . should_equal Default_Ordered_Comparator
|
Comparable.from (create_new_datetime 2023 2 3 23 59) . should_equal Default_Comparator
|
||||||
Comparable.from (parse_datetime "2021-01-01T00:30:12.7102[UTC]") . should_equal Default_Ordered_Comparator
|
Comparable.from (parse_datetime "2021-01-01T00:30:12.7102[UTC]") . should_equal Default_Comparator
|
||||||
Comparable.from (create_new_datetime 2022 10 31 2 30 55 1234) . should_equal Default_Ordered_Comparator
|
Comparable.from (create_new_datetime 2022 10 31 2 30 55 1234) . should_equal Default_Comparator
|
||||||
|
|
||||||
Test.specify "should be comparable" <|
|
Test.specify "should be comparable" <|
|
||||||
time_1 = parse_datetime "2021-01-01T00:30:12.7102[UTC]"
|
time_1 = parse_datetime "2021-01-01T00:30:12.7102[UTC]"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
import Standard.Base.Error.Common.Type_Error
|
import Standard.Base.Error.Common.Incomparable_Values
|
||||||
import Standard.Base.Error.Time_Error.Time_Error
|
import Standard.Base.Error.Time_Error.Time_Error
|
||||||
|
|
||||||
from Standard.Test import Test, Test_Suite
|
from Standard.Test import Test, Test_Suite
|
||||||
@ -62,8 +62,8 @@ spec =
|
|||||||
(duration - period).should_fail_with Time_Error
|
(duration - period).should_fail_with Time_Error
|
||||||
(period + duration).should_fail_with Time_Error
|
(period + duration).should_fail_with Time_Error
|
||||||
(period - duration).should_fail_with Time_Error
|
(period - duration).should_fail_with Time_Error
|
||||||
(duration > period).should_fail_with Type_Error
|
(duration > period).should_fail_with Incomparable_Values
|
||||||
(duration < period).should_fail_with Type_Error
|
(duration < period).should_fail_with Incomparable_Values
|
||||||
|
|
||||||
Test.specify "Date_Time supports adding and subtracting Duration" <|
|
Test.specify "Date_Time supports adding and subtracting Duration" <|
|
||||||
((Date_Time.new 2022 10 1 hour=10) + (Duration.new hours=2)) . should_equal (Date_Time.new 2022 10 1 hour=12)
|
((Date_Time.new 2022 10 1 hour=10) + (Duration.new hours=2)) . should_equal (Date_Time.new 2022 10 1 hour=12)
|
||||||
|
@ -17,7 +17,6 @@ type T
|
|||||||
Value a b
|
Value a b
|
||||||
|
|
||||||
type T_Comparator
|
type T_Comparator
|
||||||
is_ordered = True
|
|
||||||
compare t1 t2 = Comparable.from t1.a . compare t1.a t2.a
|
compare t1 t2 = Comparable.from t1.a . compare t1.a t2.a
|
||||||
hash t = Comparable.from t.a . hash t.a
|
hash t = Comparable.from t.a . hash t.a
|
||||||
|
|
||||||
|
@ -15,8 +15,7 @@ type CustomEqType
|
|||||||
CustomEqType.C2 f1 f2 -> f1 + f2
|
CustomEqType.C2 f1 f2 -> f1 + f2
|
||||||
|
|
||||||
type CustomEqType_Comparator
|
type CustomEqType_Comparator
|
||||||
is_ordered = False
|
compare o1 o2 = if o1.sum == o2.sum then Ordering.Equal else Nothing
|
||||||
equals o1 o2 = o1.sum == o2.sum
|
|
||||||
hash o =
|
hash o =
|
||||||
comp = Comparable.from o.sum
|
comp = Comparable.from o.sum
|
||||||
comp.hash o.sum
|
comp.hash o.sum
|
||||||
@ -27,8 +26,7 @@ type Child
|
|||||||
Value number
|
Value number
|
||||||
|
|
||||||
type Child_Comparator
|
type Child_Comparator
|
||||||
is_ordered = False
|
compare child1 child2 = if child1.number % 100 == child2.number % 100 then Ordering.Equal else Nothing
|
||||||
equals child1 child2 = child1.number % 100 == child2.number % 100
|
|
||||||
hash child =
|
hash child =
|
||||||
comp = Comparable.from child.number
|
comp = Comparable.from child.number
|
||||||
comp.hash (child.number % 100)
|
comp.hash (child.number % 100)
|
||||||
|
Loading…
Reference in New Issue
Block a user