Skip to content

Commit

Permalink
make Function.prototype.toString forward-compatible and fully defined
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelficarra committed Dec 15, 2017
1 parent fee2b8e commit 86d35ae
Showing 1 changed file with 54 additions and 22 deletions.
76 changes: 54 additions & 22 deletions spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ <h1>Abstract Operations</h1>

<emu-clause id=sec-algorithm-conventions-syntax-directed-operations namespace=algorithm-conventions>
<h1>Syntax-Directed Operations</h1>
<p>A <dfn>syntax-directed operation</dfn> is a named operation whose definition consists of algorithms, each of which is associated with one or more productions from one of the ECMAScript grammars. A production that has multiple alternative definitions will typically have a distinct algorithm for each alternative. When an algorithm is associated with a grammar production, it may reference the terminal and nonterminal symbols of the production alternative as if they were parameters of the algorithm. When used in this manner, nonterminal symbols refer to the actual alternative definition that is matched when parsing the source text.</p>
<p>A <dfn>syntax-directed operation</dfn> is a named operation whose definition consists of algorithms, each of which is associated with one or more productions from one of the ECMAScript grammars. A production that has multiple alternative definitions will typically have a distinct algorithm for each alternative. When an algorithm is associated with a grammar production, it may reference the terminal and nonterminal symbols of the production alternative as if they were parameters of the algorithm. When used in this manner, nonterminal symbols refer to the actual alternative definition that is matched when parsing the source text. The <dfn>source text matched by</dfn> a grammar production is the portion of the source text that starts at the beginning of the first terminal that participated in the match and ends at the end of the last terminal that participated in the match.</p>
<p>When an algorithm is associated with a production alternative, the alternative is typically shown without any &ldquo;[ ]&rdquo; grammar annotations. Such annotations should only affect the syntactic recognition of the alternative and have no effect on the associated semantics for the alternative.</p>
<p>Syntax-directed operations are invoked with a parse node and, optionally, other parameters by using the conventions on steps 1, 3, and 4 in the following algorithm:</p>
<emu-alg>
Expand Down Expand Up @@ -7259,6 +7259,17 @@ <h1>ECMAScript Function Objects</h1>
If the function uses `super`, this is the object whose [[GetPrototypeOf]] provides the object where `super` property lookups begin.
</td>
</tr>
<tr>
<td>
[[SourceText]]
</td>
<td>
String
</td>
<td>
The <emu-xref href="#sec-source-text">source text</emu-xref> that defines the function.
</td>
</tr>
</tbody>
</table>
</emu-table>
Expand Down Expand Up @@ -7454,10 +7465,11 @@ <h1>AddRestrictedFunctionProperties ( _F_, _realm_ )</h1>
<!-- es6num="9.2.7.1" -->
<emu-clause id="sec-%throwtypeerror%">
<h1>%ThrowTypeError% ( )</h1>
<p>The <dfn>%ThrowTypeError%</dfn> intrinsic is an anonymous built-in function object that is defined once for each realm. When %ThrowTypeError% is called it performs the following steps:</p>
<p>The <dfn>%ThrowTypeError%</dfn> intrinsic is a built-in function object that is defined once for each realm. When %ThrowTypeError% is called it performs the following steps:</p>
<emu-alg>
1. Throw a *TypeError* exception.
</emu-alg>
<p>The value of the `name` property of %ThrowTypeError% is `"ThrowTypeError"`.</p>
<p>The value of the [[Extensible]] internal slot of a %ThrowTypeError% function is *false*.</p>
<p>The `length` property of a %ThrowTypeError% function has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.</p>
</emu-clause>
Expand Down Expand Up @@ -18581,13 +18593,15 @@ <h1>Runtime Semantics: InstantiateFunctionObject</h1>
1. Let _F_ be FunctionCreate(~Normal~, |FormalParameters|, |FunctionBody|, _scope_, _strict_).
1. Perform MakeConstructor(_F_).
1. Perform SetFunctionName(_F_, _name_).
1. Set _F_.[[SourceText]] to the source text matched by |FunctionDeclaration|.
1. Return _F_.
</emu-alg>
<emu-grammar>FunctionDeclaration : `function` `(` FormalParameters `)` `{` FunctionBody `}`</emu-grammar>
<emu-alg>
1. Let _F_ be FunctionCreate(~Normal~, |FormalParameters|, |FunctionBody|, _scope_, *true*).
1. Perform MakeConstructor(_F_).
1. Perform SetFunctionName(_F_, `"default"`).
1. Set _F_.[[SourceText]] to the source text matched by |FunctionDeclaration|.
1. Return _F_.
</emu-alg>
<emu-note>
Expand Down Expand Up @@ -18615,6 +18629,7 @@ <h1>Runtime Semantics: Evaluation</h1>
1. Let _scope_ be the LexicalEnvironment of the running execution context.
1. Let _closure_ be FunctionCreate(~Normal~, |FormalParameters|, |FunctionBody|, _scope_, _strict_).
1. Perform MakeConstructor(_closure_).
1. Set _closure_.[[SourceText]] to the source text matched by |FunctionExpression|.
1. Return _closure_.
</emu-alg>
<emu-grammar>FunctionExpression : `function` BindingIdentifier `(` FormalParameters `)` `{` FunctionBody `}`</emu-grammar>
Expand All @@ -18628,6 +18643,7 @@ <h1>Runtime Semantics: Evaluation</h1>
1. Let _closure_ be FunctionCreate(~Normal~, |FormalParameters|, |FunctionBody|, _funcEnv_, _strict_).
1. Perform MakeConstructor(_closure_).
1. Perform SetFunctionName(_closure_, _name_).
1. Set _closure_.[[SourceText]] to the source text matched by |FunctionExpression|.
1. Perform _envRec_.InitializeBinding(_name_, _closure_).
1. Return _closure_.
</emu-alg>
Expand Down Expand Up @@ -18894,6 +18910,7 @@ <h1>Runtime Semantics: Evaluation</h1>
1. Let _scope_ be the LexicalEnvironment of the running execution context.
1. Let _parameters_ be CoveredFormalsList of |ArrowParameters|.
1. Let _closure_ be FunctionCreate(~Arrow~, _parameters_, |ConciseBody|, _scope_, _strict_).
1. Set _closure_.[[SourceText]] to the source text matched by |ArrowFunction|.
1. Return _closure_.
</emu-alg>
<emu-note>
Expand Down Expand Up @@ -19043,6 +19060,7 @@ <h1>Runtime Semantics: DefineMethod</h1>
1. Let _prototype_ be the intrinsic object %FunctionPrototype%.
1. Let _closure_ be FunctionCreate(_kind_, |UniqueFormalParameters|, |FunctionBody|, _scope_, _strict_, _prototype_).
1. Perform MakeMethod(_closure_, _object_).
1. Set _closure_.[[SourceText]] to the source text matched by |MethodDefinition|.
1. Return the Record{[[Key]]: _propKey_, [[Closure]]: _closure_}.
</emu-alg>
</emu-clause>
Expand Down Expand Up @@ -19070,6 +19088,7 @@ <h1>Runtime Semantics: PropertyDefinitionEvaluation</h1>
1. Let _closure_ be FunctionCreate(~Method~, _formalParameterList_, |FunctionBody|, _scope_, _strict_).
1. Perform MakeMethod(_closure_, _object_).
1. Perform SetFunctionName(_closure_, _propKey_, `"get"`).
1. Set _closure_.[[SourceText]] to the source text matched by |MethodDefinition|.
1. Let _desc_ be the PropertyDescriptor{[[Get]]: _closure_, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}.
1. Return ? DefinePropertyOrThrow(_object_, _propKey_, _desc_).
</emu-alg>
Expand All @@ -19082,6 +19101,7 @@ <h1>Runtime Semantics: PropertyDefinitionEvaluation</h1>
1. Let _closure_ be FunctionCreate(~Method~, |PropertySetParameterList|, |FunctionBody|, _scope_, _strict_).
1. Perform MakeMethod(_closure_, _object_).
1. Perform SetFunctionName(_closure_, _propKey_, `"set"`).
1. Set _closure_.[[SourceText]] to the source text matched by |MethodDefinition|.
1. Let _desc_ be the PropertyDescriptor{[[Set]]: _closure_, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}.
1. Return ? DefinePropertyOrThrow(_object_, _propKey_, _desc_).
</emu-alg>
Expand Down Expand Up @@ -19311,6 +19331,7 @@ <h1>Runtime Semantics: InstantiateFunctionObject</h1>
1. Let _prototype_ be ObjectCreate(%GeneratorPrototype%).
1. Perform DefinePropertyOrThrow(_F_, `"prototype"`, PropertyDescriptor{[[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false*}).
1. Perform SetFunctionName(_F_, _name_).
1. Set _F_.[[SourceText]] to the source text matched by |GeneratorDeclaration|.
1. Return _F_.
</emu-alg>
<emu-grammar>GeneratorDeclaration : `function` `*` `(` FormalParameters `)` `{` GeneratorBody `}`</emu-grammar>
Expand All @@ -19319,6 +19340,7 @@ <h1>Runtime Semantics: InstantiateFunctionObject</h1>
1. Let _prototype_ be ObjectCreate(%GeneratorPrototype%).
1. Perform DefinePropertyOrThrow(_F_, `"prototype"`, PropertyDescriptor{[[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false*}).
1. Perform SetFunctionName(_F_, `"default"`).
1. Set _F_.[[SourceText]] to the source text matched by |GeneratorDeclaration|.
1. Return _F_.
</emu-alg>
<emu-note>
Expand All @@ -19342,6 +19364,7 @@ <h1>Runtime Semantics: PropertyDefinitionEvaluation</h1>
1. Let _prototype_ be ObjectCreate(%GeneratorPrototype%).
1. Perform DefinePropertyOrThrow(_closure_, `"prototype"`, PropertyDescriptor{[[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false*}).
1. Perform SetFunctionName(_closure_, _propKey_).
1. Set _closure_.[[SourceText]] to the source text matched by |GeneratorMethod|.
1. Let _desc_ be the PropertyDescriptor{[[Value]]: _closure_, [[Writable]]: *true*, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}.
1. Return ? DefinePropertyOrThrow(_object_, _propKey_, _desc_).
</emu-alg>
Expand All @@ -19357,6 +19380,7 @@ <h1>Runtime Semantics: Evaluation</h1>
1. Let _closure_ be GeneratorFunctionCreate(~Normal~, |FormalParameters|, |GeneratorBody|, _scope_, _strict_).
1. Let _prototype_ be ObjectCreate(%GeneratorPrototype%).
1. Perform DefinePropertyOrThrow(_closure_, `"prototype"`, PropertyDescriptor{[[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false*}).
1. Set _closure_.[[SourceText]] to the source text matched by |GeneratorExpression|.
1. Return _closure_.
</emu-alg>
<emu-grammar>GeneratorExpression : `function` `*` BindingIdentifier `(` FormalParameters `)` `{` GeneratorBody `}`</emu-grammar>
Expand All @@ -19372,6 +19396,7 @@ <h1>Runtime Semantics: Evaluation</h1>
1. Perform DefinePropertyOrThrow(_closure_, `"prototype"`, PropertyDescriptor{[[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false*}).
1. Perform SetFunctionName(_closure_, _name_).
1. Perform _envRec_.InitializeBinding(_name_, _closure_).
1. Set _closure_.[[SourceText]] to the source text matched by |GeneratorExpression|.
1. Return _closure_.
</emu-alg>
<emu-note>
Expand Down Expand Up @@ -19764,13 +19789,16 @@ <h1>Runtime Semantics: BindingClassDeclarationEvaluation</h1>
1. ReturnIfAbrupt(_value_).
1. Let _hasNameProperty_ be ? HasOwnProperty(_value_, `"name"`).
1. If _hasNameProperty_ is *false*, perform SetFunctionName(_value_, _className_).
1. Set _value_.[[SourceText]] to the source text matched by |ClassDeclaration|.
1. Let _env_ be the running execution context's LexicalEnvironment.
1. Perform ? InitializeBoundName(_className_, _value_, _env_).
1. Return _value_.
</emu-alg>
<emu-grammar>ClassDeclaration : `class` ClassTail</emu-grammar>
<emu-alg>
1. Return the result of ClassDefinitionEvaluation of |ClassTail| with argument *undefined*.
1. Let _value_ be the result of ClassDefinitionEvaluation of |ClassTail| with argument *undefined*.
1. Set _value_.[[SourceText]] to the source text matched by |ClassDeclaration|.
1. Return _value_.
</emu-alg>
<emu-note>
<p><emu-grammar>ClassDeclaration : `class` ClassTail</emu-grammar> only occurs as part of an |ExportDeclaration| and the setting of a name property and establishing its binding are handled as part of the evaluation action for that production. See <emu-xref href="#sec-exports-runtime-semantics-evaluation"></emu-xref>.</p>
Expand Down Expand Up @@ -19798,6 +19826,7 @@ <h1>Runtime Semantics: Evaluation</h1>
1. Let _hasNameProperty_ be ? HasOwnProperty(_value_, `"name"`).
1. If _hasNameProperty_ is *false*, then
1. Perform SetFunctionName(_value_, _className_).
1. Set _value_.[[SourceText]] to the source text matched by |ClassExpression|.
1. Return NormalCompletion(_value_).
</emu-alg>
<emu-note>
Expand Down Expand Up @@ -24607,11 +24636,25 @@ <h1>Runtime Semantics: CreateDynamicFunction( _constructor_, _newTarget_, _kind_
1. Else if _kind_ is `"normal"`, perform MakeConstructor(_F_).
1. NOTE: Async functions are not constructable and do not have a [[Construct]] internal method or a `"prototype"` property.
1. Perform SetFunctionName(_F_, `"anonymous"`).
1. Let _prefix_ be the prefix associated with _kind_ in <emu-xref href="#table-dynamic-function-sourcetext-prefixes"></emu-xref>.
1. Let _sourceText_ be the String value whose elements are, in order, the code units of _prefix_, the code units of `" anonymous("`, the code units of _P_, 0x000A (LINE FEED), the code units of `") {"`, 0x000A (LINE FEED), the code units of _bodyText_, 0x000A (LINE FEED), and the code units of `"}"`.
1. Set _F_.[[SourceText]] to _sourceText_.
1. Return _F_.
</emu-alg>
<emu-note>
<p>A `prototype` property is created for every non-async function created using CreateDynamicFunction to provide for the possibility that the function will be used as a constructor.</p>
</emu-note>

<emu-table id="table-dynamic-function-sourcetext-prefixes" caption="Dynamic Function SourceText Prefixes">
<table>
<tbody>
<tr><th>Kind</th><th>Prefix</th></tr>
<tr><td>`"normal"`</td><td>`"function"`</td></tr>
<tr><td>`"generator"`</td><td>`"function*"`</td></tr>
<tr><td>`"async"`</td><td>`"async function"`</td></tr>
</tbody>
</table>
</emu-table>
</emu-clause>
</emu-clause>
</emu-clause>
Expand Down Expand Up @@ -24731,27 +24774,16 @@ <h1>Function.prototype.constructor</h1>
<h1>Function.prototype.toString ( )</h1>
<p>When the `toString` method is called on an object _func_, the following steps are taken:</p>
<emu-alg>
1. If _func_ is a Bound Function exotic object, then
1. Return an implementation-dependent String source code representation of _func_. The representation must conform to the rules below. It is implementation-dependent whether the representation includes bound function information or information about the target function.
1. If Type(_func_) is Object and is either a built-in function object or has an [[ECMAScriptCode]] internal slot, then
1. Return an implementation-dependent String source code representation of _func_. The representation must conform to the rules below.
1. If _func_ is a <emu-xref href="#sec-bound-function-exotic-objects">Bound Function exotic object</emu-xref> or a <emu-xref href="#sec-ecmascript-standard-built-in-objects">built-in Function object</emu-xref>, then return an implementation-dependent String source code representation of _func_. The representation must have the syntax of a |NativeFunction|. Additionally, if _func_ is a <emu-xref href="#sec-well-known-intrinsic-objects">Well-known Intrinsic Object</emu-xref>, the portion of the returned String that would be matched by |IdentifierName| must be the initial value of the *name* property of _func_.
1. If _func_ has a [[SourceText]] internal slot and Type(_func_.[[SourceText]]) is String, then return _func_.[[SourceText]].
1. If Type(_func_) is Object and IsCallable(_func_) is *true*, then return an implementation-dependent String source code representation of _func_. The representation must have the syntax of a |NativeFunction|.
1. Throw a *TypeError* exception.
</emu-alg>
<p>`toString` Representation Requirements:</p>
<ul>
<li>
The string representation must have the syntax of a |FunctionDeclaration|, |FunctionExpression|, |GeneratorDeclaration|, |GeneratorExpression|, |AsyncFunctionDeclaration|, |AsyncFunctionExpression|, |ClassDeclaration|, |ClassExpression|, |ArrowFunction|, |AsyncArrowFunction|, or |MethodDefinition| depending upon the actual characteristics of the object.
</li>
<li>
The use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent.
</li>
<li>
If the object was defined using ECMAScript code and the returned string representation is not in the form of a |MethodDefinition| or |GeneratorMethod| then the representation must be such that if the string is evaluated, using `eval` in a lexical context that is equivalent to the lexical context used to create the original object, it will result in a new functionally equivalent object. In that case the returned source code must not mention freely any variables that were not mentioned freely by the original function's source code, even if these &ldquo;extra&rdquo; names were originally in scope.
</li>
<li>
If the implementation cannot produce a source code string that meets these criteria then it must return a string for which `eval` will throw a *SyntaxError* exception.
</li>
</ul>

<emu-grammar>
NativeFunction :
`function` IdentifierName? `(` FormalParameters `)` `{` `[` `native` `code` `]` `}`
</emu-grammar>
</emu-clause>

<!-- es6num="19.2.3.6" -->
Expand Down

0 comments on commit 86d35ae

Please sign in to comment.