discard """ nimout: ''' Infix Ident "=>" Call Ident "name" Ident "a" ExprColonExpr Ident "b" Ident "cint" NilLit macrocache ok ''' output: ''' x = 10 x + y = 30 proc foo[T, N: static[int]]() proc foo[T; N: static[int]]() a[0]: 42 a[1]: 45 x: some string ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")]) ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")]) 0 0 0 ''' """ import macros, sugar, macrocache block tdump: let x = 10 y = 20 dump x dump(x + y) block texprcolonexpr: macro def(x): untyped = echo treeRepr(x) def name(a, b:cint) => nil block tgenericparams: macro test():string = let expr0 = "proc foo[T, N: static[int]]()" let expr1 = "proc foo[T; N: static[int]]()" newLit($toStrLit(parseExpr(expr0)) & "\n" & $toStrLit(parseExpr(expr1))) echo test() block tidgen: # Test compile-time state in same module var gid {.compileTime.} = 3 macro genId(): int = result = newIntLitNode(gid) inc gid proc Id1(): int {.compileTime.} = return genId() proc Id2(): int {.compileTime.} = return genId() doAssert Id1() == 3 doAssert Id2() == 4 block tlexerex: macro match(s: cstring|string; pos: int; sections: varargs[untyped]): untyped = for sec in sections: expectKind sec, nnkOfBranch expectLen sec, 2 result = newStmtList() var input = "the input" var pos = 0 match input, pos: of r"[a-zA-Z_]\w+": echo "an identifier" of r"\d+": echo "an integer" of r".": echo "something else" block tcopylineinfo: # issue #5617, feature request type Test = object macro mixer(n: typed): untyped = let x = newIdentNode("echo") x.copyLineInfo(n) result = newLit(x.lineInfo == n.lineInfo) var z = mixer(Test) doAssert z block tsetgetlineinfo: # issue #21098, feature request type Test = object macro mixer1(n: typed): untyped = let x = newIdentNode("echo") var lineInfo = n.lineInfoObj x.setLineInfo lineInfo result = newLit(x.lineInfo == n.lineInfo) macro mixer2(n: typed): untyped = let x = newIdentNode("echo") var lineInfo = n.lineInfoObj lineInfo.line += 1 x.setLineInfo lineInfo result = newLit(x.lineInfo != n.lineInfo) doAssert mixer1(Test) doAssert mixer2(Test) block tdebugstmt: macro debug(n: varargs[untyped]): untyped = result = newNimNode(nnkStmtList, n) for i in 0..n.len-1: add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i]))) add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": "))) add(result, newCall("writeLine", newIdentNode("stdout"), n[i])) var a: array[0..10, int] x = "some string" a[0] = 42 a[1] = 45 debug(a[0], a[1], x) const pairs = {"key": "val", "keyB": "2"} macro bilookups(arg: static[openArray[(string, string)]]): untyped = var a = newTree(nnkBracket) var b = newTree(nnkBracket) for (k, v) in items(arg): a.add(newTree(nnkTupleConstr, newLit k, newLit v)) b.add(newTree(nnkTupleConstr, newLit v, newLit k)) result = newTree(nnkTupleConstr, a, b) macro bilookups2(arg: untyped): untyped = var a = newTree(nnkBracket) var b = newTree(nnkBracket) arg.expectKind(nnkTableConstr) for x in items(arg): x.expectKind(nnkExprColonExpr) a.add(newTree(nnkTupleConstr, x[0], x[1])) b.add(newTree(nnkTupleConstr, x[1], x[0])) result = newTree(nnkTupleConstr, a, b) const cnst1 = bilookups(pairs) echo cnst1 const cnst2 = bilookups2({"key": "val", "keyB": "2"}) echo cnst2 # macrocache #11404 const mcTable = CacheTable"nimTest" mcSeq = CacheSeq"nimTest" mcCounter = CacheCounter"nimTest" static: doAssert(mcCounter.value == 0) # CacheCounter.value mcCounter.inc # CacheCounter.inc doAssert(mcCounter.value == 1) # CacheCounter.value let a = newLit(1) let b = newLit(2) let c = newLit(3) let d = newLit(4) mcSeq.add a # CacheSeq.add mcSeq.add b # CacheSeq.add mcSeq.add c # CacheSeq.add doAssert(mcSeq.len == 3) # CacheSeq.len #doAssert(c in mcSeq) # CacheSeq.contains #doAssert(d notin mcSeq) # CacheSeq.contains mcSeq.incl d # CacheSeq.incl doAssert(mcSeq.len == 4) # CacheSeq.len mcSeq.incl c # CacheSeq.incl doAssert(mcSeq.len == 4) # CacheSeq.len doAssert(mcSeq[3] == d) # CacheSeq.[] #doAssert(mcSeq.pop() == d)# CacheSeq.pop #doAssert(mcSeq.len == 3) # CacheSeq.len doAssert(mcTable.len == 0) # CacheTable.len mcTable["a"] = a # CacheTable.[]= doAssert(mcTable.len == 1) # CacheTable.len doAssert(mcTable["a"] == a) # CacheTable.[] #doAssert("a" in mcTable) # CacheTable.contains #doAssert(mcTable.hasKey("a"))# CacheTable.hasKey for k, v in mcTable: # CacheTable.items doAssert(k == "a") doAssert(v == a) echo "macrocache ok" block tupleNewLitTests: macro t(): untyped = result = newLit (1, "foo", (), (1,), (a1: 'x', a2: @["ba"])) doAssert $t() == """(1, "foo", (), (1,), (a1: 'x', a2: @["ba"]))""" # this `$` test is needed because tuple equality doesn't distinguish # between named vs unnamed tuples doAssert t() == (1, "foo", (), (1, ), (a1: 'x', a2: @["ba"])) from strutils import contains block getImplTransformed: macro bar(a: typed): string = # newLit a.getImpl.repr # this would be before code transformation let b = a.getImplTransformed newLit b.repr template toExpand() = for ai in 0..2: echo ai proc baz(a=1): int = defer: discard toExpand() 12 const code = bar(baz) # sanity check: doAssert "finally" in code # `defer` is lowered to try/finally doAssert "while" in code # `for` is lowered to `while` doAssert "toExpand" notin code # template is expanded (but that would already be the case with # `a.getImpl.repr`, unlike the other transformations mentioned above # test macro resemming macro makeVar(): untyped = quote: var tensorY {.inject.}: int macro noop(a: typed): untyped = a noop: makeVar echo tensorY macro xbenchmark(body: typed): untyped = result = body xbenchmark: proc fastSHA(inputtest: string) = discard inputtest fastSHA("hey") block: # issue #4547 macro lazy(stmtList : typed) : untyped = let decl = stmtList[0] decl.expectKind nnkLetSection let name = decl[0][0].strVal let call = decl[0][2].copy call.expectKind nnkCall let ident = newIdentNode("get" & name) result = quote do: var value : type(`call`) proc `ident`() : type(`call`) = if value.isNil: value = `call` value type MyObject = object a,b: int # this part, the macro call and it's result (written in the comment below) is important lazy: let y = new(MyObject) #[ var value: type(new(MyObject)) proc gety(): type(new(MyObject)) = if value.isNil: value = new(MyObject) value ]# doAssert gety().a == 0 # works and should work doAssert gety().b == 0 # works and should work doAssert not declared(y) doAssert not compiles(y.a) # identifier y should not exist anymore doAssert not compiles(y.b) # identifier y should not exist anymore block: # bug #13511 type Builder = ref object components: seq[Component] Component = object proc add(builder: var Builder, component: Component) {.compileTime.} = builder.components.add(component) macro debugAst(arg: typed): untyped = ## just for debugging purpose. discard arg.treeRepr return arg static: var component = Component() var builder = Builder() template foo(): untyped = ## WAS: this doc comment causes compilation failure. builder debugAst: add(foo(), component) block: # bug #15118 macro flop(name: static string) = let id = genSym(nskType, "env") let r = nnkStmtList.newTree( nnkTypeSection.newTree( nnkTypeDef.newTree( id, newEmptyNode(), nnkRefTy.newTree( nnkObjectTy.newTree( newEmptyNode(), newEmptyNode(), nnkRecList.newTree( nnkIdentDefs.newTree( newIdentNode(name), newIdentNode("int"), newEmptyNode() ) ) ) ) ) ), # var f: T nnkVarSection.newTree( nnkIdentDefs.newTree( newIdentNode("f"), id, newEmptyNode() ) ), # echo f.a nnkCommand.newTree( newIdentNode("new"), newIdentNode("f") ), nnkCommand.newTree( newIdentNode("echo"), nnkDotExpr.newTree( newIdentNode("f"), newIdentNode(name) ) ) ) r block: flop("a") block: flop("b") static: block: const containsTable = CacheTable"containsTable" doAssert "foo" notin containsTable containsTable["foo"] = newLit 42 doAssert "foo" in containsTable