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

cps: experimental support for for-loops #84

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion cps.nim
Original file line number Diff line number Diff line change
Expand Up @@ -941,13 +941,21 @@ proc cpsXfrm(T: NimNode, n: NimNode): NimNode =
result = copy n
result = workaroundRewrites(result)

macro cps*(T: typed, n: typed): untyped =
macro cps2(T: typed, n: typed): untyped =
# I hate doing stuff inside macros, call the proc to do the work
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# I hate doing stuff inside macros, call the proc to do the work
## We used `getImplTransformed` to make a pre-pass whatfer transforming `for` and `defer`
## into the input to this macro, where we perform the meat of the CPS transform.

Copy link
Contributor

@saem saem May 4, 2021

Choose a reason for hiding this comment

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

I think we could use a for loop macro to remove part of the getImplTransformed dependency, I still need to think about the defer one.

Not a blocker

when defined(nimdoc):
result = n
else:
result = cpsXfrm(T, n)
Comment on lines 946 to 949
Copy link
Contributor

Choose a reason for hiding this comment

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

This when should move into cps().


macro cps*(T: typed, n: typed): untyped =
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
macro cps*(T: typed, n: typed): untyped =
macro cps*(T: typed, n: typed): untyped =
## Rewrite procedure `n` in Continuation-Passing Style, extending type `T` to store any transient locals.

case n.kind
of nnkProcDef:
result = getImplTransformed n.name
result.addPragma newColonExpr(bindSym"cps2", T)
else:
result = cpsXfrm(T, n)

macro cpsMagic*(n: untyped): untyped =
## upgrade cps primitives to generate errors out of context
## and take continuations as input inside {.cps.} blocks
Expand Down
18 changes: 17 additions & 1 deletion cps/spec.nim
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,12 @@ proc normalizingRewrites*(n: NimNode): NimNode =
if n.len == 2:
n.add newEmptyNode()
elif n[1].isEmpty: # add explicit type symbol
n[1] = getTypeInst n[2]
if not n[2].isEmpty:
n[1] = getTypeInst n[2]
else:
# get the type from the symbol as the last resort.
# walkaround for #48.
n[1] = getTypeInst n[0]
n[2] = normalizingRewrites n[2]
result = n

Expand Down Expand Up @@ -439,6 +444,15 @@ proc normalizingRewrites*(n: NimNode): NimNode =
else:
discard

proc rewriteFastAsgn(n: NimNode): NimNode =
## Rewrite nnkFastAsgn into nnkAsgn because sem don't like them
case n.kind
of nnkFastAsgn:
result = newNimNode(nnkAsgn, n)
for child in n.items:
result.add child
else: discard

case n.kind
of nnkIdentDefs:
rewriteIdentDefs n
Expand All @@ -452,6 +466,8 @@ proc normalizingRewrites*(n: NimNode): NimNode =
rewriteReturn n
of CallNodes:
rewriteHidden n
of nnkFastAsgn:
rewriteFastAsgn n
else:
nil

Expand Down
27 changes: 12 additions & 15 deletions tests/taste.nim
Original file line number Diff line number Diff line change
Expand Up @@ -998,19 +998,16 @@ suite "tasteful tests":

block:
## for loops with continue, break and a split
when true:
skip"pending #48"
else:
r = 0
proc foo() {.cps: Cont.} =
inc r
for i in 0 .. 3:
noop()
if i == 0:
continue
if i > 2:
break
r.inc i
r = 0
proc foo() {.cps: Cont.} =
inc r
for i in 0 .. 3:
noop()
if i == 0:
continue
if i > 2:
break
r.inc i

trampoline foo()
check r == 4
trampoline foo()
check r == 4