diff --git a/spec.html b/spec.html index 277f6f7397..e0c9058496 100644 --- a/spec.html +++ b/spec.html @@ -9535,6 +9535,77 @@

+ +

Contents

+ + +

Static Semantics: ArrayLiteralContentNodes ( ): a List of Parse Nodes

+
+
+ + ArrayLiteral : + `[` Elision? `]` + `[` ElementList `]` + `[` ElementList `,` Elision? `]` + + + 1. Let _elements_ be a new empty List. + 1. If |ElementList| is present, set _elements_ to the list-concatenation of _elements_ and ArrayLiteralContentNodes of |ElementList|. + 1. If |Elision| is present, append |Elision| to _elements_. + 1. Return _elements_. + + + ElementList : Elision? AssignmentExpression + + 1. Let _elements_ be a new empty List. + 1. If |Elision| is present, append |Elision| to _elements_. + 1. Return the list-concatenation of _elements_ and « |AssignmentExpression| ». + + + ElementList : Elision? SpreadElement + + 1. Let _elements_ be a new empty List. + 1. If |Elision| is present, append |Elision| to _elements_. + 1. Return the list-concatenation of _elements_ and « |SpreadElement| ». + + + ElementList : ElementList `,` Elision? AssignmentExpression + + 1. Let _elements_ be ArrayLiteralContentNodes of |ElementList|. + 1. If |Elision| is present, append |Elision| to _elements_. + 1. Return the list-concatenation of _elements_ and « |AssignmentExpression| ». + + + ElementList : ElementList `,` Elision? SpreadElement + + 1. Let _elements_ be ArrayLiteralContentNodes of |ElementList|. + 1. If |Elision| is present, append |Elision| to _elements_. + 1. Return the list-concatenation of _elements_ and « |SpreadElement| ». + +
+ + +

Static Semantics: PropertyDefinitionNodes ( ): a List of Parse Nodes

+
+
+ + ObjectLiteral : `{` `}` + + 1. Return a new empty List. + + + PropertyDefinitionList : PropertyDefinition + + 1. Return « |PropertyDefinition| ». + + + PropertyDefinitionList : PropertyDefinitionList `,` PropertyDefinition + + 1. Return the list-concatenation of PropertyDefinitionNodes of |PropertyDefinitionList| and « |PropertyDefinition| ». + +
+
+

Miscellaneous

These operations are used in multiple places throughout the specification.

@@ -28637,8 +28708,8 @@

- 1. Let _json_ be ? ParseJSON(_source_). - 1. Return CreateDefaultExportSyntheticModule(_json_). + 1. Let _result_ be ? ParseJSON(_source_). + 1. Return CreateDefaultExportSyntheticModule(_result_.[[Value]]). @@ -46979,18 +47050,29 @@

The JSON Object

The JSON Data Interchange Format is defined in ECMA-404. The JSON interchange format used in this specification is exactly that described by ECMA-404. Conforming implementations of `JSON.parse` and `JSON.stringify` must support the exact interchange format described in the ECMA-404 specification without any deletions or extensions to the format.

+ +

JSON.isRawJSON ( _O_ )

+

This function performs the following steps when called:

+ + 1. If _O_ is an Object and _O_ has an [[IsRawJSON]] internal slot, return *true*. + 1. Return *false*. + +
+

JSON.parse ( _text_ [ , _reviver_ ] )

This function parses a JSON text (a JSON-formatted String) and produces an ECMAScript language value. The JSON format represents literals, arrays, and objects with a syntax similar to the syntax for ECMAScript literals, Array Initializers, and Object Initializers. After parsing, JSON objects are realized as ECMAScript objects. JSON arrays are realized as ECMAScript Array instances. JSON strings, numbers, booleans, and null are realized as ECMAScript Strings, Numbers, Booleans, and *null*.

-

The optional _reviver_ parameter is a function that takes two parameters, _key_ and _value_. It can filter and transform the results. It is called with each of the _key_/_value_ pairs produced by the parse, and its return value is used instead of the original value. If it returns what it received, the structure is not modified. If it returns *undefined* then the property is deleted from the result.

+

The optional _reviver_ parameter is a function that can filter and transform the results. For each value produced by the parse, it is called with three arguments (the key, the value, and a context object containing [for unmodified primitive values] details of the corresponding Parse Node) and its return value is used instead of the original value. If it returns what it received, the structure is not modified. If it returns *undefined* then the property is deleted from the result.

1. Let _jsonString_ be ? ToString(_text_). - 1. Let _unfiltered_ be ? ParseJSON(_jsonString_). + 1. Let _parseResult_ be ? ParseJSON(_jsonString_). + 1. Let _unfiltered_ be _parseResult_.[[Value]]. 1. If IsCallable(_reviver_) is *true*, then 1. Let _root_ be OrdinaryObjectCreate(%Object.prototype%). 1. Let _rootName_ be the empty String. 1. Perform ! CreateDataPropertyOrThrow(_root_, _rootName_, _unfiltered_). - 1. Return ? InternalizeJSONProperty(_root_, _rootName_, _reviver_). + 1. Let _snapshot_ be CreateJSONParseRecord(_parseResult_.[[ParseNode]], _rootName_, _unfiltered_). + 1. Return ? InternalizeJSONProperty(_root_, _rootName_, _reviver_, _snapshot_). 1. Else, 1. Return _unfiltered_. @@ -47013,7 +47095,7 @@

1. [id="step-json-parse-eval"] Let _result_ be ! Evaluation of _script_. 1. NOTE: The PropertyDefinitionEvaluation semantics defined in have special handling for the above evaluation. 1. [id="step-json-parse-assert-type"] Assert: _result_ is either a String, a Number, a Boolean, an Object that is defined by either an |ArrayLiteral| or an |ObjectLiteral|, or *null*. - 1. Return _result_. + 1. Return the Record { [[ParseNode]]: _script_, [[Value]]: _result_ }.

It is not permitted for a conforming implementation of `JSON.parse` to extend the JSON grammars. If an implementation wishes to support a modified or extended JSON interchange format it must do so by defining a different parse function.

@@ -47025,12 +47107,105 @@

+ +

JSON Parse Record

+

A JSON Parse Record is a Record value used to describe the initial state of a value parsed from JSON text.

+

JSON Parse Records have the fields listed in .

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Field NameValueMeaning
[[ParseNode]]a Parse NodeThe context Parse Node.
[[Key]]a property nameThe property name with which [[Value]] is associated.
[[Value]]an ECMAScript language valueThe value produced by evaluation of [[ParseNode]].
[[Elements]]a List of JSON Parse RecordsJSON Parse Records corresponding with the elements of a [[Value]] that is an Array, in order. If [[Value]] is not an Array, the List will be empty.
[[Entries]]a List of JSON Parse RecordsJSON Parse Records corresponding with the entries of a [[Value]] that is a non-Array Object, in source order. If [[Value]] is not a non-Array Object, the List will be empty.
+
+
+ + +

+ CreateJSONParseRecord ( + _parseNode_: a Parse Node, + _key_: a property name, + _val_: an ECMAScript language value, + ): a JSON Parse Record +

+
+
description
+
It recursively combines a _parseNode_ parsed from JSON text and the _val_ produced by its evaluation.
+
+ + 1. Let _typedValNode_ be ShallowestContainedJSONValue of _parseNode_. + 1. Assert: _typedValNode_ is not ~empty~. + 1. Let _elements_ be a new empty List. + 1. Let _entries_ be a new empty List. + 1. If _val_ is an Object, then + 1. Let _isArray_ be ! IsArray(_val_). + 1. If _isArray_ is *true*, then + 1. Assert: _typedValNode_ is an |ArrayLiteral| Parse Node. + 1. Let _contentNodes_ be ArrayLiteralContentNodes of _typedValNode_. + 1. Let _len_ be the number of elements in _contentNodes_. + 1. Let _valLen_ be ! LengthOfArrayLike(_val_). + 1. Assert: _valLen_ = _len_. + 1. Let _I_ be 0. + 1. Repeat, while _I_ < _len_, + 1. Let _propName_ be ! ToString(𝔽(_I_)). + 1. Let _elementParseRecord_ be CreateJSONParseRecord(_contentNodes_[_I_], _propName_, ! Get(_val_, _propName_)). + 1. Append _elementParseRecord_ to _elements_. + 1. Set _I_ to _I_ + 1. + 1. Else, + 1. Assert: _typedValNode_ is an |ObjectLiteral| Parse Node. + 1. Let _propertyNodes_ be PropertyDefinitionNodes of _typedValNode_. + 1. NOTE: Because _val_ was produced from JSON text and has not been modified, all of its property keys are Strings and will be exhaustively enumerated. + 1. Let _keys_ be ! EnumerableOwnProperties(_val_, ~key~). + 1. For each String _P_ of _keys_, do + 1. NOTE: In the case of JSON text specifying multiple name/value pairs with the same name for a single object (such as {"a":"lost","a":"kept"}), the value for the corresponding property of the resulting ECMAScript object is specified by the last pair with that name. + 1. Let _propertyDefinition_ be ~empty~. + 1. For each Parse Node _propertyNode_ of _propertyNodes_, do + 1. Let _propName_ be PropName of _propertyNode_. + 1. If _propName_ is _P_, set _propertyDefinition_ to _propertyNode_. + 1. Assert: _propertyDefinition_ is PropertyDefinition : PropertyName `:` AssignmentExpression. + 1. Let _propertyValueNode_ be the |AssignmentExpression| of _propertyDefinition_. + 1. Let _entryParseRecord_ be CreateJSONParseRecord(_propertyValueNode_, _P_, ! Get(_val_, _P_)). + 1. Append _entryParseRecord_ to _entries_. + 1. Else, + 1. Assert: _typedValNode_ is not an |ArrayLiteral| Parse Node and not an |ObjectLiteral| Parse Node. + 1. Return the JSON Parse Record { [[ParseNode]]: _typedValNode_, [[Key]]: _key_, [[Value]]: _val_, [[Elements]]: _elements_, [[Entries]]: _entries_ }. + +
+

InternalizeJSONProperty ( _holder_: an Object, _name_: a String, _reviver_: a function object, + _parseRecord_: either a JSON Parse Record or ~empty~, ): either a normal completion containing an ECMAScript language value or a throw completion

@@ -47041,14 +47216,28 @@

It performs the following steps when called:

1. Let _val_ be ? Get(_holder_, _name_). + 1. Let _context_ be OrdinaryObjectCreate(%Object.prototype%). + 1. If _parseRecord_ is a JSON Parse Record and SameValue(_parseRecord_.[[Value]], _val_) is *true*, then + 1. If _val_ is not an Object, then + 1. Let _parseNode_ be _parseRecord_.[[ParseNode]]. + 1. Assert: _parseNode_ is not an |ArrayLiteral| Parse Node and not an |ObjectLiteral| Parse Node. + 1. Let _sourceText_ be the source text matched by _parseNode_. + 1. Perform ! CreateDataPropertyOrThrow(_context_, *"source"*, CodePointsToString(_sourceText_)). + 1. Let _elementRecords_ be _parseRecord_.[[Elements]]. + 1. Let _entryRecords_ be _parseRecord_.[[Entries]]. + 1. Else, + 1. Let _elementRecords_ be a new empty List. + 1. Let _entryRecords_ be a new empty List. 1. If _val_ is an Object, then 1. Let _isArray_ be ? IsArray(_val_). 1. If _isArray_ is *true*, then + 1. Let _elementRecordsLen_ be the number of elements in _elementRecords_. 1. Let _len_ be ? LengthOfArrayLike(_val_). 1. Let _I_ be 0. 1. Repeat, while _I_ < _len_, 1. Let _prop_ be ! ToString(𝔽(_I_)). - 1. Let _newElement_ be ? InternalizeJSONProperty(_val_, _prop_, _reviver_). + 1. If _I_ < _elementRecordsLen_, let _elementRecord_ be _elementRecords_[_I_]. Otherwise, let _elementRecord_ be ~empty~. + 1. Let _newElement_ be ? InternalizeJSONProperty(_val_, _prop_, _reviver_, _elementRecord_). 1. If _newElement_ is *undefined*, then 1. Perform ? _val_.[[Delete]](_prop_). 1. Else, @@ -47057,16 +47246,71 @@

1. Else, 1. Let _keys_ be ? EnumerableOwnProperties(_val_, ~key~). 1. For each String _P_ of _keys_, do - 1. Let _newElement_ be ? InternalizeJSONProperty(_val_, _P_, _reviver_). + 1. Let _entryRecord_ be the element of _entryRecords_ whose [[Key]] field is _P_. If there is no such element, set _entryRecord_ to ~empty~. + 1. Let _newElement_ be ? InternalizeJSONProperty(_val_, _P_, _reviver_, _entryRecord_). 1. If _newElement_ is *undefined*, then 1. Perform ? _val_.[[Delete]](_P_). 1. Else, 1. Perform ? CreateDataProperty(_val_, _P_, _newElement_). - 1. Return ? Call(_reviver_, _holder_, « _name_, _val_ »). + 1. Return ? Call(_reviver_, _holder_, « _name_, _val_, _context_ »). + + + + +

Static Semantics: ShallowestContainedJSONValue ( ): a Parse Node or ~empty~

+
+
description
+
It performs a breadth-first search of the parse tree rooted at the context node, and returns the first node that is an instance of a nonterminal corresponding to a JSON value, or ~empty~ if there is no such node.
+
+ + 1. Let _F_ be the active function object. + 1. Assert: _F_ is a `JSON.parse` built-in function object (see JSON.parse). + 1. Let _types_ be « |NullLiteral|, |BooleanLiteral|, |NumericLiteral|, |StringLiteral|, |ArrayLiteral|, |ObjectLiteral|, |UnaryExpression| ». + 1. Let _unaryExpression_ be ~empty~. + 1. Let _queue_ be « this Parse Node ». + 1. Repeat, while _queue_ is not empty, + 1. Let _candidate_ be the first element of _queue_. + 1. Remove the first element from _queue_. + 1. Let _queuedChildren_ be *false*. + 1. For each nonterminal _type_ of _types_, do + 1. If _candidate_ is an instance of _type_, then + 1. NOTE: In the JSON grammar, a number token may represent a negative value. In ECMAScript, negation is represented as a unary operation. + 1. If _type_ is |UnaryExpression|, then + 1. Set _unaryExpression_ to _candidate_. + 1. Else if _type_ is |NumericLiteral|, then + 1. Assert: _candidate_ is contained within _unaryExpression_. + 1. Return _unaryExpression_. + 1. Else, + 1. Return _candidate_. + 1. If _queuedChildren_ is *false* and _candidate_ is an instance of a nonterminal and _candidate_ Contains _type_ is *true*, then + 1. Let _children_ be a List containing each child node of _candidate_, in order. + 1. Set _queue_ to the list-concatenation of _queue_ and _children_. + 1. Set _queuedChildren_ to *true*. + 1. Return ~empty~.
+ +

JSON.rawJSON ( _text_ )

+

The `rawJSON` function returns an object representing raw JSON text of a string, number, boolean, or null value.

+ + 1. Let _jsonString_ be ? ToString(_text_). + 1. If _jsonString_ is the empty String, throw a *SyntaxError* exception. + 1. If either the first or last code unit of _jsonString_ is any of 0x0009 (CHARACTER TABULATION), 0x000A (LINE FEED), 0x000D (CARRIAGE RETURN), 0x0020 (SPACE), 0x005B (LEFT SQUARE BRACKET), or 0x007B (LEFT CURLY BRACKET), throw a *SyntaxError* exception. + 1. Let _parseResult_ be ? ParseJSON(_jsonString_). + 1. Let _value_ be _parseResult_.[[Value]]. + 1. Assert: _value_ is either a String, a Number, a Boolean, or *null*. + 1. Assert: The first code unit of _jsonString_ is an ASCII lowercase letter code unit (0x0061 through 0x007A, inclusive), an ASCII digit code unit (0x0030 through 0x0039, inclusive), 0x0022 (QUOTATION MARK), or 0x002D (HYPHEN-MINUS). + 1. Assert: The last code unit of _jsonString_ is an ASCII lowercase letter code unit (0x0061 through 0x007A, inclusive), an ASCII digit code unit (0x0030 through 0x0039, inclusive), or 0x0022 (QUOTATION MARK). + 1. Let _internalSlotsList_ be « [[IsRawJSON]] ». + 1. Let _obj_ be OrdinaryObjectCreate(*null*, _internalSlotsList_). + 1. Perform ! CreateDataPropertyOrThrow(_obj_, *"rawJSON"*, _jsonString_). + 1. Perform ! SetIntegrityLevel(_obj_, ~frozen~). + 1. Return _obj_. + +
+

JSON.stringify ( _value_ [ , _replacer_ [ , _space_ ] ] )

This function returns a String in UTF-16 encoded JSON format representing an ECMAScript language value, or *undefined*. It can take three parameters. The _value_ parameter is an ECMAScript language value, which is usually an object or array, although it can also be a String, Boolean, Number or *null*. The optional _replacer_ parameter is either a function that alters the way objects and arrays are stringified, or an array of Strings and Numbers that acts as an inclusion list for selecting the object properties that will be stringified. The optional _space_ parameter is a String or Number that allows the result to have white space injected into it to improve human readability.

@@ -47216,6 +47460,8 @@

1. If _state_.[[ReplacerFunction]] is not *undefined*, then 1. Set _value_ to ? Call(_state_.[[ReplacerFunction]], _holder_, « _key_, _value_ »). 1. If _value_ is an Object, then + 1. If _value_ has an [[IsRawJSON]] internal slot, then + 1. Return ! Get(_value_, *"rawJSON"*). 1. If _value_ has a [[NumberData]] internal slot, then 1. Set _value_ to ? ToNumber(_value_). 1. Else if _value_ has a [[StringData]] internal slot, then