-
Notifications
You must be signed in to change notification settings - Fork 24
Give lazy functions ability to assert list of inner functions. #69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
syg
wants to merge
3
commits into
tc39:spec-draft
Choose a base branch
from
syg:linkable-inner-funcs
base: spec-draft
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,14 @@ <h1>Tree Grammar</h1> | |
<p>This section is derived from <a href="https://github.com/shapesecurity/shift-spec/blob/es2017/spec.idl">Shift AST Spec</a> and parts are Copyright 2014-2017 Shape Security, Inc.</p> | ||
<p>Unlike the Shift AST spec, interface types are not used to inherit fields to control over ordering of fields. Type hierarchies that are not used to discriminate are collapsed to make space costs simple. Nor are they used to discriminate types, for which explicitly discriminated unions types are used.</p> | ||
<emu-note>Whereas Shift AST's design principle is ease of search-and-replace of node types, binary AST's design principle is ease of verification and ease of associating different behaviors with syntactically different (but possibly lexically similar) productions.</emu-note> | ||
<p>The grammar is presented in WebIDL with the `[TypeIndicator]` and `[NonEmpty]` extensions per Shift AST spec. The `[Lazy]` extension serves as a hint to the surface encoding that the `[Lazy]` attribute should be skippable in the byte stream in constant time. The `typedefs` of `or` types are to be read as recursive sum types. In text below, the "is a `Foo`" prose is shorthand for checking the node's `type` attribute being equal to `"Foo"`.</p> | ||
<p>The grammar is presented in WebIDL with the `[TypeIndicator]` and `[NonEmpty]` extensions per Shift AST spec, as well as the listed extensions below. </p> | ||
<ul> | ||
<li>The `[Lazy]` extension serves as a hint to the surface encoding that the `[Lazy]` attribute must be skippable in the byte stream in constant time.</li> | ||
<li>The `[Linkable]` extension serves as a hint to the surface encoding that the `[Linkable]` attribute must be random accessible in the byte stream in constant time.</li> | ||
<li>The `NodeLink` type corresponds to the set of opaque values interpretable by the surface encoding to seek to attributes that have the `[Linkable]` extension.</li> | ||
<li>The `typedefs` of `or` types are to be read as recursive sum types.</li> | ||
<li>The prose "is a `Foo`" is shorthand for checking the node's `type` attribute being equal to `"Foo"`.</li> | ||
</ul> | ||
|
||
<pre><code class="language-webidl"> | ||
// Type aliases and enums. | ||
|
@@ -193,6 +200,7 @@ <h1>Tree Grammar</h1> | |
EmptyStatement or | ||
ExpressionStatement or | ||
FunctionDeclaration or | ||
LinkableFunctionDeclaration or | ||
IfStatement or | ||
IterationStatement or | ||
LabelledStatement or | ||
|
@@ -217,6 +225,7 @@ <h1>Tree Grammar</h1> | |
LiteralRegExpExpression or | ||
ArrayExpression or | ||
ArrowExpression or | ||
LinkableArrowExpression or | ||
AssignmentExpression or | ||
BinaryExpression or | ||
CallExpression or | ||
|
@@ -225,6 +234,7 @@ <h1>Tree Grammar</h1> | |
ConditionalExpression or | ||
ClassExpression or | ||
FunctionExpression or | ||
LinkableFunctionExpression or | ||
IdentifierExpression or | ||
NewExpression or | ||
NewTargetExpression or | ||
|
@@ -243,7 +253,12 @@ <h1>Tree Grammar</h1> | |
LiteralPropertyName) | ||
PropertyName; | ||
|
||
typedef (Method or Getter or Setter) MethodDefinition; | ||
typedef (Method or | ||
Getter or | ||
Setter or | ||
LinkableMethod or | ||
LinkableGetter or | ||
LinkableSetter) MethodDefinition; | ||
|
||
typedef (MethodDefinition or | ||
DataProperty or | ||
|
@@ -462,14 +477,20 @@ <h1>Tree Grammar</h1> | |
|
||
// `export VariableStatement`, `export Declaration` | ||
interface Export : Node { | ||
attribute (FunctionDeclaration or ClassDeclaration or VariableDeclaration) declaration; | ||
attribute (FunctionDeclaration or | ||
LinkableFunctionDeclaration or | ||
ClassDeclaration or | ||
VariableDeclaration) declaration; | ||
}; | ||
|
||
// `export default HoistableDeclaration`, | ||
// `export default ClassDeclaration`, | ||
// `export default AssignmentExpression` | ||
interface ExportDefault : Node { | ||
attribute (FunctionDeclaration or ClassDeclaration or Expression) body; | ||
attribute (FunctionDeclaration or | ||
LinkableFunctionDeclaration or | ||
ClassDeclaration or | ||
Expression) body; | ||
}; | ||
|
||
// `ExportSpecifier`, as part of an `ExportFrom`. | ||
|
@@ -513,8 +534,12 @@ <h1>Tree Grammar</h1> | |
// `length` property of this method. | ||
attribute unsigned long length; | ||
attribute FrozenArray<Directive> directives; | ||
attribute FrozenArray<NodeLink> innerLazyFunctions; | ||
[Lazy] attribute FunctionOrMethodContents contents; | ||
}; | ||
interface LinkableMethod : Node { | ||
[Linkable] attribute Method method; | ||
}; | ||
|
||
// `get PropertyName ( ) { FunctionBody }` | ||
interface EagerGetter : Node { | ||
|
@@ -525,8 +550,12 @@ <h1>Tree Grammar</h1> | |
interface LazyGetter : Node { | ||
attribute PropertyName name; | ||
attribute FrozenArray<Directive> directives; | ||
attribute FrozenArray<NodeLink> innerLazyFunctions; | ||
[Lazy] attribute GetterContents contents; | ||
}; | ||
interface LinkableGetter : Node { | ||
[Linkable] Getter getter; | ||
}; | ||
|
||
interface GetterContents : Node { | ||
attribute boolean isThisCaptured; | ||
|
@@ -547,8 +576,12 @@ <h1>Tree Grammar</h1> | |
// `length` property of this setter function. | ||
attribute unsigned long length; | ||
attribute FrozenArray<Directive> directives; | ||
attribute FrozenArray<NodeLink> innerLazyFunctions; | ||
[Lazy] attribute SetterContents contents; | ||
}; | ||
interface LinkableSetter : Node { | ||
[Linkable] attribute Setter setter; | ||
}; | ||
|
||
interface SetterContents : Node { | ||
attribute boolean isThisCaptured; | ||
|
@@ -635,6 +668,7 @@ <h1>Tree Grammar</h1> | |
// `length` property of this arrow function. | ||
attribute unsigned long length; | ||
attribute FrozenArray<Directive> directives; | ||
attribute FrozenArray<NodeLink> innerLazyFunctions; | ||
[Lazy] attribute ArrowExpressionContentsWithFunctionBody contents; | ||
}; | ||
interface EagerArrowExpressionWithExpression : Node { | ||
|
@@ -649,8 +683,12 @@ <h1>Tree Grammar</h1> | |
attribute boolean isAsync; | ||
// `length` property of this arrow function. | ||
attribute unsigned long length; | ||
attribute FrozenArray<NodeLink> innerLazyFunctions; | ||
[Lazy] attribute ArrowExpressionContentsWithExpression contents; | ||
}; | ||
interface LinkableArrowExpression : Node { | ||
[Linkable] attribute ArrowExpression arrow; | ||
}; | ||
|
||
interface ArrowExpressionContentsWithFunctionBody : Node { | ||
attribute AssertedParameterScope parameterScope; | ||
|
@@ -743,8 +781,12 @@ <h1>Tree Grammar</h1> | |
// `length` property of this function. | ||
attribute unsigned long length; | ||
attribute FrozenArray<Directive> directives; | ||
attribute FrozenArray<NodeLink> innerLazyFunctions; | ||
[Lazy] attribute FunctionExpressionContents contents; | ||
}; | ||
interface LinkableFunctionExpression : Node { | ||
[Linkable] attribute FunctionExpression fun; | ||
}; | ||
|
||
interface FunctionExpressionContents : Node { | ||
attribute boolean isFunctionNameCaptured; | ||
|
@@ -1000,16 +1042,19 @@ <h1>Tree Grammar</h1> | |
attribute FrozenArray<Directive> directives; | ||
attribute FunctionOrMethodContents contents; | ||
}; | ||
|
||
interface LazyFunctionDeclaration : Node { | ||
attribute boolean isAsync; | ||
attribute boolean isGenerator; | ||
attribute BindingIdentifier name; | ||
// `length` property of this function. | ||
attribute unsigned long length; | ||
attribute FrozenArray<Directive> directives; | ||
attribute FrozenArray<NodeLink> innerLazyFunctions; | ||
[Lazy] attribute FunctionOrMethodContents contents; | ||
}; | ||
interface LinkableFunctionDeclaration : Node { | ||
[Linkable] attribute FunctionDeclaration fun; | ||
} | ||
|
||
interface FunctionOrMethodContents : Node { | ||
attribute boolean isThisCaptured; | ||
|
@@ -1096,7 +1141,7 @@ <h1>StatementListEcmaify ( _stmts_ )</h1> | |
1. Let _emptyStmt_ be |StatementListItem| : |EmptyStatement|. | ||
1. Set _list_ to |StatementList| : _emptyStmt_. | ||
1. For each _stmt_ in _stmts_, do | ||
1. If _stmt_ is a `FunctionDeclaration`, then | ||
1. If _stmt_ is a `FunctionDeclaration` or a `LinkableFunctionDeclaration`, then | ||
1. Set _n_ to |HoistableDeclaration|: ? Ecmaify(_stmt_). | ||
1. Set _n_ to be |Declaration| : _n_. | ||
1. Else if _stmt_ an `ExpressionStatement` and _stmt_`.expression` is a `LiteralStringExpression`: | ||
|
@@ -1307,7 +1352,7 @@ <h1>PrimaryExpressionEcmaify ( _e_ )</h1> | |
<emu-alg> | ||
1. Assert: _e_ is an `Expression`, an `AssignmentTarget`, or an `AssignmentTargetWithInitializer`. | ||
1. If _e_ is a `ThisExpression`, then return ? Ecmaify(_e_). | ||
1. Else if _pn_ is an `IdentifierExpression`, a `Literal`, an `ArrayExpression`, an `ObjectExpression`, a `FunctionExpression`, a `ClassExpression`, a `LiteralRegExpExpression`, a `TemplateExpression`, an `AssignmentTargetIdentifier`, an `ArrayAssignmentExpression`, or an `ObjectAssignmentExpression`, then return |PrimaryExpression| : ? Ecmaify(_e_). | ||
1. Else if _pn_ is an `IdentifierExpression`, a `Literal`, an `ArrayExpression`, an `ObjectExpression`, a `FunctionExpression`, a `LinkableFunctionExpression`, a `ClassExpression`, a `LiteralRegExpExpression`, a `TemplateExpression`, an `AssignmentTargetIdentifier`, an `ArrayAssignmentExpression`, or an `ObjectAssignmentExpression`, then return |PrimaryExpression| : ? Ecmaify(_e_). | ||
1. Else, | ||
1. Let _parenthesized_ be |ParenthesizedExpression| : <emu-t>(</emu-t> ? ExpressionEcmaify(_e_) <emu-t>)</emu-t>. | ||
1. Return |PrimaryExpression| : _parenthesized_. | ||
|
@@ -1501,7 +1546,7 @@ <h1>AssignmentExpressionEcmaify ( _e_ )</h1> | |
<emu-alg> | ||
1. Assert: _e_ is an `Expression`, an `AssignmentTarget`, or an `AssignmentTargetWithInitializer`. | ||
1. If _e_ is an `AssignmentExpression`, a `CompoundAssignmentExpression`, or an `AssignmentTargetWithInitializer`, then return ? Ecmaify(_e_). | ||
1. Else if _e_ is a `YieldExpression` or an `ArrowExpression`, then return |AssignmentExpression| : ? Ecmaify(_e_). | ||
1. Else if _e_ is a `YieldExpression`, an `ArrowExpression`, or a `LinkableArrowExpression`, then return |AssignmentExpression| : ? Ecmaify(_e_). | ||
1. Else, | ||
1. Let _n_ be ? ConditionalExpressionEcmaify(_e_). | ||
1. Return |AssignmentExpression| : _n_. | ||
|
@@ -2004,8 +2049,10 @@ <h1>EcmaifyLabelledStatement ( _labelled_ )</h1> | |
<emu-alg> | ||
1. Assert _labelled_ is a `LabelledStatement`. | ||
1. Let _body_ be an empty Parse Node. | ||
1. If _labelled_`.body` is a `FunctionDeclaration`, then | ||
1. If _labelled_`.body.isAsync` is true or _labelled_`.body.isGenerator` is *true*, then throw a *SyntaxError* exception. | ||
1. If _labelled_`.body` is a `FunctionDeclaration` or a `LinkableFunctionDeclaration`, then | ||
1. Let _funNode_ be _labelled_`.body`. | ||
1. If _funNode_ is a `LinkableFunctionDeclaration`, then set _funNode_ to _funNode_`.fun`. | ||
1. If _funNode_`.isAsync` is true or _funNode_`.isGenerator` is *true*, then throw a *SyntaxError* exception. | ||
1. Set _body_ to ? Ecmaify(_labelled_`.body`). | ||
1. Else set _body_ to ? StatementEcmaify(_labelled_`.body`). | ||
1. Let _item_ be |LabelledItem| : _body_. | ||
|
@@ -2785,6 +2832,7 @@ <h1>Ecmaify ( _node_ )</h1> | |
1. Else if _node_ is a `EmptyStatement`, then return ? EcmaifyEmptyStatement(_node_). | ||
1. Else if _node_ is a `ExpressionStatement`, then return ? EcmaifyExpressionStatement(_node_). | ||
1. Else if _node_ is a `FunctionDeclaration`, then return ? EcmaifyFunctionDeclaration(_node_). | ||
1. Else if _node_ is a `LinkableFunctionDeclaration`, then return ? EcmaifyFunctionDeclaration(_node_`.fun`). | ||
1. Else if _node_ is a `IfStatement`, then return ? EcmaifyIfStatement(_node_). | ||
1. Else if _node_ is a `DoWhileStatement`, then return ? EcmaifyDoWhileStatement(_node_). | ||
1. Else if _node_ is a `ForInStatement`, then return ? EcmaifyForInStatement(_node_). | ||
|
@@ -2808,6 +2856,7 @@ <h1>Ecmaify ( _node_ )</h1> | |
1. Else if _node_ is a `LiteralRegExpExpression`, then return ? EcmaifyLiteralRegExpExpression(_node_). | ||
1. Else if _node_ is a `ArrayExpression`, then return ? EcmaifyArrayExpression(_node_). | ||
1. Else if _node_ is a `ArrowExpression`, then return ? EcmaifyArrowExpression(_node_). | ||
1. Else if _node_ is a `LinkableArrowExpression`, then return ? EcmaifyArrowExpression(_node_`.arrow`). | ||
1. Else if _node_ is a `AssignmentExpression`, then return ? EcmaifyAssignmentExpression(_node_). | ||
1. Else if _node_ is a `BinaryExpression`, then return ? EcmaifyBinaryExpression(_node_). | ||
1. Else if _node_ is a `CallExpression`, then return ? EcmaifyCallExpression(_node_). | ||
|
@@ -2816,6 +2865,7 @@ <h1>Ecmaify ( _node_ )</h1> | |
1. Else if _node_ is a `ConditionalExpression`, then return ? EcmaifyConditionalExpression(_node_). | ||
1. Else if _node_ is a `ClassExpression`, then return ? EcmaifyClassExpression(_node_). | ||
1. Else if _node_ is a `FunctionExpression`, then return ? EcmaifyFunctionExpression(_node_). | ||
1. Else if _node_ is a `LinkableFunctionExpression`, then return ? EcmaifyFunctionExpression(_node_`.fun`). | ||
1. Else if _node_ is a `IdentifierExpression`, then return ? EcmaifyIdentifierExpression(_node_). | ||
1. Else if _node_ is a `NewExpression`, then return ? EcmaifyNewExpression(_node_). | ||
1. Else if _node_ is a `NewTargetExpression`, then return ? EcmaifyNewTargetExpression(_node_). | ||
|
@@ -2832,8 +2882,11 @@ <h1>Ecmaify ( _node_ )</h1> | |
1. Else if _node_ is a `LiteralPropertyName`, then return ? EcmaifyLiteralPropertyName(_node_). | ||
1. Else if _node_ is a `LiteralPropertyName`, then return ? EcmaifyLiteralPropertyName(_node_). | ||
1. Else if _node_ is a `Method`, then return ? EcmaifyMethod(_node_). | ||
1. Else if _node_ is a `LinkableMethod`, then return ? EcmaifyMethod(_node_`.method`). | ||
1. Else if _node_ is a `Getter`, then return ? EcmaifyGetter(_node_). | ||
1. Else if _node_ is a `LinkableGetter`, then return ? EcmaifyGetter(_node_`.getter`). | ||
1. Else if _node_ is a `Setter`, then return ? EcmaifySetter(_node_). | ||
1. Else if _node_ is a `LinkableSetter`, then return ? EcmaifySetter(_node_`.setter`). | ||
1. Else if _node_ is a `DataProperty`, then return ? EcmaifyDataProperty(_node_). | ||
1. Else if _node_ is a `ShorthandProperty`, then return ? EcmaifyShorthandProperty(_node_). | ||
1. Else if _node_ is a `ExportAllFrom`, then return ? EcmaifyExportAllFrom(_node_). | ||
|
@@ -3029,7 +3082,7 @@ <h1>CheckRestParameterName ( _expectedParams_, _restParameterName_ )</h1> | |
</emu-alg> | ||
</emu-clause> | ||
|
||
<emu-clause id="sec-checkboundnames" aoid="CheckBOundNames"> | ||
<emu-clause id="sec-checkboundnames" aoid="CheckBoundNames"> | ||
<h1>CheckBoundNames ( _expectedBound_, _actualBound_ )</h1> | ||
<emu-alg> | ||
1. Let _unseen_ be a new empty List. | ||
|
@@ -3042,6 +3095,25 @@ <h1>CheckBoundNames ( _expectedBound_, _actualBound_ )</h1> | |
</emu-alg> | ||
</emu-clause> | ||
|
||
<emu-clause id="sec-checkinnerlazyfunctions" aoid="CheckInnerLazyFunctions"> | ||
<h1>CheckInnerLazyFunctions ( _funcNode_ )</h1> | ||
<emu-alg> | ||
1. Assert: _funcNode_ is a `LazyFunctionDeclaration`, a `LazyFunctionExpression`, a `LazyMethod`, a `LazyGetter`, a `LazySetter`, or a `LazyArrowExpression`. | ||
1. NOTE: All asserted immediately inner (i.e. not nested within another inner function) lazy functions in `innerLazyFunctions` must be found. | ||
1. Let _innerFunctions_ be a new empty List. | ||
1. For each _link_ in _funcNode_`.innerLazyFunctions`, do | ||
1. Let _linkedNode_ be the node linked to by _link_. | ||
1. NOTE: The above step is up to the surface encoding. | ||
1. Assert: _linkedNode_ is a `LinkableFunctionDeclaration`, a `LinkableFunctionExpression`, a `LinkableMethod`, a `LinkableGetter`, a `LinkableSetter`, or a `LinkableArrowExpression`. | ||
1. Add _linkedNode_ as the last element of _innerFunctions_. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't we put There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. |
||
1. For each `FunctionDeclaration`, `FunctionExpression`, `Method`, `Getter`, `Setter`, or `ArrowExpression` _candidateInnerFunction_ contained in _funcNode_, do | ||
1. If the the path from _funcNode_ to _candidateInnerFunction_ contains no other `FunctionDeclaration`, `FunctionExpression`, `Method`, `Getter`, `Setter`, or `ArrowExpression`, then | ||
1. If _candidateInnerFunction_ is not in _innerFunctions_, then throw a *SyntaxError* exception. | ||
1. Remove _candidateInnerFunction_ from _innerFunctions_. | ||
1. If _innerFunctions_ is not empty, then throw a *SyntaxError* exception. | ||
</emu-alg> | ||
</emu-clause> | ||
|
||
<emu-clause id="sec-checkassertedscope" aoid="CheckAssertedScope"> | ||
<h1>CheckAssertedScope ( _scope_ , _parseTree_ )</h1> | ||
<emu-alg> | ||
|
@@ -3609,6 +3681,7 @@ <h1>Runtime Semantics: Delazify</h1> | |
1. Let _delazifiedBody_ be ? EcmaifyFunctionBody(_funcNode_). | ||
1. Perform ? ValidateAndUpdateFunctionObject(_funcNode_, _functionObject_, _delazifiedBody_, _delazifiedParams_). | ||
1. If _funcNode_ is not a `LazyGetter`, then perform ? CheckAssertedScope(_contents_`.parameterScope`, _delazifiedParams_). | ||
1. Perform ? CheckInnerLazyFunctions(_funcNode_). | ||
1. Perform ? CheckAssertedScope(_contents_`.bodyScope`, _delazifiedBody_). | ||
1. If _funcNode_ is a `LazyArrowExpression`, then | ||
1. Perform ? CheckThisCapture(_contents_`.parameterScope`, _delazifiedParams_). | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't we assert that the linkedNode is direct inner function of funcNode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like assert that it is not nested inside another inner function? That's supposed to be taken care of by the very step: if innerFunctions isn't empty, then we throw.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it mean that such link is allowed per file format?
and even if such link appears in the file, we should check if each entry has corresponding functions and throw SyntaxError for it if there's not?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll certainly know when delazifying if there's a Linkable* that doesn't exist, and we can throw then, before exer executing anything.
Is there something in particular that has you worried?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking about the order of the error.
like, if there's 2 possible errors, which one should be observed?
maybe I should revisit this (and some other errors) once the surface encoding format is fixed.