| diff --git a/spec.html b/spec.html | |
| index ec3918c..e8f809c 100644 | |
| --- a/spec.html | |
| +++ b/spec.html | |
| @@ -5796,6 +5796,17 @@ | |
| Template objects are canonicalized separately for each realm using its Realm Record's [[templateMap]]. Each [[strings]] value is a List containing, in source text order, the raw String values of a |TemplateLiteral| that has been evaluated. The associated [[array]] value is the corresponding template object that is passed to a tag function. | |
| </td> | |
| </tr> | |
| + <tr> | |
| + <td> | |
| + [[arrayJoinCyclicSet]] | |
| + </td> | |
| + <td> | |
| + A List of objects. | |
| + </td> | |
| + <td> | |
| + (Objects in Array.prototype.join and friends.) | |
| + </td> | |
| + </tr> | |
| </tbody> | |
| </table> | |
| </emu-table> | |
| @@ -29836,24 +29847,39 @@ Date.parse(x.toLocaleString()) | |
| <p>The `join` method takes one argument, _separator_, and performs the following steps:</p> | |
| <emu-alg> | |
| 1. Let _O_ be ? ToObject(*this* value). | |
| - 1. Let _len_ be ? ToLength(? Get(_O_, `"length"`)). | |
| - 1. If _separator_ is *undefined*, let _separator_ be the single-element String `","`. | |
| - 1. Let _sep_ be ? ToString(_separator_). | |
| - 1. If _len_ is zero, return the empty String. | |
| - 1. Let _element0_ be Get(_O_, `"0"`). | |
| - 1. If _element0_ is *undefined* or *null*, let _R_ be the empty String; otherwise, let _R_ be ? ToString(_element0_). | |
| - 1. Let _k_ be `1`. | |
| - 1. Repeat, while _k_ < _len_ | |
| - 1. Let _S_ be the String value produced by concatenating _R_ and _sep_. | |
| - 1. Let _element_ be ? Get(_O_, ! ToString(_k_)). | |
| - 1. If _element_ is *undefined* or *null*, let _next_ be the empty String; otherwise, let _next_ be ? ToString(_element_). | |
| - 1. Let _R_ be a String value produced by concatenating _S_ and _next_. | |
| - 1. Increase _k_ by 1. | |
| - 1. Return _R_. | |
| + 1. Let _realm_ be the current Realm Record. | |
| + 1. Let _set_ be _realm_.[[arrayJoinCyclicSet]]. | |
| + 1. If _set_ contains _O_, return `""`. | |
| + 1. Append _O_ as the last element of _set_. | |
| + 1. Let _result_ be ArrayJoin(_O_, _separator_). | |
| + 1. Remove the last element of _set_. | |
| + 1. Return _result_. | |
| </emu-alg> | |
| <emu-note> | |
| <p>The `join` function is intentionally generic; it does not require that its *this* value be an Array object. Therefore, it can be transferred to other kinds of objects for use as a method.</p> | |
| </emu-note> | |
| + | |
| + <emu-clause id="sec-array-join" aoid="ArrayJoin"> | |
| + <h1>Runtime Semantics: ArrayJoin ( _O_ )</h1> | |
| + <p>The abstract operation ArrayJoin with arguments _O_ and _separator_ performs the following steps:</p> | |
| + <emu-alg> | |
| + 1. Assert: Type(_O_) is Object. | |
| + 1. Let _len_ be ? ToLength(? Get(_O_, `"length"`)). | |
| + 1. If _separator_ is *undefined*, let _separator_ be the single-element String `","`. | |
| + 1. Let _sep_ be ? ToString(_separator_). | |
| + 1. If _len_ is zero, return the empty String. | |
| + 1. Let _element0_ be Get(_O_, `"0"`). | |
| + 1. If _element0_ is *undefined* or *null*, let _R_ be the empty String; otherwise, let _R_ be ? ToString(_element0_). | |
| + 1. Let _k_ be `1`. | |
| + 1. Repeat, while _k_ < _len_ | |
| + 1. Let _S_ be the String value produced by concatenating _R_ and _sep_. | |
| + 1. Let _element_ be ? Get(_O_, ! ToString(_k_)). | |
| + 1. If _element_ is *undefined* or *null*, let _next_ be the empty String; otherwise, let _next_ be ? ToString(_element_). | |
| + 1. Let _R_ be a String value produced by concatenating _S_ and _next_. | |
| + 1. Increase _k_ by 1. | |
| + 1. Return _R_. | |
| + </emu-alg> | |
| + </emu-clause> | |
| </emu-clause> | |
| <!-- es6num="22.1.3.13" --> | |
| @@ -30428,25 +30454,13 @@ Date.parse(x.toLocaleString()) | |
| <p>The following steps are taken:</p> | |
| <emu-alg> | |
| 1. Let _array_ be ? ToObject(*this* value). | |
| - 1. Let _len_ be ? ToLength(? Get(_array_, `"length"`)). | |
| - 1. Let _separator_ be the String value for the list-separator String appropriate for the host environment's current locale (this is derived in an implementation-defined way). | |
| - 1. If _len_ is zero, return the empty String. | |
| - 1. Let _firstElement_ be ? Get(_array_, `"0"`). | |
| - 1. If _firstElement_ is *undefined* or *null*, then | |
| - 1. Let _R_ be the empty String. | |
| - 1. Else, | |
| - 1. Let _R_ be ? ToString(? Invoke(_firstElement_, `"toLocaleString"`)). | |
| - 1. Let _k_ be `1`. | |
| - 1. Repeat, while _k_ < _len_ | |
| - 1. Let _S_ be a String value produced by concatenating _R_ and _separator_. | |
| - 1. Let _nextElement_ be ? Get(_array_, ! ToString(_k_)). | |
| - 1. If _nextElement_ is *undefined* or *null*, then | |
| - 1. Let _R_ be the empty String. | |
| - 1. Else, | |
| - 1. Let _R_ be ? ToString(? Invoke(_nextElement_, `"toLocaleString"`)). | |
| - 1. Let _R_ be a String value produced by concatenating _S_ and _R_. | |
| - 1. Increase _k_ by 1. | |
| - 1. Return _R_. | |
| + 1. Let _realm_ be the current Realm Record. | |
| + 1. Let _set_ be _realm_.[[arrayJoinCyclicSet]]. | |
| + 1. If _set_ contains _array_, return `""`. | |
| + 1. Append _array_ as the last element of _set_. | |
| + 1. Let _result_ be ArrayToLocaleString(_array_). | |
| + 1. Remove the last element of _set_. | |
| + 1. Return _result_. | |
| </emu-alg> | |
| <emu-note> | |
| <p>The elements of the array are converted to Strings using their `toLocaleString` methods, and these Strings are then concatenated, separated by occurrences of a separator String that has been derived in an implementation-defined locale-specific way. The result of calling this function is intended to be analogous to the result of `toString`, except that the result of this function is intended to be locale-specific.</p> | |
| @@ -30454,6 +30468,33 @@ Date.parse(x.toLocaleString()) | |
| <emu-note> | |
| <p>The `toLocaleString` function is intentionally generic; it does not require that its *this* value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method.</p> | |
| </emu-note> | |
| + | |
| + <emu-clause id="sec-array-tolocalestring" aoid="ArrayToLocaleString"> | |
| + <h1>Runtime Semantics: ArrayToLocaleString ( _array_ )</h1> | |
| + <p>The abstract operation ArrayToLocaleString with argument _array_ performs the following steps:</p> | |
| + <emu-alg> | |
| + 1. Assert: Type(_array_) is Object. | |
| + 1. Let _len_ be ? ToLength(? Get(_array_, `"length"`)). | |
| + 1. Let _separator_ be the String value for the list-separator String appropriate for the host environment's current locale (this is derived in an implementation-defined way). | |
| + 1. If _len_ is zero, return the empty String. | |
| + 1. Let _firstElement_ be ? Get(_array_, `"0"`). | |
| + 1. If _firstElement_ is *undefined* or *null*, then | |
| + 1. Let _R_ be the empty String. | |
| + 1. Else, | |
| + 1. Let _R_ be ? ToString(? Invoke(_firstElement_, `"toLocaleString"`)). | |
| + 1. Let _k_ be `1`. | |
| + 1. Repeat, while _k_ < _len_ | |
| + 1. Let _S_ be a String value produced by concatenating _R_ and _separator_. | |
| + 1. Let _nextElement_ be ? Get(_array_, ! ToString(_k_)). | |
| + 1. If _nextElement_ is *undefined* or *null*, then | |
| + 1. Let _R_ be the empty String. | |
| + 1. Else, | |
| + 1. Let _R_ be ? ToString(? Invoke(_nextElement_, `"toLocaleString"`)). | |
| + 1. Let _R_ be a String value produced by concatenating _S_ and _R_. | |
| + 1. Increase _k_ by 1. | |
| + 1. Return _R_. | |
| + </emu-alg> | |
| + </emu-clause> | |
| </emu-clause> | |
| <!-- es6num="22.1.3.27" --> |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
allenwb
commented
Jan 15, 2016
|
Wow, a single global per realm cycle list. That seems potentially problematic in so many ways. Particularly now that we have many ways (accessor properties, proxies) that arbitrary user code can get invoked in the middle of such an algorithm. For example, if an array element was a proxied object whose handler happened to use [].join for some purpose that was completely independent of a currently inflight [].join/toString then the handler might break in unexpected ways??? Also not very unclear what happens if a recursive array structure contains array elements from different realms? Calling a toString from a different switches the current Realm. Does that mean that the cycle detection does not work on such structures. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
bterlson
Jan 15, 2016
@allenwb would be better to discuss this in tc39/ecma262#289 so we get email notifications!
bterlson
commented
Jan 15, 2016
|
@allenwb would be better to discuss this in tc39/ecma262#289 so we get email notifications! |
Wow, a single global per realm cycle list. That seems potentially problematic in so many ways.
Particularly now that we have many ways (accessor properties, proxies) that arbitrary user code can get invoked in the middle of such an algorithm. For example, if an array element was a proxied object whose handler happened to use [].join for some purpose that was completely independent of a currently inflight [].join/toString then the handler might break in unexpected ways???
Also not very unclear what happens if a recursive array structure contains array elements from different realms? Calling a toString from a different switches the current Realm. Does that mean that the cycle detection does not work on such structures.