Skip to content

Commit

Permalink
cps: experimental support for for-loops
Browse files Browse the repository at this point in the history
For-loops are inlined using block statements, which messes with their
control flow due to #76.

Breaks a test in tzevv due to defer being rewritten into
try-finally, which doesn't work.

Co-authored-by: Andy Davidoff <github@andy.disruptek.com>
  • Loading branch information
alaviss and disruptek committed May 14, 2021
1 parent c1a0c20 commit 4f88928
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 17 deletions.
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
when defined(nimdoc):
result = n
else:
result = cpsXfrm(T, n)

macro cps*(T: typed, n: typed): untyped =
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

0 comments on commit 4f88928

Please sign in to comment.