Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Update sorting methods to use abstract closures (#78)
Browse files Browse the repository at this point in the history
* update sorting methods to use abstract closures

Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
  • Loading branch information
acutmore and nicolo-ribaudo authored Mar 17, 2022
1 parent 61223a2 commit 7588000
Showing 1 changed file with 191 additions and 44 deletions.
235 changes: 191 additions & 44 deletions spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,112 @@ <h1>Array Objects</h1>
<emu-clause id="sec-properties-of-the-array-prototype-object">
<h1>Properties of the Array Prototype Object</h1>

<emu-clause id="sec-array.prototype.sort" oldids="sec-sortcompare">
<h1>Array.prototype.sort ( _comparefn_ )</h1>

<p>When the `sort` method is called, the following steps are taken:</p>
<emu-alg>
1. [id="step-array-sort-comparefn"] If _comparefn_ is not *undefined* and IsCallable(_comparefn_) is *false*, throw a *TypeError* exception.
1. Let _obj_ be ? ToObject(*this* value).
1. [id="step-array-sort-len"] Let _len_ be ? LengthOfArrayLike(_obj_).
1. Let _SortCompare_ be a new Abstract Closure with parameters (_x_, _y_) that captures _comparefn_ and performs the following steps when called:
1. <del>If _x_ and _y_ are both *undefined*, return *+0*<sub>𝔽</sub>.</del>
1. <del>If _x_ is *undefined*, return *1*<sub>𝔽</sub>.</del>
1. <del>If _y_ is *undefined*, return *-1*<sub>𝔽</sub>.</del>
1. <del>If _comparefn_ is not *undefined*, then</del>
1. <del>Let _v_ be ? ToNumber(? Call(_comparefn_, *undefined*, &laquo; _x_, _y_ &raquo;)).</del>
1. <del>If _v_ is *NaN*, return *+0*<sub>𝔽</sub>.</del>
1. <del>Return _v_.</del>
1. <del>[id="step-sortcompare-tostring-x"] Let _xString_ be ? ToString(_x_).</del>
1. <del>[id="step-sortcompare-tostring-y"] Let _yString_ be ? ToString(_y_).</del>
1. <del>Let _xSmaller_ be ! IsLessThan(_xString_, _yString_, *true*).</del>
1. <del>If _xSmaller_ is *true*, return *-1*<sub>𝔽</sub>.</del>
1. <del>Let _ySmaller_ be ! IsLessThan(_yString_, _xString_, *true*).</del>
1. <del>If _ySmaller_ is *true*, return *1*<sub>𝔽</sub>.</del>
1. <del>Return *+0*<sub>𝔽</sub>.</del>
1. <ins>Return ? CompareArrayElements(_x_, _y_, _comparefn_).</ins>
1. <del>Return ? SortIndexedProperties(_obj_, _len_, _SortCompare_).</del>
1. [id="step-array-sortindexedproperties"] <ins>Let _sortedList_ be ? SortIndexedProperties(_obj_, _len_, _SortCompare_, *true*).</ins>
1. <ins>Let _itemCount_ be the number of elements in _sortedList_.</ins>
1. <ins>Let _j_ be 0.</ins>
1. <ins>Repeat, while _j_ &lt; _itemCount_,</ins>
1. <ins>Perform ? CreateDataPropertyOrThrow(_obj_, ! ToString(𝔽(_j_)), _sortedList_[_j_]).</ins>
1. <ins>Set _j_ to _j_ + 1.</ins>
1. <ins>NOTE: The call to SortIndexedProperties in step <emu-xref href="#step-array-sortindexedproperties"></emu-xref> has the *skipHoles* parameter set to *true*. The remaining indexes are deleted to preserve the number of holes that were detected and excluded from the sort.</ins>
1. <ins>Repeat, while _j_ &lt; _len_,</ins>
1. <ins>Perform ? DeletePropertyOrThrow(_obj_, ! ToString(𝔽(_j_))).</ins>
1. <ins>Set _j_ to _j_ + 1.</ins>
1. <ins>Return _obj_.</ins>
</emu-alg>
</emu-clause>

<emu-clause id="sec-comparearrayelements" type="abstract operation">
<h1>
CompareArrayElements(
_x_: unknown,
_y_: unknown,
_comparefn_: a function object or *undefined*
): either a normal completion containing a Number or an abrupt completion
</h1>
<dl class="header">
</dl>
<emu-alg>
1. If _x_ and _y_ are both *undefined*, return *+0*<sub>𝔽</sub>.
1. If _x_ is *undefined*, return *1*<sub>𝔽</sub>.
1. If _y_ is *undefined*, return *-1*<sub>𝔽</sub>.
1. If _comparefn_ is not *undefined*, then
1. Let _v_ be ? ToNumber(? Call(_comparefn_, *undefined*, &laquo; _x_, _y_ &raquo;)).
1. If _v_ is *NaN*, return *+0*<sub>𝔽</sub>.
1. Return _v_.
1. [id="step-sortcompare-tostring-x"] Let _xString_ be ? ToString(_x_).
1. [id="step-sortcompare-tostring-y"] Let _yString_ be ? ToString(_y_).
1. Let _xSmaller_ be ! IsLessThan(_xString_, _yString_, *true*).
1. If _xSmaller_ is *true*, return *-1*<sub>𝔽</sub>.
1. Let _ySmaller_ be ! IsLessThan(_yString_, _xString_, *true*).
1. If _ySmaller_ is *true*, return *1*<sub>𝔽</sub>.
1. Return *+0*<sub>𝔽</sub>.
</emu-alg>
</emu-clause>

<emu-clause id="sec-sortindexedproperties" type="abstract operation">
<h1>
SortIndexedProperties (
_obj_: an Object,
_len_: a non-negative integer,
_SortCompare_: an Abstract Closure with two parameters,
<ins>_skipHoles_: a Boolean</ins>
): either a normal completion containing <del>an Object</del><ins>a List</ins> or an abrupt completion
</h1>
<dl class="header">
</dl>
<emu-alg>
1. Let _items_ be a new empty List.
1. Let _k_ be 0.
1. Repeat, while _k_ &lt; _len_,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. <del>Let _kPresent_ be ? HasProperty(_obj_, _Pk_).</del>
1. <ins>If _skipHoles_ is *true*, then</ins>
1. <ins>Let _kRead_ be ? HasProperty(_obj_, _Pk_).</ins>
1. <ins>Else,</ins>
1. <ins>Let _kRead_ be *true*.</ins>
1. If <del>_kPresent_</del><ins>_kRead_</ins> is *true*, then
1. Let _kValue_ be ? Get(_obj_, _Pk_).
1. Append _kValue_ to _items_.
1. Set _k_ to _k_ + 1.
1. <del>Let _itemCount_ be the number of elements in _items_.</del>
1. [id="step-array-sort"] Sort _items_ using an implementation-defined sequence of calls to _SortCompare_. If any such call returns an abrupt completion, stop before performing any further calls to _SortCompare_ or steps in this algorithm and return that Completion Record.
1. <del>Let _j_ be 0.</del>
1. <del>Repeat, while _j_ &lt; _itemCount_,</del>
1. <del>Perform ? Set(_obj_, ! ToString(𝔽(_j_)), _items_[_j_], *true*).</del>
1. <del>Set _j_ to _j_ + 1.</del>
1. <del>Repeat, while _j_ &lt; _len_,</del>
1. <del>Perform ? DeletePropertyOrThrow(_obj_, ! ToString(𝔽(_j_))).</del>
1. <del>Set _j_ to _j_ + 1.</del>
1. <del>Return _obj_.</del>
1. <ins>Return _items_.</ins>
</emu-alg>
</emu-clause>

<emu-clause id="sec-array.prototype.toReversed">
<h1>Array.prototype.toReversed ( )</h1>

Expand All @@ -39,7 +145,7 @@ <h1>Array.prototype.toReversed ( )</h1>
</emu-clause>

<emu-clause id="sec-array.prototype.toSorted">
<h1>Array.prototype.toSorted ( _compareFn_ )</h1>
<h1>Array.prototype.toSorted ( _comparefn_ )</h1>

<p>When the *toSorted* method is called, the following steps are taken:</p>

Expand All @@ -48,19 +154,13 @@ <h1>Array.prototype.toSorted ( _compareFn_ )</h1>
1. Let _O_ be ? ToObject(*this* value).
1. Let _len_ be ? LengthOfArrayLike(_O_).
1. Let _A_ be ? ArrayCreate(𝔽(_len_)).
1. Let _items_ be a new empty List.
1. Let _k_ be 0.
1. Repeat, while _k_ &lt; _len_,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ? Get(_O_, _Pk_).
1. Append _kValue_ to _items_.
1. Set _k_ to _k_ + 1.
1. Sort _items_ using an implementation-defined sequence of calls to SortCompare. If any such call returns an abrupt completion, stop before performing any further calls to SortCompare or steps in this algorithm and return that completion.
1. Let _SortCompare_ be a new Abstract Closure with parameters (_x_, _y_) that captures _comparefn_ and performs the following steps when called:
1. Return ? CompareArrayElements(_x_, _y_, _comparefn_).
1. Let _sortedList_ be ? SortIndexedProperties(_obj_, _len_, _SortCompare_, *false*).
1. Let _j_ be 0.
1. For each element _E_ of _items_, do
1. Let _Pj_ be ! ToString(𝔽(_j_)).
1. Perform ! CreateDataPropertyOrThrow(_A_, _Pj_, _E_).
1. Set _j_ to _j_ + 1.
1. Repeat, while _j_ &lt; _len_,
1. Perform ! CreateDataPropertyOrThrow(_A_, ! ToString(𝔽(_j_)), _sortedList_[_j_]).
1. Set _j_ to _j_ + 1.
1. Return _A_.
</emu-alg>
</emu-clause>
Expand Down Expand Up @@ -197,6 +297,75 @@ <h1>The %TypedArray% Intrinsic Object</h1>
<emu-clause id="sec-properties-of-the-%typedarrayprototype%-object">
<h1>Properties of the %TypedArray% Prototype Object</h1>

<emu-clause id="sec-%typedarray%.prototype.sort" oldids="sec-typedarraysortcompare">
<h1>%TypedArray%.prototype.sort ( _comparefn_ )</h1>

<p>The following steps are performed:</p>
<emu-alg>
1. If _comparefn_ is not *undefined* and IsCallable(_comparefn_) is *false*, throw a *TypeError* exception.
1. Let _obj_ be the *this* value.
1. Perform ? ValidateTypedArray(_obj_).
1. Let _buffer_ be _obj_.[[ViewedArrayBuffer]].
1. Let _len_ be _obj_.[[ArrayLength]].
1. NOTE: The following closure performs a numeric comparison rather than the string comparison used in <emu-xref href="#sec-array.prototype.sort"></emu-xref>.
1. Let _SortCompare_ be a new Abstract Closure with parameters (_x_, _y_) that captures _comparefn_ and _buffer_ and performs the following steps when called:
1. <del>Assert: Both Type(_x_) and Type(_y_) are Number or both are BigInt.</del>
1. <del>If _comparefn_ is not *undefined*, then</del>
1. <del>Let _v_ be ? ToNumber(? Call(_comparefn_, *undefined*, &laquo; _x_, _y_ &raquo;)).</del>
1. <del>If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.</del>
1. <del>If _v_ is *NaN*, return *+0*<sub>𝔽</sub>.</del>
1. <del>Return _v_.</del>
1. <del>If _x_ and _y_ are both *NaN*, return *+0*<sub>𝔽</sub>.</del>
1. <del>If _x_ is *NaN*, return *1*<sub>𝔽</sub>.</del>
1. <del>If _y_ is *NaN*, return *-1*<sub>𝔽</sub>.</del>
1. <del>If _x_ &lt; _y_, return *-1*<sub>𝔽</sub>.</del>
1. <del>If _x_ &gt; _y_, return *1*<sub>𝔽</sub>.</del>
1. <del>If _x_ is *-0*<sub>𝔽</sub> and _y_ is *+0*<sub>𝔽</sub>, return *-1*<sub>𝔽</sub>.</del>
1. <del>If _x_ is *+0*<sub>𝔽</sub> and _y_ is *-0*<sub>𝔽</sub>, return *1*<sub>𝔽</sub>.</del>
1. <del>Return *+0*<sub>𝔽</sub>.</del>
1. <ins>Return ? CompareTypedArrayElements(_x_, _y_, _comparefn_, _buffer_).</ins>
1. <del>Return ? SortIndexedProperties(_obj_, _len_, _SortCompare_).</del>
1. <ins>Let _sortedList_ be ? SortIndexedProperties(_obj_, _len_, _SortCompare_, *false*).</ins>
1. <ins>Let _j_ be 0.</ins>
1. <ins>Repeat, while _j_ &lt; _len_,</ins>
1. <ins>Perform ! Set(_obj_, ! ToString(𝔽(_j_)), _sortedList_[_j_], *true*).</ins>
1. <ins>Set _j_ to _j_ + 1.</ins>
1. <ins>Return _obj_.</ins>
</emu-alg>
</emu-clause>

<emu-clause id="sec-comparetypedarrayelements" type="abstract operation">
<h1>
CompareTypedArrayElements(
_x_: unknown,
_y_: unknown,
_comparefn_: a function object or *undefined*,
_buffer_: An ArrayBuffer
): either a normal completion containing a Number or an abrupt completion
</h1>
<dl class="header">
</dl>
<emu-alg>
1. Assert: Both Type(_x_) and Type(_y_) are Number or both are BigInt.
1. If _comparefn_ is not *undefined*, then
1. Let _v_ be ? ToNumber(? Call(_comparefn_, *undefined*, &laquo; _x_, _y_ &raquo;)).
1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1. If _v_ is *NaN*, return *+0*<sub>𝔽</sub>.
1. Return _v_.
1. If _x_ and _y_ are both *NaN*, return *+0*<sub>𝔽</sub>.
1. If _x_ is *NaN*, return *1*<sub>𝔽</sub>.
1. If _y_ is *NaN*, return *-1*<sub>𝔽</sub>.
1. If _x_ &lt; _y_, return *-1*<sub>𝔽</sub>.
1. If _x_ &gt; _y_, return *1*<sub>𝔽</sub>.
1. If _x_ is *-0*<sub>𝔽</sub> and _y_ is *+0*<sub>𝔽</sub>, return *-1*<sub>𝔽</sub>.
1. If _x_ is *+0*<sub>𝔽</sub> and _y_ is *-0*<sub>𝔽</sub>, return *1*<sub>𝔽</sub>.
1. Return *+0*<sub>𝔽</sub>.
</emu-alg>
<emu-note>
This performs a numeric comparison rather than the string comparison used in <emu-xref href="#sec-comparearrayelements"></emu-xref>.
</emu-note>
</emu-clause>

<emu-clause id="sec-%typedarray%.prototype.toReversed">
<h1>%TypedArray%.prototype.toReversed ( )</h1>

Expand All @@ -219,49 +388,27 @@ <h1>%TypedArray%.prototype.toReversed ( )</h1>
</emu-clause>

<emu-clause id="sec-%typedarray%.prototype.toSorted">
<h1>%TypedArray%.prototype.toSorted ( _compareFn_ )</h1>
<h1>%TypedArray%.prototype.toSorted ( _comparefn_ )</h1>

<p>When the *toSorted* method is called, the following steps are taken:</p>

<emu-alg>
1. If _comparefn_ is not *undefined* and IsCallable(_comparefn_) is *false*, throw a *TypeError* exception.
1. Let _O_ be the *this* value.
1. Perform ? ValidateTypedArray(_O_).
1. Let _buffer_ be _obj_.[[ViewedArrayBuffer]].
1. Let _len_ be _O_.[[ArrayLength]].
1. Let _A_ be ? TypedArrayCreateSameType(_O_, &laquo; 𝔽(_len_) &raquo;).
1. Let _items_ be a new empty List.
1. Let _k_ be 0.
1. Repeat, while _k_ &lt; _len_,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ! Get(_O_, _Pk_).
1. Append _kValue_ to _items_.
1. Set _k_ to _k_ + 1.
1. Sort _items_ using an implementation-defined sequence of calls to SortCompare. If any such call returns an abrupt completion, stop before performing any further calls to SortCompare or steps in this algorithm and return that completion.
1. NOTE: The following closure performs a numeric comparison rather than the string comparison used in <emu-xref href="#sec-array.prototype.toSorted"></emu-xref>.
1. Let _SortCompare_ be a new Abstract Closure with parameters (_x_, _y_) that captures _comparefn_ and _buffer_ and performs the following steps when called:
1. Return ? CompareTypedArrayElements(_x_, _y_, _comparefn_, _buffer_).
1. Let _sortedList_ be ? SortIndexedProperties(_obj_, _len_, _SortCompare_, *false*).
1. Let _j_ be 0.
1. For each element _E_ of _items_, do
1. Let _Pj_ be ! ToString(𝔽(_j_)).
1. Perform ! Set(_A_, _Pj_, _E_, *true*).
1. Set _j_ to _j_ + 1.
1. Repeat, while _j_ &lt; _len_,
1. Perform ! Set(_A_, ! ToString(𝔽(_j_)), _sortedList_[_j_], *true*).
1. Set _j_ to _j_ + 1.
1. Return _A_.
</emu-alg>
<p>The following version of SortCompare is used by %TypedArray%`.prototype.toSorted`.</p>
<p>The abstract operation TypedArraySortCompare performs the following steps when called:</p>
<emu-alg>
1. Assert: Both Type(_x_) and Type(_y_) are Number or both are BigInt.
1. If _comparefn_ is not *undefined*, then
1. Let _v_ be ? ToNumber(? Call(_comparefn_, *undefined*, &laquo; _x_, _y_ &raquo;)).
1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1. If _v_ is *NaN*, return *+0*<sub>𝔽</sub>.
1. Return _v_.
1. If _x_ and _y_ are both *NaN*, return *+0*<sub>𝔽</sub>.
1. If _x_ is *NaN*, return *1*<sub>𝔽</sub>.
1. If _y_ is *NaN*, return *-1*<sub>𝔽</sub>.
1. If _x_ &lt; _y_, return *-1*<sub>𝔽</sub>.
1. If _x_ &gt; _y_, return *1*<sub>𝔽</sub>.
1. If _x_ is *-0*<sub>𝔽</sub> and _y_ is *+0*<sub>𝔽</sub>, return *-1*<sub>𝔽</sub>.
1. If _x_ is *+0*<sub>𝔽</sub> and _y_ is *-0*<sub>𝔽</sub>, return *1*<sub>𝔽</sub>.
1. Return *+0*<sub>𝔽</sub>.
</emu-alg>
</emu-clause>

<emu-clause id="sec-%typedarray%.prototype.toSpliced">
Expand Down

0 comments on commit 7588000

Please sign in to comment.