Skip to content
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

closureiters: use case-based dispatcher #607

Merged

Conversation

zerbina
Copy link
Collaborator

@zerbina zerbina commented Mar 29, 2023

Summary

Use a case statement for the dispatcher generated by the closureiters transformation, removing the need for both dedicated code generator support and the nkState node kind. This is a significant step towards closure iterator support the JavaScript and VM backend.

While neither officially supported nor documented, it was previously possible to emit nkGotoState and nkState nodes from a macro, which could be used for unsafe unstructured control-flow. With the removal of the nkState node kind and nkGotoState being disallowed in AST reaching semantic analysis, the aforementioned is no longer possible.

Details

The AST generated by the closureiters transformation always looked as follows:

while true:
  block :stateLoop: # the block's body is wrapped in a try-except, if
		    # necessary
    goto env.:state # goto the label corresponding to the run-time value
                    # of `:state`
    # declarations
    body

where body defines the code blocks associated with each state value, like so:

state 0:
...
env.:state = 1
break :stateLoop
state 1:
...
state 2:
...
... # more labels (if used) follow

The control-flow described by the goto (nkGotoState) followed by the labels (nkState) is equally representable by the use of a case statement, which is what is now done after this commit.

To summarize the change:

  • don't support nkGotoState nodes in AST reaching sem
  • adjust closureiters to generate a case statement for the dispatcher and to not depend on nkState
  • remove C code-generator support for nkGotoState and nkState
  • remove the nkState node kind

Nodes with the nkGotoState kind now only exists during the transformation, but never before or after.


Notes for Reviewers

  • all code-generators support the closure-iterator transformation now, but jsgen and vmgen don't implement the mFinished magic yet, meaning that .closure iterators are still not supported by the respective backends
  • I'm going to implement mFinished support as a follow-up PR

@zerbina zerbina added enhancement New feature or request compiler General compiler tag compiler/sem Related to semantic-analysis system of the compiler compiler/backend Related to backend system of the compiler simplification Removal of the old, unused, unnecessary or un/under-specified language features. and removed enhancement New feature or request labels Mar 29, 2023
@zerbina zerbina force-pushed the closureiters-case-statement-dispatcher branch from 5fc978a to e04de01 Compare March 29, 2023 19:24
@zerbina zerbina changed the title closureiters: use case-statement-based dispatcher closureiters: use case-based dispatcher Mar 29, 2023
@@ -185,7 +185,7 @@ type
unrollFinallySym: PSym # Indicates that we're unrolling finally states (either exception happened or premature return)
curExcSym: PSym # Current exception

states: seq[PNode] # The resulting states. Every state is an nkState node.
states: seq[tuple[label: int, body: PNode]] # The resulting states
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type reads more nicely and the tuple fields make the access below easier to follow when skimming. 👍🏽

while i < ctx.states.len - 1:
let fs = skipStmtList(ctx, ctx.states[i][1])
if fs.kind == nkGotoState and i != 0:
if ctx.states[i].label == -1: # is it unused?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very soft suggestion: make -1 a constant, such as unusedStateIdx, might read a bit better. It'd also be applicable to the setting of the label values above.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's much better, thanks.

@saem
Copy link
Collaborator

saem commented Mar 29, 2023

I definitely like how this collapses the language into itself. Even before this change, I can imagine using case to explain how iterators work to a newcomer, and now the simple explanation and implementation are that much closer. Makes bridging the gap from language user to contributor that much smaller. 🚀

@zerbina zerbina force-pushed the closureiters-case-statement-dispatcher branch from e04de01 to c5fc991 Compare March 29, 2023 20:53
Summary
=======

Use a case statement for the dispatcher generated by the `closureiters`
transformation, removing the need for both dedicated code generator
support and the `nkState` node kind. This is a significant step towards
closure iterator support the JavaScript and VM backend.

While neither officially supported nor documented, it was previously
possible to emit `nkGotoState` and `nkState` nodes from a macro, which
could be used for unsafe unstructured control-flow. With the removal of
the `nkState` node kind and `nkGotoState` being disallowed in AST
reaching semantic analysis, the aforementioned is no longer possible.

Details
=======

The AST generated by the `closureiters` transformation always looked
as follows:

```nim
while true:
  block :stateLoop: # the block's body is wrapped in a try-except, if
		    # necessary
    goto env.:state # goto the label corresponding to the run-time value
                    # of `:state`
    # declarations
    body
```

where `body` defines the code blocks associated with each state
value, like so:

```nim
state 0:
...
env.:state = 1
break :stateLoop
state 1:
...
state 2:
...
... # more labels (if used) follow
```

The control-flow described by the `goto` (`nkGotoState`) followed by
the labels (`nkState`) is equally representable by the use of a case
statement, which is what is now done after this commit.

To summarize the change:
- don't support `nkGotoState` nodes in AST reaching sem
- adjust `closureiters` to generate a case statement for the dispatcher
  and to not depend on `nkState`
- remove C code-generator support for `nkGotoState` and `nkState`
- remove the `nkState` node kind

Nodes with the `nkGotoState` kind now only exists *during* the
transformation, but never before or after.
@saem
Copy link
Collaborator

saem commented Mar 29, 2023

bors r+

@bors
Copy link
Contributor

bors bot commented Mar 30, 2023

Build succeeded:

@bors bors bot merged commit 674cbbe into nim-works:devel Mar 30, 2023
@zerbina zerbina deleted the closureiters-case-statement-dispatcher branch April 10, 2023 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/backend Related to backend system of the compiler compiler/sem Related to semantic-analysis system of the compiler compiler General compiler tag simplification Removal of the old, unused, unnecessary or un/under-specified language features.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants