From 1388e5c78195ffb10e20a9100a5e7813595cb1a8 Mon Sep 17 00:00:00 2001 From: Tab Atkins-Bittner Date: Thu, 5 May 2022 11:41:38 -0700 Subject: [PATCH 1/4] Precisely specify iteration details. Fixes #396 --- infra.bs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/infra.bs b/infra.bs index a5662fd..bb39d89 100644 --- a/infra.bs +++ b/infra.bs @@ -1389,6 +1389,7 @@ its size is zero. set of steps on each item in order, use phrasing of the form "For each |item| of list", and then operate on |item| in the subsequent prose. +The subsequent prose constitutes the |steps| of [=sequence iteration=] over the [=list=].

To clone a list |list| is to create a new list |clone|, of the same designation, and, for each |item| of |list|, @@ -1424,6 +1425,23 @@ ascending order, with |a| being less than |b| if |a|'s second item code unit less than |b|'s second item, gives the result « (404, "Not Found"), (200, "OK"), (null, "OK") ».

+
+ Sequence iteration over an ordered sequence |seq|, + given some per-item |steps|, + means to: + + 1. Let |length| be the number of entries in |seq|. + 1. Let |index| initially be 0. + 1. While |index| < |length|: + 1. Let |entry| be the |index|th entry in |seq|. + 1. Invoke |steps| with |entry|. + 1. Increment |index| by 1. + 1. Set |length| to the number of entries in |seq|. + + Note: Both the number of entries in |seq|, and their order, + can potentialy change while invoking |steps|. +
+

The list type originates from the JavaScript specification (where it is capitalized, as @@ -1595,6 +1613,7 @@ of running get the keys on the map. a set of steps on each entry in order, use phrasing of the form "For each |key| → |value| of |map|", and then operate on |key| and |value| in the subsequent prose. +The subsequent prose constitutes the |steps| of [=sequence iteration=] over the [=map=].

To clone an ordered map |map| is to create a new ordered map |clone|, and, for each |key| → |value| of |map|, From 892a1e8d7ed10f7868f3344beabad65d368a0053 Mon Sep 17 00:00:00 2001 From: Tab Atkins-Bittner Date: Thu, 5 May 2022 16:02:58 -0700 Subject: [PATCH 2/4] Specialize iteration on lists and maps to use better-defined terms. Adjust wording of the invocation as suggested. --- infra.bs | 59 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/infra.bs b/infra.bs index bb39d89..7cb1ad5 100644 --- a/infra.bs +++ b/infra.bs @@ -1385,11 +1385,23 @@ its size is zero. list, return the range from 0 to the list's size, exclusive. -

To iterate over a list, performing a -set of steps on each item in order, use phrasing of the form -"For each |item| of list", and then operate on |item| in the -subsequent prose. -The subsequent prose constitutes the |steps| of [=sequence iteration=] over the [=list=]. +

To iterate over a list |list|, +performing a set of steps |steps| on each item in order, perform [=list iteration=] +using |list| and |steps|. This can also be (and usually is) written as "[=list/For each=] +|item| of |list|: |steps|". + +

+ + List iteration over a [=list=] |list|, given some per-item |steps|, means to: + + 1. Let |index| initially be 0. + 1. While |index| < |list|'s [=list/size=]: + 1. Invoke |steps| with |list|[|index|]. + 1. Increment |index| by 1. + + Note: Both the [=list/size=] of |list|, and the order of its items, can potentialy change while + invoking |steps|. +

To clone a list |list| is to create a new list |clone|, of the same designation, and, for each |item| of |list|, @@ -1425,23 +1437,6 @@ ascending order, with |a| being less than |b| if |a|'s second item code unit less than |b|'s second item, gives the result « (404, "Not Found"), (200, "OK"), (null, "OK") ».

-
- Sequence iteration over an ordered sequence |seq|, - given some per-item |steps|, - means to: - - 1. Let |length| be the number of entries in |seq|. - 1. Let |index| initially be 0. - 1. While |index| < |length|: - 1. Let |entry| be the |index|th entry in |seq|. - 1. Invoke |steps| with |entry|. - 1. Increment |index| by 1. - 1. Set |length| to the number of entries in |seq|. - - Note: Both the number of entries in |seq|, and their order, - can potentialy change while invoking |steps|. -
-

The list type originates from the JavaScript specification (where it is capitalized, as @@ -1613,7 +1608,25 @@ of running get the keys on the map. a set of steps on each entry in order, use phrasing of the form "For each |key| → |value| of |map|", and then operate on |key| and |value| in the subsequent prose. -The subsequent prose constitutes the |steps| of [=sequence iteration=] over the [=map=]. + +

To iterate over an ordered map |map|, +performing a set of steps |steps| on each [=map/entry=] in order, perform [=map iteration=] +using |map| and |steps|. This can also be (and usually is) written as "[=map/For each=] +|key| → |value| of |map|: |steps|". + +

+ Map iteration over a [=map=] |map|, given some per-item |steps|, means to: + + 1. Let |index| initially be 0. + 1. While |index| < |map|'s [=map/size=]: + 1. Let |entry| be the |index|th entry in [=map=]. + 1. Let |key| and |value| be the [=map/key=] and [=map/value=] of |entry|. + 1. Invoke |steps| with |key| and |value|. + 1. Increment |index| by 1. + + Note: Both the [=map/size=] of |map|, and the order of its entries, can potentialy change while + invoking |steps|. +

To clone an ordered map |map| is to create a new ordered map |clone|, and, for each |key| → |value| of |map|, From a6903577370ac832b848ced19247178fe2179181 Mon Sep 17 00:00:00 2001 From: Tab Atkins-Bittner Date: Thu, 5 May 2022 16:03:50 -0700 Subject: [PATCH 3/4] Whoops, removing lingering old verison of map/iterate. --- infra.bs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/infra.bs b/infra.bs index 7cb1ad5..7bf98ff 100644 --- a/infra.bs +++ b/infra.bs @@ -1604,11 +1604,6 @@ of running get the keys on the map.

An ordered map is empty if its size is zero. -

To iterate over an ordered map, performing -a set of steps on each entry in order, use phrasing of the form -"For each |key| → |value| of |map|", and then operate on |key| and |value| in the -subsequent prose. -

To iterate over an ordered map |map|, performing a set of steps |steps| on each [=map/entry=] in order, perform [=map iteration=] using |map| and |steps|. This can also be (and usually is) written as "[=map/For each=] From cf68dbb70fe8fed8639ec67806ff630626a08679 Mon Sep 17 00:00:00 2001 From: Tab Atkins-Bittner Date: Tue, 13 Dec 2022 14:17:52 -0800 Subject: [PATCH 4/4] Add holes to lists and maps, and define iteration using those. --- infra.bs | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/infra.bs b/infra.bs index 7bf98ff..2d8bc04 100644 --- a/infra.bs +++ b/infra.bs @@ -1319,6 +1319,12 @@ out-of-bounds, except when used with exists. "b", "c", "a" ». Then |example|[1] is the string "b". +

Lists can also have holes, which mark the location of a deleted value. Holes are not exposed to any algorithm unless explicitly called out; in all other cases, holes are treated as if they did not exist and are automatically skipped over. There is no literal syntax for holes. + +

For example, if the list « 0, 1, 2 » has the item at index 1 [=list/removed=], it leaves behind a hole in its position. Subsequent requests for the item at index 1 will now return 2, as index counting skips over holes unless otherwise specified; similarly, the list will report its [=list/size=] as 2 rather than 3. + +Note: Holes exist to make [=list/iteration=] stable and predictable when the list can be mutated during the iteration, matching ECMAScript behavior. If the [=list=] is read-only or not currently being iterated by anything, [=list/holes=] can be omitted or removed. +


To append to a list that is not an ordered set is to @@ -1356,7 +1362,7 @@ index is to add the given item to the list between the given index − 1 and the given index is 0, then prepend the given item to the list.

To remove zero or more items from a list is -to remove all items from the list that match a given condition, or do nothing if none do. +to remove all items from the list that match a given condition, replacing each with a [=list/hole=], or do nothing if none do.

Removing |x| from the list « |x|, |y|, |z|, |x| » is to remove all @@ -1369,7 +1375,7 @@ to remove all items from the list that match a given condition, or do nothing if

To empty a list is to remove -all of its items. +all of its items, replacing all of them with [=list/holes=].

A list contains an item if it appears in the list. We can also denote this by saying that, for a @@ -1395,18 +1401,20 @@ using |list| and |steps|. This can also be (and usually is) written as "[=list/F List iteration over a [=list=] |list|, given some per-item |steps|, means to: 1. Let |index| initially be 0. - 1. While |index| < |list|'s [=list/size=]: - 1. Invoke |steps| with |list|[|index|]. + 1. While |index| < |list|'s [=list/size=] (including [=list/holes=]): + 1. Let |item| be |list|[|index|] (including [=list/holes=]). 1. Increment |index| by 1. + 1. If |item| is a [=list/hole=], [=iteration/continue=]. + 1. Invoke |steps| with |item|. - Note: Both the [=list/size=] of |list|, and the order of its items, can potentialy change while - invoking |steps|. + Note: Entries deleted from the list before being visited will not be processed. + Otherwise, every entry in a list is visited exactly once, including any entries added after iteration has begun.

To clone a list |list| is to create a new list |clone|, of the same designation, and, for each |item| of |list|, append |item| to |clone|, so that |clone| contains the same -items, in the same order as |list|. +items, in the same order as |list|, omitting any [=list/holes=] that |list| contains.

This is a "shallow clone", as the items themselves are not cloned in any way. @@ -1552,6 +1560,10 @@ entries with a comma. "a" → `x`, "b" → `y` ]». Then |example|["a"] is the byte sequence `x`. +

[=Maps=] can have holes, which mark the location of a deleted value. A hole is considered to have a key and value which are also holes. Holes are not exposed to any algorithm unless explicitly called out; in all other cases, holes are treated as if they did not exist and are automatically skipped over. There is no literal syntax for holes. + +Note: As with [=list=] [=list/holes=], these exist solely to make [=map/iteration=] stable and predictable, and to match ECMAScript Map iteration. If the [=map=] is read-only, or nothing is iterating the map, [=map/holes=] can be omitted or removed. +


To get the value of an entry in an @@ -1578,12 +1590,12 @@ also denote this by saying, for an ordered map |map|, key |key|, and valu "set |map|[|key|] to |value|".

To remove an entry from an ordered map is to remove -all entries from the map that match a given condition, or do nothing if none do. If +all entries from the map that match a given condition, replacing them with [=map/holes=], or do nothing if none do. If the condition is having a certain key, then we can also denote this by saying, for an ordered map |map| and key |key|, "remove |map|[|key|]".

To clear an ordered map is to remove all entries -from the map. +from the map, leaving [=map/holes=] in their places.

An ordered map contains an entry with a given key if there exists an entry with that key. @@ -1613,14 +1625,15 @@ using |map| and |steps|. This can also be (and usually is) written as "[=map/For Map iteration over a [=map=] |map|, given some per-item |steps|, means to: 1. Let |index| initially be 0. - 1. While |index| < |map|'s [=map/size=]: - 1. Let |entry| be the |index|th entry in [=map=]. + 1. While |index| < |map|'s [=map/size=] (including [=map/holes=]): + 1. Let |entry| be the |index|th entry in [=map=] (including [=map/holes=]). + 1. Increment |index| by 1. + 1. If |entry| is a [=map/hole=], [=iteration/continue=]. 1. Let |key| and |value| be the [=map/key=] and [=map/value=] of |entry|. 1. Invoke |steps| with |key| and |value|. - 1. Increment |index| by 1. - Note: Both the [=map/size=] of |map|, and the order of its entries, can potentialy change while - invoking |steps|. + Note: Entries deleted from the map before being visited will not be processed. + Otherwise, every entry in a map is visited exactly once, including any entries added after iteration has begun.

To clone an ordered map |map| is to create a new