summary refs log blame commit diff stats
path: root/tests/macros/tmacros_various.nim
blob: 00d74cb5c97a959a96f0a7c558f3faf6385f49a0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
           









                  
             









                             

                                                                  
 



   
                                






















                                               
                                                                            

































































                                                                                 

























                                                                    


















































                                                     
 
                       





                                                                        



















                                                                        













                               







                                        
























                                                                        
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
'''
"""


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 tlineinfo:
  # 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 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: # 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)