Created
May 24, 2017 23:26
-
-
Save mratsim/92f069c652eb1704e1a7bfc376941919 to your computer and use it in GitHub Desktop.
Nim inline iterator chaining macro
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
| ## From https://forum.nim-lang.org/t/2856 | |
| import macros | |
| macro chaining(code: untyped): untyped = | |
| const chainIdent = "chain" | |
| const combineIdent = "combine" | |
| proc inspect(depth: int, n: NimNode): NimNode = | |
| case(n.kind) | |
| of nnkIdent, nnkStrLit: | |
| return n; | |
| of nnkForStmt: | |
| let onevar = n.len == 3 | |
| let call = n[n.len-2] | |
| if call.kind == nnkCall: | |
| proc get_iter(j: int): NimNode = | |
| let item = call[j] | |
| if item.kind == nnkIdent: | |
| return newCall(item) | |
| item | |
| case($call[0].ident) | |
| of chainIdent: | |
| proc get_name(): NimNode = | |
| if onevar: | |
| return n[0] | |
| result = newNimNode(nnkPar) | |
| for i in 0..n.len - 2: | |
| result.add(n[i]) | |
| let name = get_name() | |
| let body = inspect(depth+1,n[n.len-1]) | |
| let list = newStmtList() | |
| for j in 1..call.len-1: | |
| list.add(newTree(nnkForStmt,name,get_iter(j),body.copy())) | |
| # echo(treeRepr(list)) | |
| return newBlockStmt(list) | |
| of combineIdent: | |
| var body = inspect(depth+1,n[n.len-1]) | |
| var par = newNimNode(nnkPar) | |
| for j in 1..call.len-1: | |
| par.add(genSym(nskForVar)) | |
| var vars: NimNode | |
| if onevar: | |
| vars = newNimNode(nnkIdentDefs) | |
| vars.add(n[0]) | |
| else: | |
| vars = newNimNode(nnkVarTuple) | |
| for i in 0..n.len - 3: | |
| vars.add(n[i]) | |
| vars.add(newEmptyNode()) | |
| vars.add(par) | |
| body.insert(0,newTree(nnkLetSection,vars)) | |
| for j in 1..call.len-1: | |
| let iter = get_iter(j) | |
| let sym = par[j-1] | |
| let f = newTree(nnkForStmt,sym,iter,body) | |
| body = f | |
| # echo(treeRepr(body)) | |
| return body | |
| else: discard | |
| else: discard | |
| var children: seq[NimNode] = @[] | |
| for i in 0..n.len-1: | |
| children.add(inspect(depth+1,n[i])) | |
| result = newNimNode(n.kind) | |
| if children.len > 0: | |
| result.add(children) | |
| result = inspect(0,code) | |
| # echo(treeRepr(result)) | |
| iterator thing1: string = | |
| yield "A" | |
| yield "B" | |
| yield "C" | |
| iterator thing2: string = | |
| yield "D" | |
| yield "E" | |
| yield "F" | |
| yield "cookiemonster" | |
| iterator thing3(i: int): int = | |
| yield 1+i | |
| yield 2+i | |
| yield 3+i | |
| chaining: | |
| echo("regular iteration.......") | |
| for thing in thing1(): | |
| echo(thing) | |
| echo("chaining.......") | |
| for thing in chain(thing1,thing2,["wait, try that again"],thing1,thing3(0),"derp"): | |
| echo(thing) | |
| echo("combinations.......") | |
| for a,b in combine(thing1,thing3(39)): | |
| echo(a, " ", b) | |
| echo(".......") | |
| for a,b in combine(thing1,thing1): | |
| echo(a, " ", b) | |
| echo("can capture as a tuple-ish thing.......") | |
| for thing in combine(thing1,thing3(23)): | |
| echo(thing) | |
| let (a,b) = thing | |
| echo(a," ",b) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment