Skip to content

Commit

Permalink
As of tc39/ecma262#3222 the signature of HostEnsureCanCompileStrings …
Browse files Browse the repository at this point in the history
…changed. This updates the spec to better reflect the current state.
  • Loading branch information
lukewarlow committed Feb 20, 2024
1 parent 0e3b124 commit 2f7bfc8
Showing 1 changed file with 116 additions and 57 deletions.
173 changes: 116 additions & 57 deletions spec.emu
Original file line number Diff line number Diff line change
Expand Up @@ -23,83 +23,142 @@ contributors: Krzysztof Kotowicz, Mike Samuel
</emu-note>
</emu-clause>

<emu-clause id="sec-hostvalidatedynamiccode" aoid="HostValidateDynamicCode">
<h1><del>HostEnsureCanCompileStrings</del> <ins>HostValidateDynamicCode</ins> ( _callerRealm_, _calleeRealm_<ins>, _codeString_, _wasCodeLike_, _compilationSink_</ins>)</h1>
<p><del>HostEnsureCanCompileStrings</del> <ins>HostValidateDynamicCode</ins> is a host-defined abstract operation that <ins>takes arguments _callerRealm_ (a Realm), _calleeRealm_ (a Realm), _codeString_ (a string), _wasCodeLike_ (a boolean), and _compilationSink_ (*"Function"* or *"eval"*) and </ins>allows host environments to <del>block</del><ins>guard</ins> certain ECMAScript functions which allow developers to compile strings into ECMAScript code. </p>
<p>An implementation of <del>HostEnsureCanCompileStrings</del> <ins>HostValidateDynamicCode</ins> may complete normally or abruptly. <ins>Any normal completion must return a String.</ins> Any abrupt completions will be propagated to its callers. The default implementation of <del>HostEnsureCanCompileStrings</del><ins>HostValidateDynamicCode</ins> is to unconditionally return a <del>empty normal completion</del><ins>NormalCompletion(_codeString_)</ins>.</p>
<emu-clause id="sec-hostvalidatedynamiccode" aoid="HostValidateDynamicCode" type="host-defined abstract operation">
<h1>
<del>HostEnsureCanCompileStrings</del> <ins>HostValidateDynamicCode</ins> (
_calleeRealm_: a Realm Record,
_parameterStrings_: a List of Strings,
_bodyString_: a String,
_direct_: a Boolean,
<ins>_wasCodeLike_ (a boolean),</ins>
<ins>_compilationSink_ (*"Function"* or *"eval"*)</ins>
): either a normal completion containing ~unused~ or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It allows host environments to block certain ECMAScript functions which allow developers to interpret and evaluate strings as ECMAScript code.</dd>
</dl>
<p>
_parameterStrings_ represents the strings that, when using one of the function constructors, will be concatenated together to build the parameters list. _bodyString_ represents the function body or the string passed to an `eval` call.
_direct_ signifies whether the evaluation is a direct eval. _wasCodeLike_ is a boolean that indicates whether the code was constructed from code-like objects. _compilationSink_ is a string that indicates the type of the compilation sink, either *"Function"* or *"eval"*.
</p>
<p>The default implementation of <del>HostEnsureCanCompileStrings</del><ins>HostValidateDynamicCode</ins> is to return NormalCompletion(~unused~).</p>
</emu-clause>


<emu-clause id="sec-performeval" aoid="PerformEval">
<h1>Runtime Semantics: PerformEval ( _x_, _callerRealm_, _strictCaller_, _direct_ )</h1>
<p>The abstract operation PerformEval with arguments _x_, _callerRealm_, _strictCaller_, and _direct_ performs the following steps:</p>
<emu-alg>
1. Assert: If _direct_ is *false*, then _strictCaller_ is also *false*.
1. <ins>Let _isCodeLike_ be ! IsCodeLike(_x_).</ins>
1. <ins>If _isCodeLike_ is *true*, set _x_ to _x_.[[HostDefinedCodeLike]].</ins>
1. If Type(_x_) is not String, return _x_.
1. Let _evalRealm_ be the current Realm Record.
1. <del>Perform ? HostEnsureCanCompileStrings(_callerRealm_, _calleeRealm_).</del><br>
<ins>Set _x_ to be ? HostValidateDynamicCode(_callerRealm_, _calleeRealm_, _x_, _isCodeLike_, *"eval"*).</ins>
1. ...
</emu-alg>
<emu-clause id="sec-performeval" type="abstract operation" oldids="sec-performeval-rules-outside-functions,sec-performeval-rules-outside-methods,sec-performeval-rules-outside-constructors">
<h1>
PerformEval (
_x_: an ECMAScript language value,
_strictCaller_: a Boolean,
_direct_: a Boolean,
): either a normal completion containing an ECMAScript language value or a throw completion
</h1>
<dl class="header">
</dl>
<emu-alg>
1. Assert: If _direct_ is *false*, then _strictCaller_ is also *false*.
1. <ins>Let _isCodeLike_ be ! IsCodeLike(_x_).</ins>
1. <ins>If _isCodeLike_ is *true*, set _x_ to _x_.[[HostDefinedCodeLike]].</ins>
1. If _x_ is not a String, return _x_.
1. Let _evalRealm_ be the current Realm Record.
1. NOTE: In the case of a direct eval, _evalRealm_ is the realm of both the caller of `eval` and of the `eval` function itself.
1. <del>Perform ? HostEnsureCanCompileStrings(_evalRealm_, « », _x_, _direct_).</del><br>
<ins>Set _x_ to be ? HostValidateDynamicCode(_callerRealm_, _calleeRealm_, _x_, _isCodeLike_, *"eval"*).</ins>
1. ...
</emu-alg>
</emu-clause>


<emu-clause id="sec-createdynamicfunction" aoid="CreateDynamicFunction">
<h1>CreateDynamicFunction ( _constructor_, _newTarget_, _kind_, _args_ )</h1>
<p>The abstract operation CreateDynamicFunction takes arguments _constructor_ (a constructor), _newTarget_ (a constructor), _kind_ (either ~normal~, ~generator~, ~async~, or ~asyncGenerator~), and _args_ (a List of ECMAScript language values). _constructor_ is the constructor function that is performing this action. _newTarget_ is the constructor that `new` was initially applied to. _args_ is the argument values that were passed to _constructor_. It performs the following steps when called:</p>
<emu-clause id="sec-createdynamicfunction" type="abstract operation" oldids="table-dynamic-function-sourcetext-prefixes">
<h1>
CreateDynamicFunction (
_constructor_: a constructor,
_newTarget_: a constructor,
_kind_: ~normal~, ~generator~, ~async~, or ~async-generator~,
_parameterArgs_: a List of ECMAScript language values,
_bodyArg_: an ECMAScript language value,
): either a normal completion containing an ECMAScript function object or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>_constructor_ is the constructor function that is performing this action. _newTarget_ is the constructor that `new` was initially applied to. _parameterArgs_ and _bodyArg_ reflect the argument values that were passed to _constructor_.</dd>
</dl>
<emu-alg>
1. Assert: The execution context stack has at least two elements.
1. Let _callerContext_ be the second to top element of the execution context stack.
1. Let _callerRealm_ be _callerContext_'s Realm.
1. Let _calleeRealm_ be the current Realm Record.
1. <del>Perform ? HostEnsureCanCompileStrings(_callerRealm_, _calleeRealm_).</del>
1. If _newTarget_ is *undefined*, set _newTarget_ to _constructor_.
1. If _kind_ is ~normal~, then
1. Let _goal_ be the grammar symbol |FunctionBody[~Yield, ~Await]|.
1. Let _parameterGoal_ be the grammar symbol |FormalParameters[~Yield, ~Await]|.
1. Let _prefix_ be *"function"*.
1. Let _exprSym_ be the grammar symbol |FunctionExpression|.
1. Let _bodySym_ be the grammar symbol |FunctionBody[~Yield, ~Await]|.
1. Let _parameterSym_ be the grammar symbol |FormalParameters[~Yield, ~Await]|.
1. Let _fallbackProto_ be *"%Function.prototype%"*.
1. Else if _kind_ is ~generator~, then
1. Let _goal_ be the grammar symbol |GeneratorBody|.
1. Let _parameterGoal_ be the grammar symbol |FormalParameters[+Yield, ~Await]|.
1. Let _prefix_ be *"function\*"*.
1. Let _exprSym_ be the grammar symbol |GeneratorExpression|.
1. Let _bodySym_ be the grammar symbol |GeneratorBody|.
1. Let _parameterSym_ be the grammar symbol |FormalParameters[+Yield, ~Await]|.
1. Let _fallbackProto_ be *"%GeneratorFunction.prototype%"*.
1. Else if _kind_ is ~async~, then
1. Let _goal_ be the grammar symbol |AsyncFunctionBody|.
1. Let _parameterGoal_ be the grammar symbol |FormalParameters[~Yield, +Await]|.
1. Let _prefix_ be *"async function"*.
1. Let _exprSym_ be the grammar symbol |AsyncFunctionExpression|.
1. Let _bodySym_ be the grammar symbol |AsyncFunctionBody|.
1. Let _parameterSym_ be the grammar symbol |FormalParameters[~Yield, +Await]|.
1. Let _fallbackProto_ be *"%AsyncFunction.prototype%"*.
1. Else,
1. Assert: _kind_ is ~asyncGenerator~.
1. Let _goal_ be the grammar symbol |AsyncGeneratorBody|.
1. Let _parameterGoal_ be the grammar symbol |FormalParameters[+Yield, +Await]|.
1. Assert: _kind_ is ~async-generator~.
1. Let _prefix_ be *"async function\*"*.
1. Let _exprSym_ be the grammar symbol |AsyncGeneratorExpression|.
1. Let _bodySym_ be the grammar symbol |AsyncGeneratorBody|.
1. Let _parameterSym_ be the grammar symbol |FormalParameters[+Yield, +Await]|.
1. Let _fallbackProto_ be *"%AsyncGeneratorFunction.prototype%"*.
1. Let _argCount_ be the number of elements in _args_.
1. Let _P_ be the empty String.
1. Let _argCount_ be the number of elements in _parameterArgs_.
1. <ins>Let _assembledFromCodeLike_ be *true*.</ins>
1. If _argCount_ = 0, let _bodyArg_ be the empty String.
1. Else if _argCount_ = 1, <del>let _bodyArg_ be _args_[0]</del>.
1. <ins>Let _bodyArg_ be _args_[0].</ins>
1. <ins>If IsCodeLike(_bodyArg_) is *true*, set _bodyArg_ to _bodyArg_.[[HostDefinedCodeLike]]. Otherwise, set _assembledFromCodeLike_ to *false*.</ins>
1. Else,
1. Assert: _argCount_ &gt; 1.
1. Let _firstArg_ be _args_[0].
1. <ins>If IsCodeLike(_firstArg_) is *true*, set _firstArg_ to _firstArg_.[[HostDefinedCodeLike]]. Otherwise, set _assembledFromCodeLike_ to *false*.</ins>
1. Set _P_ to ? ToString(_firstArg_).
1. <ins>If IsCodeLike(_bodyArg_) is *true*, set _bodyArg_ to _bodyArg_.[[HostDefinedCodeLike]]. Otherwise, set _assembledFromCodeLike_ to *false*.</ins>
1. Let _bodyString_ be ? ToString(_bodyArg_).
1. Let _parameterStrings_ be a new empty List.
1. For each element _arg_ of _parameterArgs_, do
1. <ins>If IsCodeLike(_arg_) is *true*, set _arg_ to _arg_.[[HostDefinedCodeLike]]. Otherwise, set _assembledFromCodeLike_ to *false*.</ins>
1. Append ? ToString(_arg_) to _parameterStrings_.
1. Let _currentRealm_ be the current Realm Record.
// TODO: HostValidateDynamicCode needs to be changed to handle the new model where body and parameter strings are separated.
1. <ins>Let _sourceString_ be</ins><del>Perform</del> ? <del>HostEnsureCanCompileStrings</del><ins>HostValidateDynamicCode</ins>(_currentRealm_, _parameterStrings_, _bodyString_, *false*<ins>, _assembledFromCodeLike_, *"Function"*</ins>).
1. Let _P_ be the empty String.
1. If _argCount_ > 0, then
1. Set _P_ to _parameterStrings_[0].
1. Let _k_ be 1.
1. Repeat, while _k_ &lt; _argCount_ - 1,
1. Let _nextArg_ be _args_[_k_].
1. <ins>If IsCodeLike(_nextArg_) is *true*, set _nextArg_ to _nextArg_.[[HostDefinedCodeLike]]. Otherwise, set _assembledFromCodeLike_ to *false*.</ins>
1. Let _nextArgString_ be ? ToString(_nextArg_).
1. Repeat, while _k_ &lt; _argCount_,
1. Let _nextArgString_ be _parameterStrings_[_k_].
1. Set _P_ to the string-concatenation of _P_, *","* (a comma), and _nextArgString_.
1. Set _k_ to _k_ + 1.
1. Let _bodyArg_ be _args_[_k_].
1. <ins>If IsCodeLike(_bodyArg_) is *true*, set _bodyArg_ to _bodyArg_.[[HostDefinedCodeLike]]. Otherwise, set _assembledFromCodeLike_ to *false*.</ins>
1. Let _bodyString_ be the string-concatenation of 0x000A (LINE FEED), ? ToString(_bodyArg_), and 0x000A (LINE FEED).
1. Let _prefix_ be the prefix associated with _kind_ in <emu-xref href="#table-dynamic-function-sourcetext-prefixes"></emu-xref>.
1. Let _sourceString_ be the string-concatenation of _prefix_, *" anonymous("*, _P_, 0x000A (LINE FEED), *") {"*, _bodyString_, and *"}"*.
1. <ins>Set _sourceString_ to be ? HostValidateDynamicCode(_callerRealm_, _calleeRealm_, _sourceString_, _assembledFromCodeLike_, *"Function"*). </ins>
1. ...
1. Let _bodyParseString_ be the string-concatenation of 0x000A (LINE FEED), _bodyString_, and 0x000A (LINE FEED).
1. Let _sourceString_ be the string-concatenation of _prefix_, *" anonymous("*, _P_, 0x000A (LINE FEED), *") {"*, _bodyParseString_, and *"}"*.
1. Let _sourceText_ be StringToCodePoints(_sourceString_).
1. Let _parameters_ be ParseText(StringToCodePoints(_P_), _parameterSym_).
1. If _parameters_ is a List of errors, throw a *SyntaxError* exception.
1. Let _body_ be ParseText(StringToCodePoints(_bodyParseString_), _bodySym_).
1. If _body_ is a List of errors, throw a *SyntaxError* exception.
1. NOTE: The parameters and body are parsed separately to ensure that each is valid alone. For example, `new Function("/*", "*/ ) {")` does not evaluate to a function.
1. NOTE: If this step is reached, _sourceText_ must have the syntax of _exprSym_ (although the reverse implication does not hold). The purpose of the next two steps is to enforce any Early Error rules which apply to _exprSym_ directly.
1. Let _expr_ be ParseText(_sourceText_, _exprSym_).
1. If _expr_ is a List of errors, throw a *SyntaxError* exception.
1. Let _proto_ be ? GetPrototypeFromConstructor(_newTarget_, _fallbackProto_).
1. Let _env_ be _currentRealm_.[[GlobalEnv]].
1. Let _privateEnv_ be *null*.
1. Let _F_ be OrdinaryFunctionCreate(_proto_, _sourceText_, _parameters_, _body_, ~non-lexical-this~, _env_, _privateEnv_).
1. Perform SetFunctionName(_F_, *"anonymous"*).
1. If _kind_ is ~generator~, then
1. Let _prototype_ be OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
1. Perform ! DefinePropertyOrThrow(_F_, *"prototype"*, PropertyDescriptor { [[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false* }).
1. Else if _kind_ is ~async-generator~, then
1. Let _prototype_ be OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).
1. Perform ! DefinePropertyOrThrow(_F_, *"prototype"*, PropertyDescriptor { [[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false* }).
1. Else if _kind_ is ~normal~, then
1. Perform MakeConstructor(_F_).
1. NOTE: Functions whose _kind_ is ~async~ are not constructible and do not have a [[Construct]] internal method or a *"prototype"* property.
1. Return _F_.
</emu-alg>
<emu-note>
<p>CreateDynamicFunction defines a *"prototype"* property on any function it creates whose _kind_ is not ~async~ to provide for the possibility that the function will be used as a constructor.</p>
</emu-note>
</emu-clause>

<emu-annex id="sec-host-layering-points">
Expand Down

0 comments on commit 2f7bfc8

Please sign in to comment.