summary refs log tree commit diff stats
path: root/tests/macros
diff options
context:
space:
mode:
Diffstat (limited to 'tests/macros')
-rw-r--r--tests/macros/m18235.nim42
-rw-r--r--tests/macros/macro_bug.nim18
-rw-r--r--tests/macros/mparsefile.nim4
-rw-r--r--tests/macros/t14227.nim23
-rw-r--r--tests/macros/t14329.nim4
-rw-r--r--tests/macros/t14511.nim54
-rw-r--r--tests/macros/t14847.nim20
-rw-r--r--tests/macros/t15691.nim22
-rw-r--r--tests/macros/t15751.nim11
-rw-r--r--tests/macros/t16758.nim38
-rw-r--r--tests/macros/t17836.nim15
-rw-r--r--tests/macros/t18203.nim15
-rw-r--r--tests/macros/t18235.nim18
-rw-r--r--tests/macros/t19766_20114.nim16
-rw-r--r--tests/macros/t20067.nim28
-rw-r--r--tests/macros/t20435.nim30
-rw-r--r--tests/macros/t21593.nim13
-rw-r--r--tests/macros/t23032_1.nim19
-rw-r--r--tests/macros/t23032_2.nim20
-rw-r--r--tests/macros/t23547.nim23
-rw-r--r--tests/macros/t23784.nim157
-rw-r--r--tests/macros/t7454.nim8
-rw-r--r--tests/macros/t7875.nim22
-rw-r--r--tests/macros/t8997.nim26
-rw-r--r--tests/macros/tastrepr.nim58
-rw-r--r--tests/macros/tbindsym.nim67
-rw-r--r--tests/macros/tcasestmtmacro.nim33
-rw-r--r--tests/macros/tclosuremacro.nim80
-rw-r--r--tests/macros/tcollect.nim63
-rw-r--r--tests/macros/tcomplexecho.nim42
-rw-r--r--tests/macros/tcprag.nim32
-rw-r--r--tests/macros/tdumpast.nim161
-rw-r--r--tests/macros/tdumpast2.nim36
-rw-r--r--tests/macros/tdumpastgen.nim45
-rw-r--r--tests/macros/tdumptree.nim27
-rw-r--r--tests/macros/tescape_var_into_quotedo_as_const.nim36
-rw-r--r--tests/macros/texpectIdent1.nim18
-rw-r--r--tests/macros/texpectIdent2.nim24
-rw-r--r--tests/macros/tfail_parse.nim15
-rw-r--r--tests/macros/tforloop_macro1.nim44
-rw-r--r--tests/macros/tgetimpl.nim103
-rw-r--r--tests/macros/tgetraiseslist.nim29
-rw-r--r--tests/macros/tgettype.nim85
-rw-r--r--tests/macros/tgettype2.nim99
-rw-r--r--tests/macros/tgettype3.nim48
-rw-r--r--tests/macros/tgettypeinst.nim214
-rw-r--r--tests/macros/tgettypeinst7737.nim61
-rw-r--r--tests/macros/tincremental.nim150
-rw-r--r--tests/macros/tinvalidtypesym.nim14
-rw-r--r--tests/macros/tisexported.nim10
-rw-r--r--tests/macros/tlocktypednode1.nim12
-rw-r--r--tests/macros/tlocktypednode2.nim12
-rw-r--r--tests/macros/tlocktypednode3.nim15
-rw-r--r--tests/macros/tmacro1.nim119
-rw-r--r--tests/macros/tmacro2.nim36
-rw-r--r--tests/macros/tmacro3.nim30
-rw-r--r--tests/macros/tmacro4.nim17
-rw-r--r--tests/macros/tmacro5.nim59
-rw-r--r--tests/macros/tmacro6.nim75
-rw-r--r--tests/macros/tmacro7.nim36
-rw-r--r--tests/macros/tmacro8.nim35
-rw-r--r--tests/macros/tmacroaspragma.nim7
-rw-r--r--tests/macros/tmacrogenerics.nim38
-rw-r--r--tests/macros/tmacrogensym.nim65
-rw-r--r--tests/macros/tmacrogetimpl.nim31
-rw-r--r--tests/macros/tmacros1.nim81
-rw-r--r--tests/macros/tmacros_issues.nim521
-rw-r--r--tests/macros/tmacros_various.nim391
-rw-r--r--tests/macros/tmacrostmt.nim155
-rw-r--r--tests/macros/tmacrotypes.nim157
-rw-r--r--tests/macros/tmemit.nim38
-rw-r--r--tests/macros/tmsginfo.nim24
-rw-r--r--tests/macros/tnewlit.nim194
-rw-r--r--tests/macros/tnewproc.nim51
-rw-r--r--tests/macros/tnodecompare.nim39
-rw-r--r--tests/macros/tparsefile.nim11
-rw-r--r--tests/macros/tprocgettype.nim28
-rw-r--r--tests/macros/tprochelpers.nim22
-rw-r--r--tests/macros/tquotedo.nim51
-rw-r--r--tests/macros/tquotewords.nim22
-rw-r--r--tests/macros/trecmacro.nim14
-rw-r--r--tests/macros/treturnsempty.nim11
-rw-r--r--tests/macros/tsame_name_497.nim6
-rw-r--r--tests/macros/tsametype.nim42
-rw-r--r--tests/macros/tslice.nim38
-rw-r--r--tests/macros/tstaticparamsmacro.nim75
-rw-r--r--tests/macros/tstringinterp.nim73
-rw-r--r--tests/macros/tstructuredlogging.nim154
-rw-r--r--tests/macros/ttemplatesymbols.nim171
-rw-r--r--tests/macros/ttryparseexpr.nim24
-rw-r--r--tests/macros/ttypenodes.nim16
-rw-r--r--tests/macros/tvarargsuntyped.nim108
-rw-r--r--tests/macros/tvtable.nim74
-rw-r--r--tests/macros/twrapiterator.nim19
-rw-r--r--tests/macros/typesafeprintf.nim49
-rw-r--r--tests/macros/typesapi2.nim48
96 files changed, 5534 insertions, 0 deletions
diff --git a/tests/macros/m18235.nim b/tests/macros/m18235.nim
new file mode 100644
index 000000000..6bb4547e0
--- /dev/null
+++ b/tests/macros/m18235.nim
@@ -0,0 +1,42 @@
+import macros
+
+# Necessary code to update the AST on a symbol across module boundaries when
+# processed by a type macro. Used by a test of a corresponding name of this
+# file.
+
+macro eexport(n: typed): untyped =
+  result = copyNimTree(n)
+  # turn exported nnkSym -> nnkPostfix(*, nnkIdent), forcing re-sem
+  result[0] = nnkPostfix.newTree(ident"*").add:
+    n.name.strVal.ident
+
+macro unexport(n: typed): untyped =
+  result = copyNimTree(n)
+  # turn nnkSym -> nnkIdent, forcing re-sem and dropping any exported-ness
+  # that might be present
+  result[0] = n.name.strVal.ident
+
+proc foo*() {.unexport.} = discard
+proc bar() {.eexport.} = discard
+
+proc foooof*() {.unexport, eexport, unexport.} = discard
+proc barrab() {.eexport, unexport, eexport.} = discard
+
+macro eexportMulti(n: typed): untyped =
+  # use the call version of `eexport` macro for one or more decls
+  result = copyNimTree(n)
+  for i in 0..<result.len:
+    result[i] = newCall(ident"eexport", result[i])
+
+macro unexportMulti(n: typed): untyped =
+  # use the call version of `unexport` macro for one or more decls
+  result = copyNimTree(n)
+  for i in 0..<result.len:
+    result[i] = newCall(ident"unexport", result[i])
+
+unexportMulti:
+  proc oof*() = discard
+
+eexportMulti:
+  proc rab() = discard
+  proc baz*() = discard
\ No newline at end of file
diff --git a/tests/macros/macro_bug.nim b/tests/macros/macro_bug.nim
new file mode 100644
index 000000000..c723a4ab6
--- /dev/null
+++ b/tests/macros/macro_bug.nim
@@ -0,0 +1,18 @@
+import macros
+
+macro macro_bug*(s: untyped) =
+  echo s.treeRepr
+  s.expectKind({nnkProcDef, nnkMethodDef})
+
+  var params = s.params
+
+  let genericParams = s[2]
+  result = newNimNode(nnkProcDef).add(
+    s.name, s[1], genericParams, params, pragma(s), newEmptyNode())
+
+  # don't really do anything
+  var body = body(s)
+  result.add(body)
+
+  echo "result:"
+  echo result.repr
diff --git a/tests/macros/mparsefile.nim b/tests/macros/mparsefile.nim
new file mode 100644
index 000000000..8ac99d568
--- /dev/null
+++ b/tests/macros/mparsefile.nim
@@ -0,0 +1,4 @@
+let a = 1
+let b = 2
+let c =
+let d = 4
diff --git a/tests/macros/t14227.nim b/tests/macros/t14227.nim
new file mode 100644
index 000000000..4206e2c06
--- /dev/null
+++ b/tests/macros/t14227.nim
@@ -0,0 +1,23 @@
+discard """
+  action: "compile"
+"""
+import sugar
+
+
+block:
+  let y = @[@[1, 2], @[2, 4, 6]]
+  let x = collect(newSeq):
+    for i in y:
+      if i.len > 2:
+        for j in i:
+          j
+  echo(x)
+
+block:
+  let y = @[@[1, 2], @[2, 4, 6]]
+  let x = collect(newSeq):
+    for i in y:
+      for j in i:
+        if i.len > 2:
+          j
+  echo(x)
diff --git a/tests/macros/t14329.nim b/tests/macros/t14329.nim
new file mode 100644
index 000000000..b5606424a
--- /dev/null
+++ b/tests/macros/t14329.nim
@@ -0,0 +1,4 @@
+import macros
+
+macro myMacro(n) =
+  let x = if true: newLit"test" else: error "error", n
diff --git a/tests/macros/t14511.nim b/tests/macros/t14511.nim
new file mode 100644
index 000000000..f3b1e2894
--- /dev/null
+++ b/tests/macros/t14511.nim
@@ -0,0 +1,54 @@
+discard """
+  output: "true\n(y: XInt, a: 5)\n(y: XString, b: \"abc\")"
+"""
+
+import macros
+
+block TEST_1:
+  # https://github.com/nim-lang/Nim/issues/14511
+
+  template myPragma() {.pragma.}
+
+  type
+    XType = enum
+      XInt,
+      XString,
+      XUnused
+    X = object
+      case y {.myPragma.}: XType
+        of XInt, XUnused:
+          a: int
+        else: # <-- Else case caused the "Error: index 1 not in 0 .. 0" error
+          b: string
+
+  var x: X = X(y: XInt, a: 5)
+  echo x.y.hasCustomPragma(myPragma)
+  echo x
+  echo X(y: XString, b: "abc")
+
+
+block TEST_2:
+  template myDevice(val: string) {.pragma.}
+  template myKey(val: string) {.pragma.}
+  template myMouse(val: string) {.pragma.}
+
+  type
+    Device {.pure.} = enum Keyboard, Mouse
+    Key = enum Key1, Key2
+    Mouse = enum Mouse1, Mouse2
+
+  type
+    Obj = object of RootObj
+      case device {.myDevice: "MyDevicePragmaStr".}: Device
+      of Device.Keyboard:
+        key {.myKey: "MyKeyPragmaStr".}: Key
+      else: # <-- Else case caused the "Error: index 1 not in 0 .. 0" error
+        mouse {.myMouse: "MyMousePragmaStr".}: Mouse
+
+  var obj: Obj
+  assert obj.device.hasCustomPragma(myDevice) == true
+  assert obj.key.hasCustomPragma(myKey) == true
+  assert obj.mouse.hasCustomPragma(myMouse) == true
+  assert obj.device.getCustomPragmaVal(myDevice) == "MyDevicePragmaStr"
+  assert obj.key.getCustomPragmaVal(myKey) == "MyKeyPragmaStr"
+  assert obj.mouse.getCustomPragmaVal(myMouse) == "MyMousePragmaStr"
\ No newline at end of file
diff --git a/tests/macros/t14847.nim b/tests/macros/t14847.nim
new file mode 100644
index 000000000..0e6d0dd2d
--- /dev/null
+++ b/tests/macros/t14847.nim
@@ -0,0 +1,20 @@
+discard """
+  output: "98"
+"""
+import macros
+
+#bug #14847
+proc hello*(b: string) =
+  echo b
+
+macro dispatch(pro: typed, params: untyped): untyped =
+  var impl = pro.getImpl
+  let id = ident(pro.strVal & "_coverage")
+  impl[0] = id
+  let call = newCall(id, params)
+
+  result = newStmtList()
+  result.add(impl)
+  result.add(call)
+
+dispatch(hello, "98")
diff --git a/tests/macros/t15691.nim b/tests/macros/t15691.nim
new file mode 100644
index 000000000..c1e8a8648
--- /dev/null
+++ b/tests/macros/t15691.nim
@@ -0,0 +1,22 @@
+discard """
+  action: compile
+"""
+
+import std/macros
+
+macro simplifiedExpandMacros(body: typed): untyped =
+  result = body
+
+simplifiedExpandMacros:
+  proc testProc() = discard
+
+simplifiedExpandMacros:
+  template testTemplate(): untyped = discard
+
+# Error: illformed AST: macro testMacro(): untyped =
+simplifiedExpandMacros:
+  macro testMacro(): untyped = discard
+
+# Error: illformed AST: converter testConverter(x: int): float =
+simplifiedExpandMacros:
+  converter testConverter(x: int): float = discard
diff --git a/tests/macros/t15751.nim b/tests/macros/t15751.nim
new file mode 100644
index 000000000..fcabb2f9e
--- /dev/null
+++ b/tests/macros/t15751.nim
@@ -0,0 +1,11 @@
+discard """
+  cmd: "nim c --hints:off $file"
+  nimout: "out"
+"""
+
+# bug #15751
+macro print(n: untyped): untyped =
+  echo n.repr
+
+print:
+  out
diff --git a/tests/macros/t16758.nim b/tests/macros/t16758.nim
new file mode 100644
index 000000000..66b6d42c5
--- /dev/null
+++ b/tests/macros/t16758.nim
@@ -0,0 +1,38 @@
+discard """

+errormsg: "'blk.p(a)' has nil child at index 1"

+action: reject

+"""

+import macros

+

+type BlockLiteral[T] = object

+  p: T

+

+proc p[T](a:int) = echo 1

+proc p[T](a:string) = echo "a"

+

+iterator arguments(formalParams: NimNode): NimNode =

+  var iParam = 0

+  for i in 1 ..< formalParams.len:

+    let pp = formalParams[i]

+    for j in 0 .. pp.len - 3:

+      yield pp[j]

+      inc iParam

+

+macro implementInvoke(T: typedesc): untyped =

+  let t = getTypeImpl(T)[1]

+

+  let call = newCall(newDotExpr(ident"blk", ident"p"))

+  let params = copyNimTree(t[0])

+  result = newProc(ident"invoke", body = call)

+  # result[2] = newTree(nnkGenericParams,T)

+  for n in arguments(params):

+    call.add(n)

+  

+  params.insert(1, newIdentDefs(ident"blk", newTree(nnkBracketExpr, bindSym"BlockLiteral", T)))

+  result.params = params

+

+proc getInvoke(T: typedesc) =

+  implementInvoke(T)

+

+

+getInvoke(proc(a: int))

diff --git a/tests/macros/t17836.nim b/tests/macros/t17836.nim
new file mode 100644
index 000000000..2453637f5
--- /dev/null
+++ b/tests/macros/t17836.nim
@@ -0,0 +1,15 @@
+import macros
+
+# Ensure that `isNil` works in the typed macro context when pass procs.
+
+type
+  O = object
+    fn: proc(i: int): int
+
+var o: O
+
+macro typedBug(expr: typed) =
+  doAssert expr[1] != nil
+  doAssert not expr[1].isNil
+
+typedBug(o.fn)
\ No newline at end of file
diff --git a/tests/macros/t18203.nim b/tests/macros/t18203.nim
new file mode 100644
index 000000000..aae0a2690
--- /dev/null
+++ b/tests/macros/t18203.nim
@@ -0,0 +1,15 @@
+discard """
+  matrix: "--hint:SuccessX:off --hint:Link:off --hint:Conf:off --hint:CC:off --hint:XDeclaredButNotUsed:on"
+  nimout: '''
+'''
+nimoutFull: true
+action: compile
+"""
+
+# bug #18203
+import std/macros
+
+macro foo(x: typed) = newProc ident"bar"
+proc bar() {.foo.} = raise
+bar()
+
diff --git a/tests/macros/t18235.nim b/tests/macros/t18235.nim
new file mode 100644
index 000000000..ba5c48a24
--- /dev/null
+++ b/tests/macros/t18235.nim
@@ -0,0 +1,18 @@
+import m18235
+
+# this must error out because it was never actually exported
+doAssert(not declared(foo))
+doAssert not compiles(foo())
+
+doAssert(not declared(foooof))
+doAssert not compiles(foooof())
+
+doAssert(not declared(oof))
+doAssert not compiles(oof())
+
+# this should have been exported just fine
+
+bar()
+barrab()
+rab()
+baz()
\ No newline at end of file
diff --git a/tests/macros/t19766_20114.nim b/tests/macros/t19766_20114.nim
new file mode 100644
index 000000000..ac336f150
--- /dev/null
+++ b/tests/macros/t19766_20114.nim
@@ -0,0 +1,16 @@
+discard """
+  action: compile
+  nimout: '''
+const
+  foo {.strdefine.} = "abc"
+let hey {.tddd.} = 5
+'''
+"""
+
+import macros
+
+template tddd {.pragma.}
+
+expandMacros:
+  const foo {.strdefine.} = "abc"
+  let hey {.tddd.} = 5
diff --git a/tests/macros/t20067.nim b/tests/macros/t20067.nim
new file mode 100644
index 000000000..0ee3a4712
--- /dev/null
+++ b/tests/macros/t20067.nim
@@ -0,0 +1,28 @@
+discard """
+  output: '''
+b.defaultVal = foo
+$c.defaultVal = bar
+'''
+"""
+
+import macros
+
+# #18976
+
+macro getString(identifier): string =
+  result = newLit($identifier)
+doAssert getString(abc) == "abc"
+doAssert getString(`a b c`) == "abc"
+
+# #20067
+
+template defaultVal*(value : typed) {.pragma.}
+
+type A = ref object
+  b {.defaultVal: "foo".}: string
+  `$c` {.defaultVal: "bar".}: string
+
+let a = A(b: "a", `$c`: "b")
+
+echo "b.defaultVal = " & a.b.getCustomPragmaVal(defaultVal)
+echo "$c.defaultVal = " & a.`$c`.getCustomPragmaVal(defaultVal)
diff --git a/tests/macros/t20435.nim b/tests/macros/t20435.nim
new file mode 100644
index 000000000..824282198
--- /dev/null
+++ b/tests/macros/t20435.nim
@@ -0,0 +1,30 @@
+
+#[
+  A better test requires matching, so the use of @ working can be showcased
+  For example:
+
+  proc regularCase[T]() = 
+    case [(1, 3), (3, 4)]:
+    of [(1, @a), (_, @b)]:
+      echo a, b
+    else: discard
+]#
+
+{.experimental: "caseStmtMacros".}
+
+import macros
+
+type Foo = object
+
+macro `case`(obj: Foo) = quote do: discard
+
+proc notGeneric() =
+  case Foo()
+  of a b c d: discard
+
+proc generic[T]() =
+  case Foo()
+  of a b c d: discard
+
+notGeneric()
+generic[int]()
diff --git a/tests/macros/t21593.nim b/tests/macros/t21593.nim
new file mode 100644
index 000000000..b0b7ebe75
--- /dev/null
+++ b/tests/macros/t21593.nim
@@ -0,0 +1,13 @@
+discard """
+nimout: '''
+StmtList
+  UIntLit 18446744073709551615
+  IntLit -1'''
+"""
+
+import macros
+
+dumpTree:
+  0xFFFFFFFF_FFFFFFFF'u
+  0xFFFFFFFF_FFFFFFFF
+
diff --git a/tests/macros/t23032_1.nim b/tests/macros/t23032_1.nim
new file mode 100644
index 000000000..4e1707414
--- /dev/null
+++ b/tests/macros/t23032_1.nim
@@ -0,0 +1,19 @@
+import std/macros
+
+type A[T, H] = object
+
+proc `%*`(a: A): bool = true
+proc `%*`[T](a: A[int, T]): bool = false
+
+macro collapse(s: untyped) =
+  result = newStmtList()
+  result.add quote do:
+    doAssert(`s`(A[float, int]()) == true)
+
+macro startHere(n: untyped): untyped =
+  result = newStmtList()
+  let s = n[0]
+  result.add quote do:
+    `s`.collapse()
+
+startHere(`a` %* `b`)
diff --git a/tests/macros/t23032_2.nim b/tests/macros/t23032_2.nim
new file mode 100644
index 000000000..8dde29e10
--- /dev/null
+++ b/tests/macros/t23032_2.nim
@@ -0,0 +1,20 @@
+discard """
+  action: "reject"
+  errormsg: "ambiguous identifier: '%*'"
+"""
+import std/macros
+
+type A[T, H] = object
+
+proc `%*`[T](a: A) = discard
+proc `%*`[T](a: A[int, T]) = discard
+
+macro collapse(s: typed) = discard
+
+macro startHere(n: untyped): untyped =
+  result = newStmtList()
+  let s = n[0]
+  result.add quote do:
+    collapse(`s`.typeof())
+
+startHere(`a` %* `b`)
diff --git a/tests/macros/t23547.nim b/tests/macros/t23547.nim
new file mode 100644
index 000000000..9a2bff9ff
--- /dev/null
+++ b/tests/macros/t23547.nim
@@ -0,0 +1,23 @@
+# https://github.com/nim-lang/Nim/issues/23547
+
+type
+  A[T] = object
+    x: T
+
+proc mulCheckSparse[F](dummy: var A[F], xmulchecksparse: static A[F]) =
+  static:
+    echo "mulCheckSparse: ", typeof(dummy), ", ", typeof(xmulchecksparse) # when generic params not specified: A[system.int], A
+
+template sumImpl(xsumimpl: typed) =
+  static:
+    echo "sumImpl: ", typeof(xsumimpl) # A
+  var a = A[int](x: 55)
+  mulCheckSparse(a, xsumimpl) # fails here
+
+proc sum[T](xsum: static T) =
+  static:
+    echo "sum: ", typeof(xsum) # A[system.int]
+  sumImpl(xsum)
+
+const constA = A[int](x : 100)
+sum[A[int]](constA)
diff --git a/tests/macros/t23784.nim b/tests/macros/t23784.nim
new file mode 100644
index 000000000..31b4544c6
--- /dev/null
+++ b/tests/macros/t23784.nim
@@ -0,0 +1,157 @@
+discard """
+  joinable: false
+"""
+
+
+# debug ICE: genCheckedRecordField
+# apparently after https://github.com/nim-lang/Nim/pull/23477
+
+# bug #23784
+
+import std/bitops, std/macros
+
+# --------------------------------------------------------------
+
+type Algebra = enum
+  BN254_Snarks
+
+type SecretWord* = distinct uint64
+const WordBitWidth* = sizeof(SecretWord) * 8
+
+func wordsRequired*(bits: int): int {.inline.} =
+  const divShiftor = fastLog2(WordBitWidth)
+  result = (bits + WordBitWidth - 1) shr divShiftor
+
+type
+  BigInt*[bits: static int] = object
+    limbs*: array[bits.wordsRequired, SecretWord]  # <--- crash points to here
+
+# --------------------------------------------------------------
+
+const CurveBitWidth = [
+  BN254_Snarks: 254
+]
+
+const BN254_Snarks_Modulus = BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x2, SecretWord 0x3, SecretWord 0x4])
+const BN254_Snarks_Order = BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x1, SecretWord 0x2, SecretWord 0x2])
+
+func montyOne*(M: BigInt[254]): BigInt[254] =
+  ## Returns "1 (mod M)" in the Montgomery domain.
+  ## This is equivalent to R (mod M) in the natural domain
+  BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x1, SecretWord 0x1, SecretWord 0x1])
+
+
+{.experimental: "dynamicBindSym".}
+
+type
+  DerivedConstantMode* = enum
+    kModulus
+    kOrder
+
+macro genDerivedConstants*(mode: static DerivedConstantMode): untyped =
+  ## Generate constants derived from the main constants
+  ##
+  ## For example
+  ## - the Montgomery magic constant "R^2 mod N" in ROM
+  ##   For each curve under the private symbol "MyCurve_R2modP"
+  ## - the Montgomery magic constant -1/P mod 2^Wordbitwidth
+  ##   For each curve under the private symbol "MyCurve_NegInvModWord
+  ## - ...
+
+  # Now typedesc are NimNode and there is no way to translate
+  # NimNode -> typedesc easily so we can't
+  # "for curve in low(Curve) .. high(Curve):"
+  # As an ugly workaround, we count
+  # The item at position 0 is a pragma
+  result = newStmtList()
+
+  template used(name: string): NimNode =
+    nnkPragmaExpr.newTree(
+      ident(name),
+      nnkPragma.newTree(ident"used")
+    )
+
+  let ff = if mode == kModulus: "_Fp" else: "_Fr"
+
+  for curveSym in low(Algebra) .. high(Algebra):
+    let curve = $curveSym
+    let M = if mode == kModulus: bindSym(curve & "_Modulus")
+            else: bindSym(curve & "_Order")
+
+    # const MyCurve_montyOne = montyOne(MyCurve_Modulus)
+    result.add newConstStmt(
+      used(curve & ff & "_MontyOne"), newCall(
+        bindSym"montyOne",
+        M
+      )
+    )
+
+# --------------------------------------------------------------
+
+{.experimental: "dynamicBindSym".}
+
+genDerivedConstants(kModulus)
+genDerivedConstants(kOrder)
+
+proc bindConstant(ff: NimNode, property: string): NimNode =
+  # Need to workaround https://github.com/nim-lang/Nim/issues/14021
+  # which prevents checking if a type FF[Name] = Fp[Name] or Fr[Name]
+  # was instantiated with Fp or Fr.
+  # getTypeInst only returns FF and sameType doesn't work.
+  # so quote do + when checks.
+  let T = getTypeInst(ff)
+  T.expectKind(nnkBracketExpr)
+  doAssert T[0].eqIdent("typedesc")
+
+  let curve =
+    if T[1].kind == nnkBracketExpr: # typedesc[Fp[BLS12_381]] as used internally
+      # doAssert T[1][0].eqIdent"Fp" or T[1][0].eqIdent"Fr", "Found ident: '" & $T[1][0] & "' instead of 'Fp' or 'Fr'"
+      T[1][1].expectKind(nnkIntLit) # static enum are ints in the VM
+      $Algebra(T[1][1].intVal)
+    else: # typedesc[bls12381_fp] alias as used for C exports
+      let T1 = getTypeInst(T[1].getImpl()[2])
+      if T1.kind != nnkBracketExpr or
+         T1[1].kind != nnkIntLit:
+        echo T.repr()
+        echo T1.repr()
+        echo getTypeInst(T1).treerepr()
+        error "getTypeInst didn't return the full instantiation." &
+          " Dealing with types in macros is hard, complain at https://github.com/nim-lang/RFCs/issues/44"
+      $Algebra(T1[1].intVal)
+
+  let curve_fp = bindSym(curve & "_Fp_" & property)
+  let curve_fr = bindSym(curve & "_Fr_" & property)
+  result = quote do:
+    when `ff` is Fp:
+      `curve_fp`
+    elif `ff` is Fr:
+      `curve_fr`
+    else:
+      {.error: "Unreachable, received type: " & $`ff`.}
+
+# --------------------------------------------------------------
+
+template matchingBigInt*(Name: static Algebra): untyped =
+  ## BigInt type necessary to store the prime field Fp
+  # Workaround: https://github.com/nim-lang/Nim/issues/16774
+  # as we cannot do array accesses in type section.
+  # Due to generic sandwiches, it must be exported.
+  BigInt[CurveBitWidth[Name]]
+
+type
+  Fp*[Name: static Algebra] = object
+    mres*: matchingBigInt(Name)
+
+macro getMontyOne*(ff: type Fp): untyped =
+  ## Get one in Montgomery representation (i.e. R mod P)
+  result = bindConstant(ff, "MontyOne")
+
+func getOne*(T: type Fp): T {.noInit, inline.} =
+  result = cast[ptr T](unsafeAddr getMontyOne(T))[]
+
+# --------------------------------------------------------------
+proc foo(T: Fp) =
+  discard T
+
+let a = Fp[BN254_Snarks].getOne()
+foo(a) # oops this was a leftover that broke the bisect.
diff --git a/tests/macros/t7454.nim b/tests/macros/t7454.nim
new file mode 100644
index 000000000..e527de0c3
--- /dev/null
+++ b/tests/macros/t7454.nim
@@ -0,0 +1,8 @@
+discard """
+errormsg: "expression has no type:"
+line: 8
+"""
+
+macro p(t: typedesc): typedesc =
+  discard
+var a: p(int)
diff --git a/tests/macros/t7875.nim b/tests/macros/t7875.nim
new file mode 100644
index 000000000..7b6e47b86
--- /dev/null
+++ b/tests/macros/t7875.nim
@@ -0,0 +1,22 @@
+discard """
+  nimout: "var mysym`gensym0: MyType[float32]"
+  joinable: false
+"""
+
+import macros
+
+type
+  MyType[T] = object
+
+# this is totally fine
+var mysym: MyType[float32]
+
+macro foobar(): untyped =
+  let floatSym = bindSym"float32"
+
+  result = quote do:
+    var mysym: MyType[`floatSym`]
+
+  echo result.repr
+
+foobar()
diff --git a/tests/macros/t8997.nim b/tests/macros/t8997.nim
new file mode 100644
index 000000000..b06223717
--- /dev/null
+++ b/tests/macros/t8997.nim
@@ -0,0 +1,26 @@
+discard """
+  errormsg: "illformed AST: "
+  line: 24
+"""
+
+import macros
+
+type
+  Node* = ref object
+    children: seq[Node]
+
+proc newNode*(): Node =
+  Node(children: newSeq[Node]())
+
+macro build*(body: untyped): untyped =
+
+  template appendElement(tmp, childrenBlock) {.dirty.} =
+    bind newNode
+    let tmp = newNode()
+    tmp.children = childrenBlock  # this line seems to be the problem
+
+  let tmp = genSym(nskLet, "tmp")
+  let childrenBlock = newEmptyNode()
+  result = getAst(appendElement(tmp, childrenBlock))
+
+build(body)
diff --git a/tests/macros/tastrepr.nim b/tests/macros/tastrepr.nim
new file mode 100644
index 000000000..96a37c7a2
--- /dev/null
+++ b/tests/macros/tastrepr.nim
@@ -0,0 +1,58 @@
+discard """
+output: '''
+
+var data = @[(1, "one"), (2, "two")]
+for (i, d) in pairs(data):
+  discard
+for i, d in pairs(data):
+  discard
+for i, (x, y) in pairs(data):
+  discard
+var
+  a = 1
+  b = 2
+type
+  A* = object
+
+var data = @[(1, "one"), (2, "two")]
+for (i, d) in pairs(data):
+  discard
+for i, d in pairs(data):
+  discard
+for i, (x, y) in pairs(data):
+  discard
+var (a, b) = (1, 2)
+type
+  A* = object
+
+var t04 = 1.0'f128
+t04 = 2.0'f128
+'''
+"""
+
+import macros
+
+macro echoTypedRepr(arg: typed) =
+  result = newCall(ident"echo", newLit(arg.repr))
+
+macro echoUntypedRepr(arg: untyped) =
+  result = newCall(ident"echo", newLit(arg.repr))
+
+template echoTypedAndUntypedRepr(arg: untyped) =
+  echoTypedRepr(arg)
+  echoUntypedRepr(arg)
+
+echoTypedAndUntypedRepr:
+  var data = @[(1,"one"), (2,"two")]
+  for (i, d) in pairs(data):
+    discard
+  for i, d in pairs(data):
+    discard
+  for i, (x,y) in pairs(data):
+    discard
+  var (a,b) = (1,2)
+  type A* = object # issue #22933
+
+echoUntypedRepr:
+  var t04 = 1'f128
+  t04 = 2'f128
diff --git a/tests/macros/tbindsym.nim b/tests/macros/tbindsym.nim
new file mode 100644
index 000000000..a493d6a88
--- /dev/null
+++ b/tests/macros/tbindsym.nim
@@ -0,0 +1,67 @@
+discard """
+  nimout: '''initApple
+deinitApple
+Coral
+enum
+  redCoral, blackCoral'''
+  output: '''TFoo
+TBar'''
+"""
+
+# bug #1319
+
+import macros
+
+type
+  TTextKind = enum
+    TFoo, TBar
+
+macro test: untyped =
+  var x = @[TFoo, TBar]
+  result = newStmtList()
+  for i in x:
+    result.add newCall(newIdentNode("echo"),
+      case i
+      of TFoo:
+        bindSym("TFoo")
+      of TBar:
+        bindSym("TBar"))
+
+test()
+
+# issue 7827, bindSym power up
+{.experimental: "dynamicBindSym".}
+type
+  Apple = ref object
+    name: string
+    color: int
+    weight: int
+
+proc initApple(name: string): Apple =
+  discard
+
+proc deinitApple(x: Apple) =
+  discard
+
+macro wrapObject(obj: typed, n: varargs[untyped]): untyped =
+  let m = n[0]
+  for x in m:
+    var z = bindSym x
+    echo z.repr
+
+wrapObject(Apple):
+  initApple
+  deinitApple
+
+type
+  Coral = enum
+    redCoral
+    blackCoral
+
+macro mixer(): untyped =
+  let m = "Co" & "ral"
+  let x = bindSym(m)
+  echo x.repr
+  echo getType(x).repr
+
+mixer()
diff --git a/tests/macros/tcasestmtmacro.nim b/tests/macros/tcasestmtmacro.nim
new file mode 100644
index 000000000..32019a92a
--- /dev/null
+++ b/tests/macros/tcasestmtmacro.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''
+yes
+'''
+"""
+
+import macros
+
+macro `case`(n: tuple): untyped =
+  result = newTree(nnkIfStmt)
+  let selector = n[0]
+  for i in 1 ..< n.len:
+    let it = n[i]
+    case it.kind
+    of nnkElse, nnkElifBranch, nnkElifExpr, nnkElseExpr:
+      result.add it
+    of nnkOfBranch:
+      for j in 0..it.len-2:
+        let cond = newCall("==", selector, it[j])
+        result.add newTree(nnkElifBranch, cond, it[^1])
+    else:
+      error "custom 'case' for tuple cannot handle this node", it
+
+var correct = false
+
+case ("foo", 78)
+of ("foo", 78):
+  correct = true
+  echo "yes"
+of ("bar", 88): echo "no"
+else: discard
+
+doAssert correct
diff --git a/tests/macros/tclosuremacro.nim b/tests/macros/tclosuremacro.nim
new file mode 100644
index 000000000..44c2411a5
--- /dev/null
+++ b/tests/macros/tclosuremacro.nim
@@ -0,0 +1,80 @@
+discard """
+  output: '''
+noReturn
+calling mystuff
+yes
+calling mystuff
+yes
+'''
+"""
+
+import sugar, macros
+
+proc twoParams(x: (int, int) -> int): int =
+  result = x(5, 5)
+
+proc oneParam(x: int -> int): int =
+  x(5)
+
+proc noParams(x: () -> int): int =
+  result = x()
+
+proc noReturn(x: () -> void) =
+  x()
+
+proc doWithOneAndTwo(f: (int, int) -> int): int =
+  f(1,2)
+
+doAssert twoParams(proc (a, b: auto): auto = a + b) == 10
+doAssert twoParams((x, y) => x + y) == 10
+doAssert oneParam(x => x+5) == 10
+doAssert noParams(() => 3) == 3
+doAssert doWithOneAndTwo((x, y) => x + y) == 3
+
+noReturn((() -> void) => echo("noReturn"))
+
+proc pass2(f: (int, int) -> int): (int) -> int =
+  ((x: int) -> int) => f(2, x)
+
+doAssert pass2((x, y) => x + y)(4) == 6
+
+const fun = (x, y: int) {.noSideEffect.} => x + y
+
+doAssert typeof(fun) is (proc (x, y: int): int {.nimcall.})
+doAssert fun(3, 4) == 7
+
+proc register(name: string; x: proc()) =
+  echo "calling ", name
+  x()
+
+register("mystuff", proc () =
+  echo "yes"
+)
+
+proc helper(x: NimNode): NimNode =
+  if x.kind == nnkProcDef:
+    result = copyNimTree(x)
+    result[0] = newEmptyNode()
+    result = newCall("register", newLit($x[0]), result)
+  else:
+    result = copyNimNode(x)
+    for i in 0..<x.len:
+      result.add helper(x[i])
+
+macro m(x: untyped): untyped =
+  result = helper(x)
+
+m:
+  proc mystuff() =
+    echo "yes"
+
+const typedParamAndPragma = (x, y: int) -> int => x + y
+doAssert typedParamAndPragma(1, 2) == 3
+
+type
+  Bot = object
+    call: proc (): string {.noSideEffect.}
+
+var myBot = Bot()
+myBot.call = () {.noSideEffect.} => "I'm a bot."
+doAssert myBot.call() == "I'm a bot."
diff --git a/tests/macros/tcollect.nim b/tests/macros/tcollect.nim
new file mode 100644
index 000000000..ae28ab61b
--- /dev/null
+++ b/tests/macros/tcollect.nim
@@ -0,0 +1,63 @@
+discard """
+  output: '''@[2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4]
+@[0, 1, 2, 3]'''
+"""
+
+const data = [1,2,3,4,5,6]
+
+import macros
+
+macro collect(body): untyped =
+  # analyse the body, find the deepest expression 'it' and replace it via
+  # 'result.add it'
+  let res = genSym(nskVar, "collectResult")
+
+  when false:
+    proc detectForLoopVar(n: NimNode): NimNode =
+      if n.kind == nnkForStmt:
+        result = n[0]
+      else:
+        for x in n:
+          result = detectForLoopVar(x)
+          if result != nil: return result
+        return nil
+
+  proc t(n, res: NimNode): NimNode =
+    case n.kind
+    of nnkStmtList, nnkStmtListExpr, nnkBlockStmt, nnkBlockExpr,
+       nnkWhileStmt,
+       nnkForStmt, nnkIfExpr, nnkIfStmt, nnkTryStmt, nnkCaseStmt,
+       nnkElifBranch, nnkElse, nnkElifExpr:
+      result = copyNimTree(n)
+      if n.len >= 1:
+        result[^1] = t(n[^1], res)
+    else:
+      if true: #n == it:
+        template adder(res, it) =
+          res.add it
+        result = getAst adder(res, n)
+      else:
+        result = n
+
+  when false:
+    let it = detectForLoopVar(body)
+    if it == nil: error("no for loop in body", body)
+
+  let v = newTree(nnkVarSection,
+     newTree(nnkIdentDefs, res, newTree(nnkBracketExpr, bindSym"seq",
+     newCall(bindSym"type", body)), newEmptyNode()))
+
+  result = newTree(nnkStmtListExpr, v, t(body, res), res)
+  #echo repr result
+
+let stuff = collect:
+  var i = -1
+  while i < 4:
+    inc i
+    for it in data:
+      if it < 5 and it > 1:
+        it
+
+echo stuff
+
+echo collect(for i in 0..3: i)
diff --git a/tests/macros/tcomplexecho.nim b/tests/macros/tcomplexecho.nim
new file mode 100644
index 000000000..d58fa561c
--- /dev/null
+++ b/tests/macros/tcomplexecho.nim
@@ -0,0 +1,42 @@
+discard """
+  output: '''3
+OK
+56
+123
+56
+61'''
+"""
+
+import macros
+
+# Bug from the forum
+macro addEcho1(s: untyped): untyped =
+  s.body.add(newCall("echo", newStrLitNode("OK")))
+  result = s
+
+proc f1() {.addEcho1.} =
+  let i = 1+2
+  echo i
+
+f1()
+
+# bug #537
+proc test(): seq[NimNode] {.compiletime.} =
+  result = @[]
+  result.add parseExpr("echo 56")
+  result.add parseExpr("echo 123")
+  result.add parseExpr("echo 56")
+
+proc foo(): seq[NimNode] {.compiletime.} =
+  result = @[]
+  result.add test()
+  result.add parseExpr("echo(5+56)")
+
+macro bar() =
+  result = newNimNode(nnkStmtList)
+  let x = foo()
+  for xx in x:
+    result.add xx
+  echo treeRepr(result)
+
+bar()
diff --git a/tests/macros/tcprag.nim b/tests/macros/tcprag.nim
new file mode 100644
index 000000000..71618883f
--- /dev/null
+++ b/tests/macros/tcprag.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''true
+true
+true
+'''
+"""
+
+# issue #7615
+import macros
+
+template table(name: string) {.pragma.}
+
+type
+   User {.table("tuser").} = object
+      id: int
+      name: string
+      age: int
+
+echo User.hasCustomPragma(table)
+
+
+## crash: Error: internal error: (filename: "sempass2.nim", line: 560, column: 19)
+macro m1(T: typedesc): untyped =
+  getAST hasCustomPragma(T, table)
+echo m1(User) # Oops crash
+
+
+## This works
+macro m2(T: typedesc): untyped =
+  result = quote do:
+    `T`.hasCustomPragma(table)
+echo m2(User)
diff --git a/tests/macros/tdumpast.nim b/tests/macros/tdumpast.nim
new file mode 100644
index 000000000..484b3c2f3
--- /dev/null
+++ b/tests/macros/tdumpast.nim
@@ -0,0 +1,161 @@
+# Dump the contents of a NimNode
+
+import macros
+
+block:
+  template plus(a, b: untyped): untyped {.dirty} =
+    a + b
+
+  macro call(e: untyped): untyped =
+    result = newCall("foo", newStrLitNode("bar"))
+
+  macro dumpAST(n: untyped): string =
+    var msg = ""
+    msg.add "lispRepr:\n" & n.lispRepr & "\n"
+    msg.add "treeRepr:\n" & n.treeRepr & "\n"
+
+    var plusAst = getAst(plus(1, 2))
+    msg.add "lispRepr:\n" & n.lispRepr & "\n"
+
+    var callAst = getAst(call(4))
+    msg.add "callAst.lispRepr:\n" & callAst.lispRepr & "\n"
+
+    var e = parseExpr("foo(bar + baz)")
+    msg.add "e.lispRepr:\n" & e.lispRepr & "\n"
+    result = msg.newLit
+
+  let a = dumpAST:
+    proc add(x, y: int): int =
+      return x + y
+    const foo = 3
+
+  doAssert a == """
+lispRepr:
+(StmtList (ProcDef (Ident "add") (Empty) (Empty) (FormalParams (Ident "int") (IdentDefs (Ident "x") (Ident "y") (Ident "int") (Empty))) (Empty) (Empty) (StmtList (ReturnStmt (Infix (Ident "+") (Ident "x") (Ident "y"))))) (ConstSection (ConstDef (Ident "foo") (Empty) (IntLit 3))))
+treeRepr:
+StmtList
+  ProcDef
+    Ident "add"
+    Empty
+    Empty
+    FormalParams
+      Ident "int"
+      IdentDefs
+        Ident "x"
+        Ident "y"
+        Ident "int"
+        Empty
+    Empty
+    Empty
+    StmtList
+      ReturnStmt
+        Infix
+          Ident "+"
+          Ident "x"
+          Ident "y"
+  ConstSection
+    ConstDef
+      Ident "foo"
+      Empty
+      IntLit 3
+lispRepr:
+(StmtList (ProcDef (Ident "add") (Empty) (Empty) (FormalParams (Ident "int") (IdentDefs (Ident "x") (Ident "y") (Ident "int") (Empty))) (Empty) (Empty) (StmtList (ReturnStmt (Infix (Ident "+") (Ident "x") (Ident "y"))))) (ConstSection (ConstDef (Ident "foo") (Empty) (IntLit 3))))
+callAst.lispRepr:
+(Call (Ident "foo") (StrLit "bar"))
+e.lispRepr:
+(Call (Ident "foo") (Infix (Ident "+") (Ident "bar") (Ident "baz")))
+"""
+
+macro fun() =
+  let n = quote do:
+    1+1 == 2
+  doAssert n.repr == "1 + 1 == 2", n.repr
+fun()
+
+macro fun2(): untyped =
+  let n = quote do:
+    1 + 2 * 3 == 1 + 6
+  doAssert n.repr == "1 + 2 * 3 == 1 + 6", n.repr
+fun2()
+
+macro fun3(): untyped =
+  let n = quote do:
+    int | float | array | seq | object | ptr | pointer | float32
+  doAssert n.repr == "int | float | array | seq | object | ptr | pointer | float32", n.repr
+fun3()
+
+macro fun4() =
+  let n = quote do:
+    (a: 1)
+  doAssert n.repr == "(a: 1)", n.repr
+fun4()
+
+# nkTupleConstr vs nkPar tests:
+block: # lispRepr
+  macro lispRepr2(a: untyped): string = newLit a.lispRepr
+
+  doAssert lispRepr2(()) == """(TupleConstr)"""
+  doAssert lispRepr2((a: 1)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)))"""
+  doAssert lispRepr2((a: 1, b: 2)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)) (ExprColonExpr (Ident "b") (IntLit 2)))"""
+  doAssert lispRepr2((1,)) == """(TupleConstr (IntLit 1))"""
+  doAssert lispRepr2((1, 2)) == """(TupleConstr (IntLit 1) (IntLit 2))"""
+  doAssert lispRepr2((1, 2, 3.0)) == """(TupleConstr (IntLit 1) (IntLit 2) (FloatLit 3.0))"""
+  doAssert lispRepr2((1)) == """(Par (IntLit 1))"""
+  doAssert lispRepr2((1+2)) == """(Par (Infix (Ident "+") (IntLit 1) (IntLit 2)))"""
+
+block: # repr
+  macro repr2(a: untyped): string = newLit a.repr
+
+  doAssert repr2(()) == "()"
+  doAssert repr2((a: 1)) == "(a: 1)"
+  doAssert repr2((a: 1, b: 2)) == "(a: 1, b: 2)"
+  doAssert repr2((1,)) == "(1,)"
+  doAssert repr2((1, 2)) == "(1, 2)"
+  doAssert repr2((1, 2, 3.0)) == "(1, 2, 3.0)"
+  doAssert repr2((1)) == "(1)"
+  doAssert repr2((1+2)) == "(1 + 2)"
+
+block: # treeRepr
+  macro treeRepr2(a: untyped): string = newLit a.treeRepr
+  macro treeRepr3(a: typed): string = newLit a.treeRepr
+
+  doAssert treeRepr2(1+1 == 2) == """
+Infix
+  Ident "=="
+  Infix
+    Ident "+"
+    IntLit 1
+    IntLit 1
+  IntLit 2"""
+
+  proc baz() = discard
+  proc baz(a: int) = discard
+  proc baz(a: float) = discard
+
+  doAssert treeRepr3(baz()) == """
+Call
+  Sym "baz""""
+
+  let a = treeRepr3(block:
+    proc bar(a: auto) = baz())
+  doAssert a == """
+BlockStmt
+  Empty
+  ProcDef
+    Sym "bar"
+    Empty
+    GenericParams
+      Sym "a:type"
+    FormalParams
+      Empty
+      IdentDefs
+        Sym "a"
+        Sym "auto"
+        Empty
+    Empty
+    Bracket
+      Empty
+      Empty
+    StmtList
+      Call
+        OpenSymChoice 3 "baz""""
diff --git a/tests/macros/tdumpast2.nim b/tests/macros/tdumpast2.nim
new file mode 100644
index 000000000..c4c591b2a
--- /dev/null
+++ b/tests/macros/tdumpast2.nim
@@ -0,0 +1,36 @@
+# Dump the contents of a NimNode
+
+import macros
+
+proc dumpit(n: NimNode): string {.compileTime.} =
+  if n == nil: return "nil"
+  result = $n.kind
+  add(result, "(")
+  case n.kind
+  of nnkEmpty: discard # same as nil node in this representation
+  of nnkNilLit:                  add(result, "nil")
+  of nnkCharLit..nnkInt64Lit:    add(result, $n.intVal)
+  of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
+  of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
+  of nnkIdent:                   add(result, $n.ident)
+  of nnkSym, nnkNone:            assert false
+  else:
+    add(result, dumpit(n[0]))
+    for j in 1..n.len-1:
+      add(result, ", ")
+      add(result, dumpit(n[j]))
+  add(result, ")")
+
+macro dumpAST(n): untyped =
+  # dump AST as a side-effect and return the inner node
+  let n = callsite()
+  echo dumpit(n)
+  result = n[1]
+
+dumpAST:
+  proc add(x, y: int): int =
+    return x + y
+
+  proc sub(x, y: int): int = return x - y
+
+
diff --git a/tests/macros/tdumpastgen.nim b/tests/macros/tdumpastgen.nim
new file mode 100644
index 000000000..0e0581f6a
--- /dev/null
+++ b/tests/macros/tdumpastgen.nim
@@ -0,0 +1,45 @@
+discard """
+nimout: '''nnkStmtList.newTree(
+  nnkVarSection.newTree(
+    nnkIdentDefs.newTree(
+      newIdentNode("x"),
+      newEmptyNode(),
+      nnkCall.newTree(
+        nnkDotExpr.newTree(
+          newIdentNode("baz"),
+          newIdentNode("create")
+        ),
+        newLit(56)
+      )
+    )
+  ),
+  nnkProcDef.newTree(
+    newIdentNode("foo"),
+    newEmptyNode(),
+    newEmptyNode(),
+    nnkFormalParams.newTree(
+      newEmptyNode()
+    ),
+    newEmptyNode(),
+    newEmptyNode(),
+    nnkStmtList.newTree(
+      newCommentStmtNode("This is a docstring"),
+      nnkCommand.newTree(
+        newIdentNode("echo"),
+        newLit("bar")
+      )
+    )
+  )
+)'''
+"""
+
+# disabled; can't work as the output is done by the compiler
+
+import macros
+
+dumpAstGen:
+  var x = baz.create(56)
+
+  proc foo() =
+    ## This is a docstring
+    echo "bar"
diff --git a/tests/macros/tdumptree.nim b/tests/macros/tdumptree.nim
new file mode 100644
index 000000000..f540306c4
--- /dev/null
+++ b/tests/macros/tdumptree.nim
@@ -0,0 +1,27 @@
+discard """
+nimout: '''
+StmtList
+  VarSection
+    IdentDefs
+      Ident "x"
+      Empty
+      Call
+        DotExpr
+          Ident "foo"
+          Ident "create"
+        IntLit 56'''
+"""
+
+# disabled; can't work as the output is done by the compiler
+
+import macros
+
+#emit("type\n  TFoo = object\n    bar: int")
+
+#var f: TFoo
+#f.bar = 5
+#echo(f.bar)
+
+dumpTree:
+  var x = foo.create(56)
+
diff --git a/tests/macros/tescape_var_into_quotedo_as_const.nim b/tests/macros/tescape_var_into_quotedo_as_const.nim
new file mode 100644
index 000000000..1ed93f012
--- /dev/null
+++ b/tests/macros/tescape_var_into_quotedo_as_const.nim
@@ -0,0 +1,36 @@
+discard """
+  output: '''ok'''
+"""
+# bug #9864
+import macros, tables
+
+proc bar(shOpt: Table[string, int]) = discard
+
+macro dispatchGen(): untyped =
+  var shOpt = initTable[string, int]()
+  shOpt["foo"] = 10
+  result = quote do:
+     bar(`shOpt`)
+
+dispatchGen()
+
+type
+  Foo = object
+    data: seq[int]
+
+proc barB(a: Foo) = discard
+
+proc shOptB(): auto =
+  var shOpt: Foo
+  shOpt.data.setLen 1 # fails
+  shOpt
+
+macro dispatchGenB(): untyped =
+  var shOpt = shOptB() # fails
+
+  result = quote do:
+     barB(`shOpt`)
+
+dispatchGenB()
+
+echo "ok"
diff --git a/tests/macros/texpectIdent1.nim b/tests/macros/texpectIdent1.nim
new file mode 100644
index 000000000..26e52afb5
--- /dev/null
+++ b/tests/macros/texpectIdent1.nim
@@ -0,0 +1,18 @@
+discard """
+errormsg: "Expected identifier to be `foo` here"
+line: 18
+"""
+
+import macros
+
+macro testUntyped(arg: untyped): void =
+  arg.expectKind nnkStmtList
+  arg.expectLen 2
+  arg[0].expectKind nnkCall
+  arg[0][0].expectIdent "foo"  # must pass
+  arg[1].expectKind nnkCall
+  arg[1][0].expectIdent "foo"  # must fail
+
+testUntyped:
+  foo(123)
+  bar(321)
diff --git a/tests/macros/texpectIdent2.nim b/tests/macros/texpectIdent2.nim
new file mode 100644
index 000000000..887a6ddc3
--- /dev/null
+++ b/tests/macros/texpectIdent2.nim
@@ -0,0 +1,24 @@
+discard """
+errormsg: "Expected identifier to be `foo` here"
+line: 24
+"""
+
+import macros
+
+macro testTyped(arg: typed): void =
+  arg.expectKind nnkStmtList
+  arg.expectLen 2
+  arg[0].expectKind nnkCall
+  arg[0][0].expectIdent "foo"  # must pass
+  arg[1].expectKind nnkCall
+  arg[1][0].expectIdent "foo"  # must fail
+
+proc foo(arg: int) =
+  discard
+
+proc bar(arg: int) =
+  discard
+
+testTyped:
+  foo(123)
+  bar(321)
diff --git a/tests/macros/tfail_parse.nim b/tests/macros/tfail_parse.nim
new file mode 100644
index 000000000..1925f2b69
--- /dev/null
+++ b/tests/macros/tfail_parse.nim
@@ -0,0 +1,15 @@
+discard """
+action: "reject"
+cmd: "nim check $file"
+errormsg: "expected expression, but got multiple statements [ValueError]"
+file: "macros.nim"
+"""
+
+import macros
+static:
+  discard parseStmt("'")
+  discard parseExpr("'")
+  discard parseExpr("""
+proc foo()
+proc foo() = discard
+""")
diff --git a/tests/macros/tforloop_macro1.nim b/tests/macros/tforloop_macro1.nim
new file mode 100644
index 000000000..a8f45c7ac
--- /dev/null
+++ b/tests/macros/tforloop_macro1.nim
@@ -0,0 +1,44 @@
+discard """
+  output: '''0 1
+1 2
+2 3
+0 1
+1 2
+2 3
+0 1
+1 2
+2 3
+3 5'''
+"""
+
+import macros
+
+macro mymacro(): untyped =
+  result = newLit([1, 2, 3])
+
+for a, b in mymacro():
+  echo a, " ", b
+
+macro enumerate(x: ForLoopStmt): untyped =
+  expectKind x, nnkForStmt
+  # we strip off the first for loop variable and use
+  # it as an integer counter:
+  result = newStmtList()
+  result.add newVarStmt(x[0], newLit(0))
+  var body = x[^1]
+  if body.kind != nnkStmtList:
+    body = newTree(nnkStmtList, body)
+  body.add newCall(bindSym"inc", x[0])
+  var newFor = newTree(nnkForStmt)
+  for i in 1..x.len-3:
+    newFor.add x[i]
+  # transform enumerate(X) to 'X'
+  newFor.add x[^2][1]
+  newFor.add body
+  result.add newFor
+
+for a, b in enumerate(items([1, 2, 3])):
+  echo a, " ", b
+
+for a2, b2 in enumerate([1, 2, 3, 5]):
+  echo a2, " ", b2
diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim
new file mode 100644
index 000000000..ab33131b0
--- /dev/null
+++ b/tests/macros/tgetimpl.nim
@@ -0,0 +1,103 @@
+discard """
+  nimout: '''foo = "muhaha"
+proc poo(x, y: int) =
+  let y = x
+  echo ["poo"]'''
+"""
+
+import macros
+
+const
+  foo = "muhaha"
+
+proc poo(x, y: int) =
+  let y = x
+  echo "poo"
+
+macro m(x: typed): untyped =
+  echo repr x.getImpl
+
+m(foo)
+m(poo)
+
+#------------
+
+macro checkOwner(x: typed, check_id: static[int]): untyped =
+  let sym = case check_id:
+    of 0: x
+    of 1: x.getImpl.body[0][0][0]
+    of 2: x.getImpl.body[0][0][^1]
+    of 3: x.getImpl.body[1][0]
+    else: x
+  result = newStrLitNode($sym.owner.symKind)
+
+macro isSameOwner(x, y: typed): untyped =
+  result =
+    if x.owner == y.owner: bindSym"true"
+    else: bindSym"false"
+
+
+static:
+  doAssert checkOwner(foo, 0) == "nskModule"
+  doAssert checkOwner(poo, 0) == "nskModule"
+  doAssert checkOwner(poo, 1) == "nskProc"
+  doAssert checkOwner(poo, 2) == "nskProc"
+  doAssert checkOwner(poo, 3) == "nskModule"
+  doAssert isSameOwner(foo, poo)
+  proc wrappedScope() =
+    proc dummyproc() = discard
+    doAssert isSameOwner(foo, dummyproc) == false
+    doAssert isSameOwner(poo, dummyproc) == false
+  wrappedScope()
+
+macro check_gen_proc(ex: typed): (bool, bool) =
+  let lenChoice = bindsym"len"
+  var is_equal = false 
+  var is_instance_of = false 
+  for child in lenChoice:
+    if not is_equal:
+      is_equal = ex[0] == child
+    if not is_instance_of:
+      is_instance_of = isInstantiationOf(ex[0], child)
+         
+  result = nnkTupleConstr.newTree(newLit(is_equal), newLit(is_instance_of))
+
+# check that len(seq[int]) is not equal to bindSym"len", but is instance of it
+let a = @[1,2,3]
+assert: check_gen_proc(len(a)) == (false, true)
+
+
+#---------------------------------------------------------------
+# issue #16110
+
+macro check(x: type): untyped =
+  let z = getType(x)
+  let y = getImpl(z[1])  
+  var sym = y[0]
+  if sym.kind == nnkPragmaExpr: sym = sym[0]
+  if sym.kind == nnkPostfix: sym = sym[1]
+  expectKind(z[1], nnkSym)
+  expectKind(sym, nnkSym)
+  expectKind(y[2], nnkObjectTy)
+  doAssert(sym == z[1])
+
+type
+  TirePtr = ptr object
+    code: int
+
+  TireRef* = ref object
+    code: int
+
+  TireRef2* {.inheritable.} = ref object
+    code: int
+
+  TireRef3* {.inheritable.} = object
+    code: int
+
+var z1: TirePtr
+check(typeof(z1[]))
+var z2: TireRef
+check(typeof(z2[]))
+var z3: TireRef2
+check(typeof(z3[]))
+check(TireRef3)
diff --git a/tests/macros/tgetraiseslist.nim b/tests/macros/tgetraiseslist.nim
new file mode 100644
index 000000000..79694a66f
--- /dev/null
+++ b/tests/macros/tgetraiseslist.nim
@@ -0,0 +1,29 @@
+discard """
+  nimout: '''##[ValueError, Gen[string]]##
+%%[RootEffect]%%
+true true'''
+"""
+
+import macros
+import std / effecttraits
+
+type
+  Gen[T] = object of CatchableError
+    x: T
+
+macro m(call: typed): untyped =
+  echo "##", repr getRaisesList(call[0]), "##"
+  echo "%%", repr getTagsList(call[0]), "%%"
+  echo isGcSafe(call[0]), " ", hasNoSideEffects(call[0])
+  result = call
+
+proc gutenTag() {.tags: RootEffect.} = discard
+
+proc r(inp: int) =
+  if inp == 0:
+    raise newException(ValueError, "bah")
+  elif inp == 1:
+    raise newException(Gen[string], "bahB")
+  gutenTag()
+
+m r(2)
diff --git a/tests/macros/tgettype.nim b/tests/macros/tgettype.nim
new file mode 100644
index 000000000..d91efe1fe
--- /dev/null
+++ b/tests/macros/tgettype.nim
@@ -0,0 +1,85 @@
+import std/macros
+import stdtest/testutils
+
+# getType
+
+block:
+  type
+    Model = object of RootObj
+    User = object of Model
+      name : string
+      password : string
+
+  macro testUser: string =
+    result = newLit(User.getType.lispRepr)
+
+  macro testGeneric(T: typedesc[Model]): string=
+    result = newLit(T.getType.lispRepr)
+
+  doAssert testUser == """(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password")))"""
+  doAssert User.testGeneric == """(BracketExpr (Sym "typeDesc") (Sym "User"))"""
+
+  macro assertVoid(e: typed): untyped =
+    assert(getTypeInst(e).typeKind == ntyVoid)
+
+  proc voidProc() = discard
+
+  assertVoid voidProc()
+
+block:
+  # refs #18220; not an actual solution (yet) but at least shows what's currently
+  # possible
+
+  type Callable1[R, T, U] = concept fn
+    fn(default(T)) is R
+    fn is U
+
+  # note that typetraits.arity doesn't work
+  macro arity(a: typed): int =
+    # number of params
+    # this is not production code!
+    let a2 = a.getType[1] # this used to crash nim, with: `vmdeps.nim(292, 25) `false``
+    newLit a2.len - 1
+
+  type Callable2[R, T, U] = concept fn
+    fn(default(T)) is R
+    fn is U
+    arity(U) == 2
+
+  proc map1[T, R, U](a: T, fn: Callable1[R, T, U]): R =
+    let fn = U(fn)
+      # `cast[U](fn)` would also work;
+      # this is currently needed otherwise, sigmatch errors with:
+      # Error: attempting to call routine: 'fn'
+      #  found 'fn' [param declared in tgettype.nim(53, 28)]
+      # this can be fixed in future work
+    fn(a)
+
+  proc map2[T, R, U](a: T, fn: Callable2[R, T, U]): R =
+    let fn = U(fn)
+    fn(a)
+
+  proc fn1(a: int, a2 = 'x'): string = $(a, a2, "fn1")
+  proc fn2(a: int, a2 = "zoo"): string = $(a, a2, "fn2")
+  proc fn3(a: int, a2 = "zoo2"): string = $(a, a2, "fn3")
+  proc fn4(a: int): string {.inline.} = $(a, "fn4")
+  proc fn5(a: int): string = $(a, "fn5")
+
+  assertAll:
+    # Callable1
+    1.map1(fn1) == """(1, 'x', "fn1")"""
+    1.map1(fn2) == """(1, "zoo", "fn2")"""
+    1.map1(fn3) == """(1, "zoo", "fn3")"""
+      # fn3's optional param is not honored, because fn3 and fn2 yield same
+      # generic instantiation; this is a caveat with this approach
+      # There are several possible ways to improve things in future work.
+    1.map1(fn4) == """(1, "fn4")"""
+    1.map1(fn5) == """(1, "fn5")"""
+
+    # Callable2; prevents passing procs with optional params to avoid above
+    # mentioned caveat, but more restrictive
+    not compiles(1.map2(fn1))
+    not compiles(1.map2(fn2))
+    not compiles(1.map2(fn3))
+    1.map2(fn4) == """(1, "fn4")"""
+    1.map2(fn5) == """(1, "fn5")"""
diff --git a/tests/macros/tgettype2.nim b/tests/macros/tgettype2.nim
new file mode 100644
index 000000000..c579cf6ff
--- /dev/null
+++ b/tests/macros/tgettype2.nim
@@ -0,0 +1,99 @@
+discard """
+output: '''
+############
+#### gt ####
+############
+gt(Foo):	typeDesc[Foo]
+gt(Bar):	typeDesc[Bar]
+gt(Baz):	typeDesc[int]
+gt(foo):	distinct[int]
+gt(bar):	distinct[int]
+gt(baz):	int, int
+gt(v):	seq[int]
+gt(vv):	seq[float]
+gt(t):	distinct[tuple[int, int]]
+gt(tt):	distinct[tuple[float, float]]
+gt(s):	distinct[tuple[int, int]]
+#############
+#### gt2 ####
+#############
+gt2(Foo): 	Foo
+gt2(Bar): 	Bar
+gt2(Baz): 	Baz
+gt2(foo): 	Foo
+gt2(bar): 	Bar
+gt2(baz): 	Baz
+gt2(v): 	seq[int]
+gt2(vv): 	seq[float]
+gt2(t): 	MyType[system.int]
+gt2(tt): 	MyType[system.float]
+gt2(s): 	MySimpleType
+'''
+"""
+
+import macros, typetraits
+
+type Foo = distinct int
+type Bar = distinct int
+type Baz = int
+
+let foo = 0.Foo
+let bar = 1.Bar
+let baz = 2.Baz
+
+type MyType[T] = distinct tuple[a,b:T]
+type MySimpleType = distinct tuple[a,b: int]
+
+var v: seq[int]
+var vv: seq[float]
+var t: MyType[int]
+var tt: MyType[float]
+var s: MySimpleType
+
+echo "############"
+echo "#### gt ####"
+echo "############"
+
+macro gt(a: typed): string =
+  let b = a.getType
+  var str = "gt(" & $a & "):\t" & b.repr
+  if b.kind == nnkSym: # bad predicat to check weather the type has an implementation
+    str = str & ", " & b.getType.repr  # append the implementation to the result
+  result = newLit(str)
+
+echo gt(Foo) # typeDesc[Foo]
+echo gt(Bar) # typeDesc[Bar]
+echo gt(Baz) # typeDesc[int]     shouldn't it be typeDesc[Baz]?
+echo gt(foo) # distinct[int]     I would prefer Foo, distinct[int]
+echo gt(bar) # distinct[int]     I would prefer Bar, distinct[int]
+echo gt(baz) # int, int          I would prefer Baz, int
+
+echo gt(v)   # seq[int], ok
+echo gt(vv)  # seq[float], ok
+echo gt(t)   # MyType, distinct[tuple[int, int]]      I would prefer MyType[int],   distinct[tuple[int, int]]
+echo gt(tt)  # MyType, distinct[tuple[float, float]]  I would prefer MyType[float], distinct[tuple[int, int]]
+echo gt(s)   # distinct[tuple[int, int]]              I would prefer MySimpleType, distinct[tuple[int,int]]
+
+echo "#############"
+echo "#### gt2 ####"
+echo "#############"
+
+# get type name via typetraits
+
+macro gt2(a: typed): string =
+  let prefix = "gt2(" & $a & "): \t"
+  result = quote do:
+    `prefix` & `a`.type.name
+
+echo gt2(Foo) # Foo  shouldn't this be typeDesc[Foo] ?
+echo gt2(Bar) # Bar  shouldn't this be typeDesc[Bar] ?
+echo gt2(Baz) # Baz  shouldn't this be typeDesc[Baz] ?
+echo gt2(foo) # Foo
+echo gt2(bar) # Bar
+echo gt2(baz) # Baz
+
+echo gt2(v)   # seq[int]
+echo gt2(vv)  # seq[float]
+echo gt2(t)   # MyType[system.int]      why is it system.int and not just int like in seq?
+echo gt2(tt)  # MyType[system.float]    why is it system.float and not just float like in seq?
+echo gt2(s)   # MySimpleType
diff --git a/tests/macros/tgettype3.nim b/tests/macros/tgettype3.nim
new file mode 100644
index 000000000..786d09d8b
--- /dev/null
+++ b/tests/macros/tgettype3.nim
@@ -0,0 +1,48 @@
+discard """
+  output: "vec2"
+"""
+# bug #5131
+
+import macros
+
+type
+    vecBase[I: static[int], T] = distinct array[I, T]
+    vec2* = vecBase[2, float32]
+
+proc isRange(n: NimNode, rangeLen: int = -1): bool =
+    if n.kind == nnkBracketExpr and $(n[0]) == "range":
+        if rangeLen == -1:
+            result = true
+        elif n[2].intVal - n[1].intVal + 1 == rangeLen:
+            result = true
+
+proc getTypeName(t: NimNode, skipVar = false): string =
+    case t.kind
+    of nnkBracketExpr:
+        if $(t[0]) == "array" and t[1].isRange(2) and $(t[2]) == "float32":
+            result = "vec2"
+        elif $(t[0]) == "array" and t[1].isRange(3) and $(t[2]) == "float32":
+            result = "vec3"
+        elif $(t[0]) == "array" and t[1].isRange(4) and $(t[2]) == "float32":
+            result = "vec4"
+        elif $(t[0]) == "distinct":
+            result = getTypeName(t[1], skipVar)
+    of nnkSym:
+        case $t
+        of "vecBase": result = getTypeName(getType(t), skipVar)
+        of "float32": result = "float"
+        else:
+            result = $t
+    of nnkVarTy:
+        result = getTypeName(t[0])
+        if not skipVar:
+            result = "inout " & result
+    else:
+        echo "UNKNOWN TYPE: ", treeRepr(t)
+        assert(false, "Unknown type")
+
+macro typeName(t: typed): string =
+    result = newLit(getTypeName(getType(t)))
+
+var tt : vec2
+echo typeName(tt)
diff --git a/tests/macros/tgettypeinst.nim b/tests/macros/tgettypeinst.nim
new file mode 100644
index 000000000..e722f14aa
--- /dev/null
+++ b/tests/macros/tgettypeinst.nim
@@ -0,0 +1,214 @@
+discard """
+"""
+
+import macros
+
+proc symToIdent(x: NimNode): NimNode =
+  case x.kind:
+    of nnkCharLit..nnkUInt64Lit:
+      result = newNimNode(x.kind)
+      result.intVal = x.intVal
+    of nnkFloatLit..nnkFloat64Lit:
+      result = newNimNode(x.kind)
+      result.floatVal = x.floatVal
+    of nnkStrLit..nnkTripleStrLit:
+      result = newNimNode(x.kind)
+      result.strVal = x.strVal
+    of nnkIdent, nnkSym:
+      result = newIdentNode($x)
+    else:
+      result = newNimNode(x.kind)
+      for c in x:
+        result.add symToIdent(c)
+
+# check getTypeInst and getTypeImpl for given symbol x
+macro testX(x,inst0: typed; recurse: static[bool]; implX: typed) =
+  # check that getTypeInst(x) equals inst0
+  let inst = x.getTypeInst
+  let instr = inst.symToIdent.treeRepr
+  let inst0r = inst0.symToIdent.treeRepr
+  if instr != inst0r:
+    echo "instr:\n", instr
+    echo "inst0r:\n", inst0r
+    doAssert(instr == inst0r)
+
+  # check that getTypeImpl(x) is correct
+  #  if implX is nil then compare to inst0
+  #  else we expect implX to be a type definition
+  #       and we extract the implementation from that
+  let impl = x.getTypeImpl
+  var impl0 =
+    if implX.kind == nnkNilLit: inst0
+    else: implX[0][2]
+  let implr = impl.symToIdent.treerepr
+  let impl0r = impl0.symToIdent.treerepr
+  if implr != impl0r:
+    echo "implr:\n", implr
+    echo "impl0r:\n", impl0r
+    doAssert(implr == impl0r)
+
+  result = newStmtList()
+  #template echoString(s: string) = echo s.replace("\n","\n  ")
+  #result.add getAst(echoString("  " & inst0.repr))
+  #result.add getAst(echoString("  " & inst.repr))
+  #result.add getAst(echoString("  " & impl0.repr))
+  #result.add getAst(echoString("  " & impl.repr))
+
+  if recurse:
+    # now test using a newly formed variable of type getTypeInst(x)
+    template testDecl(n,m: typed) =
+      testV(n, false):
+        type _ = m
+    result.add getAst(testDecl(inst.symToIdent, impl.symToIdent))
+
+# test with a variable (instance) of type
+template testV(inst, recurse, impl) =
+  block:
+    #echo "testV(" & astToStr(inst) & ", " & $recurse & "):" & astToStr(impl)
+    var x: inst
+    testX(x, inst, recurse, impl)
+
+# test with a newly created typedesc (myType)
+# using the passed type as the implementation
+template testT(impl, recurse) =
+  block:
+    type myType = impl
+    testV(myType, recurse):
+      type _ = impl
+
+# test a built-in type whose instance is equal to the implementation
+template test(inst) =
+  testT(inst, false)
+  testV(inst, true, nil)
+
+# test a custom type with provided implementation
+template test(inst, impl) =
+  testV(inst, true, impl)
+
+type
+  Model = object of RootObj
+  User = object of Model
+    name : string
+    password : string
+
+  Tree = object of RootObj
+    value : int
+    left,right : ref Tree
+
+  MyEnum = enum
+    valueA, valueB, valueC
+
+  MySet = set[MyEnum]
+  MySeq = seq[int]
+  MyIntPtr = ptr int
+  MyIntRef = ref int
+
+  GenericObject[T] = object
+    value:T
+  Foo[N:static[int],T] = object
+  Bar[N:static[int],T] = object
+    #baz:Foo[N+1,GenericObject[T]]  # currently fails
+    baz:Foo[N,GenericObject[T]]
+
+  Generic[T] = seq[int]
+  Concrete = Generic[int]
+
+  Generic2[T1, T2] = seq[T1]
+  Concrete2 = Generic2[int, float]
+
+  Alias1 = float
+  Alias2 = Concrete
+  Alias3 = Concrete2
+
+  Vec[N: static[int],T] = object
+    arr: array[N,T]
+  Vec4[T] = Vec[4,T]
+
+
+test(bool)
+test(char)
+test(int)
+test(float)
+test(ptr int)
+test(ref int)
+test(array[1..10,Bar[2,Foo[3,float]]])
+test(array[MyEnum,Bar[2,Foo[3,float]]])
+test(distinct Bar[2,Foo[3,float]])
+test(tuple[a:int,b:Foo[-1,float]])
+test(seq[int])
+test(set[MyEnum])
+test(proc (a: int, b: Foo[2,float]))
+test(proc (a: int, b: Foo[2,float]): Bar[3,int])
+
+test(MyEnum):
+  type _ = enum
+    valueA, valueB, valueC
+test(Bar[2,Foo[3,float]]):
+  type _ = object
+    baz: Foo[2, GenericObject[Foo[3, float]]]
+test(Model):
+  type _ = object of RootObj
+test(User):
+  type _ = object of Model
+    name: string
+    password: string
+test(Tree):
+  type _ = object of RootObj
+    value: int
+    left: ref Tree
+    right: ref Tree
+test(Concrete):
+  type _ = seq[int]
+test(Generic[int]):
+  type _ = seq[int]
+test(Generic[float]):
+  type _ = seq[int]
+test(Concrete2):
+  type _ = seq[int]
+test(Generic2[int,float]):
+  type _ = seq[int]
+test(Alias1):
+  type _ = float
+test(Alias2):
+  type _ = seq[int]
+test(Alias3):
+  type _ = seq[int]
+test(Vec[4,float32]):
+  type _ = object
+    arr: array[0..3,float32]
+test(Vec4[float32]):
+  type _ = object
+    arr: array[0..3,float32]
+
+# bug #4862
+static:
+  discard typedesc[(int, int)].getTypeImpl
+
+# custom pragmas
+template myAttr() {.pragma.}
+template myAttr2() {.pragma.}
+template myAttr3() {.pragma.}
+template serializationKey(key: string) {.pragma.}
+
+type
+  MyObj {.packed,myAttr,serializationKey: "one".} = object
+    myField {.myAttr2,serializationKey: "two".}: int
+    myField2 {.myAttr3,serializationKey: "three".}: float
+
+# field pragmas not currently supported
+test(MyObj):
+  type
+    _ {.packed,myAttr,serializationKey: "one".} = object
+      myField: int
+      myField2: float
+
+block t9600:
+  type
+    Apple = ref object of RootObj
+
+  macro mixer(x: typed): untyped =
+    let w = getType(x)
+    let v = getTypeImpl(w[1])
+
+  var z: Apple
+  mixer(z)
diff --git a/tests/macros/tgettypeinst7737.nim b/tests/macros/tgettypeinst7737.nim
new file mode 100644
index 000000000..e49f82562
--- /dev/null
+++ b/tests/macros/tgettypeinst7737.nim
@@ -0,0 +1,61 @@
+discard """
+  nimout: '''
+seq[int]
+CustomSeq[int]
+'''
+"""
+
+import macros, typetraits, sequtils
+
+block: # issue #7737 original
+  type
+    CustomSeq[T] = object
+      data: seq[T]
+
+  proc getSubType(T: NimNode): NimNode =
+    echo getTypeInst(T).repr
+    result = getTypeInst(T)[1]
+
+  macro typed_helper(x: varargs[typed]): untyped =
+    let foo = getSubType(x[0])
+    result = quote do: discard
+
+  macro untyped_heavylifting(x: varargs[untyped]): untyped =
+    var containers = nnkArgList.newTree()
+    for arg in x:
+      case arg.kind:
+      of nnkInfix:
+        if eqIdent(arg[0], "in"):
+          containers.add arg[2]
+      else:
+        discard
+    result = quote do:
+      typed_helper(`containers`)
+  var a, b, c: seq[int]
+  untyped_heavylifting z in c, x in a, y in b:
+    discard
+  ## The following gives me CustomSeq instead
+  ## of CustomSeq[int] in getTypeInst
+  var u, v, w: CustomSeq[int]
+  untyped_heavylifting z in u, x in v, y in w:
+    discard
+
+block: # issue #7737 comment
+  type
+    CustomSeq[T] = object
+      data: seq[T]
+  # when using just one argument, `foo` and `bar` should be exactly
+  # identical.
+  macro foo(arg: typed): string =
+    result = newLit(arg.getTypeInst.repr)
+  macro bar(args: varargs[typed]): untyped =
+    result = newTree(nnkBracket)
+    for arg in args:
+      result.add newLit(arg.getTypeInst.repr)
+  var
+    a: seq[int]
+    b: CustomSeq[int]
+  doAssert foo(a) == "seq[int]"
+  doAssert bar(a) == ["seq[int]"]
+  doAssert foo(b) == "CustomSeq[int]"
+  doAssert bar(b) == ["CustomSeq[int]"]
diff --git a/tests/macros/tincremental.nim b/tests/macros/tincremental.nim
new file mode 100644
index 000000000..401d6f3f8
--- /dev/null
+++ b/tests/macros/tincremental.nim
@@ -0,0 +1,150 @@
+discard """
+  output: '''heavy_calc_impl is called
+sub_calc1_impl is called
+sub_calc2_impl is called
+** no changes recompute effectively
+** change one input and recompute effectively
+heavy_calc_impl is called
+sub_calc2_impl is called'''
+"""
+
+# sample incremental
+
+import tables
+import macros
+
+var inputs = initTable[string, float]() 
+var cache = initTable[string, float]()
+var dep_tree {.compileTime.} = initTable[string, string]()
+
+macro symHash(s: typed{nkSym}): string = 
+  result = newStrLitNode(symBodyHash(s))
+
+#######################################################################################
+
+template graph_node(key: string) {.pragma.}
+
+proc tag(n: NimNode): NimNode = 
+  ## returns graph node unique name of a function or nil if it is not a graph node
+  expectKind(n, {nnkProcDef, nnkFuncDef})
+  for p in n.pragma:
+    if p.len > 0 and p[0] == bindSym"graph_node":
+      return p[1]
+  return nil 
+
+macro graph_node_key(n: typed{nkSym}): untyped =
+  result = newStrLitNode(n.symBodyHash)
+
+macro graph_discovery(n: typed{nkSym}): untyped =
+  # discovers graph dependency tree and updated dep_tree global var
+  let mytag = newStrLitNode(n.symBodyHash)
+  var visited: seq[NimNode]
+  proc discover(n: NimNode) = 
+    case n.kind:
+      of nnkNone..pred(nnkSym), succ(nnkSym)..nnkNilLit: discard
+      of nnkSym:
+        if n.symKind in {nskFunc, nskProc}:
+          if n notin visited:
+            visited.add n
+            let tag = n.getImpl.tag
+            if tag != nil:
+              dep_tree[tag.strVal] =  mytag.strVal
+            else:
+              discover(n.getImpl.body)
+      else:
+        for child in n:
+          discover(child)
+  discover(n.getImpl.body)
+  result = newEmptyNode()
+
+#######################################################################################
+
+macro incremental_input(key: static[string], n: untyped{nkFuncDef}): untyped =
+  # mark leaf nodes of the graph
+  template getInput(key) {.dirty.} =
+    {.noSideEffect.}:
+      inputs[key]
+  result = n
+  result.pragma = nnkPragma.newTree(nnkCall.newTree(bindSym"graph_node", newStrLitNode(key)))
+  result.body = getAst(getInput(key))
+
+macro incremental(n: untyped{nkFuncDef}): untyped =
+  ## incrementalize side effect free computation
+  ## wraps function into caching layer, mark caching function as a graph_node
+  ## injects dependency discovery between graph nodes
+  template cache_func_body(func_name, func_name_str, func_call) {.dirty.} =
+    {.noSideEffect.}: 
+      graph_discovery(func_name)
+      let key = graph_node_key(func_name)
+      if key in cache:
+        result = cache[key]
+      else:
+        echo func_name_str & " is called"
+        result = func_call
+        cache[key] = result
+
+  let func_name = n.name.strVal & "_impl"
+  let func_call = nnkCall.newTree(ident func_name)
+  for i in 1..<n.params.len:
+    func_call.add n.params[i][0]
+  let cache_func = n.copyNimTree
+  cache_func.body = getAst(cache_func_body(ident func_name, func_name, func_call))
+  cache_func.pragma = nnkPragma.newTree(newCall(bindSym"graph_node", 
+    newCall(bindSym"symHash", ident func_name)))
+  
+  n.name = ident(func_name)
+  result = nnkStmtList.newTree(n, cache_func)
+
+###########################################################################
+### Example
+###########################################################################
+
+func input1(): float {.incremental_input("a1").}
+
+func input2(): float {.incremental_input("a2").}
+
+func sub_calc1(a: float): float  {.incremental.} = 
+  a + input1()
+
+func sub_calc2(b: float): float  {.incremental.} = 
+  b + input2()
+
+func heavy_calc(a: float, b: float): float {.incremental.} = 
+  sub_calc1(a) + sub_calc2(b)
+
+###########################################################################
+## graph finalize and inputs
+###########################################################################
+
+macro finalize_dep_tree(): untyped = 
+  result = nnkTableConstr.newNimNode
+  for key, val in dep_tree:
+    result.add nnkExprColonExpr.newTree(newStrLitNode key, newStrLitNode val)
+  result = nnkCall.newTree(bindSym"toTable", result)
+
+const dep_tree_final = finalize_dep_tree()
+
+proc set_input(key: string, val: float) = 
+  ## set input value
+  ## all affected nodes of graph are invalidated
+  inputs[key] = val
+  var k = key
+  while k != "":
+    k = dep_tree_final.getOrDefault(k , "")
+    cache.del(k)
+
+###########################################################################
+## demo
+###########################################################################
+
+set_input("a1", 5)
+set_input("a2", 2)
+discard heavy_calc(5.0, 10.0)
+
+echo "** no changes recompute effectively"
+discard heavy_calc(5.0, 10.0)
+
+echo "** change one input and recompute effectively"
+
+set_input("a2", 10)
+discard heavy_calc(5.0, 10.0)
diff --git a/tests/macros/tinvalidtypesym.nim b/tests/macros/tinvalidtypesym.nim
new file mode 100644
index 000000000..af6f31d10
--- /dev/null
+++ b/tests/macros/tinvalidtypesym.nim
@@ -0,0 +1,14 @@
+discard """
+errormsg: "type expected, but symbol 'MyType' has no type."
+"""
+
+import macros
+
+macro foobar(name) =
+  let sym = genSym(nskType, "MyType")
+
+  result = quote do:
+    type
+      `name` = `sym`
+
+foobar(MyAlias)
diff --git a/tests/macros/tisexported.nim b/tests/macros/tisexported.nim
new file mode 100644
index 000000000..53766edf5
--- /dev/null
+++ b/tests/macros/tisexported.nim
@@ -0,0 +1,10 @@
+import macros
+
+proc t1* = discard
+proc t2 = discard
+
+macro check(p1: typed, p2: typed) =
+  doAssert isExported(p1) == true
+  doAssert isExported(p2) == false
+
+check t1, t2
diff --git a/tests/macros/tlocktypednode1.nim b/tests/macros/tlocktypednode1.nim
new file mode 100644
index 000000000..f760c7cf1
--- /dev/null
+++ b/tests/macros/tlocktypednode1.nim
@@ -0,0 +1,12 @@
+discard """
+errormsg: "typechecked nodes may not be modified"
+"""
+
+import macros
+
+macro doSomething(arg: typed): untyped =
+  echo arg.treeREpr
+  result = arg
+  result.add newCall(bindSym"echo", newLit(1))
+
+doSomething((echo(1); echo(2)))
diff --git a/tests/macros/tlocktypednode2.nim b/tests/macros/tlocktypednode2.nim
new file mode 100644
index 000000000..e921772b0
--- /dev/null
+++ b/tests/macros/tlocktypednode2.nim
@@ -0,0 +1,12 @@
+discard """
+errormsg: "typechecked nodes may not be modified"
+"""
+
+import macros
+
+macro doSomething(arg: typed): untyped =
+  echo arg.treeREpr
+  result = arg
+  result[0] = newCall(bindSym"echo", newLit(1))
+
+doSomething((echo(1); echo(2)))
diff --git a/tests/macros/tlocktypednode3.nim b/tests/macros/tlocktypednode3.nim
new file mode 100644
index 000000000..0eb9d4467
--- /dev/null
+++ b/tests/macros/tlocktypednode3.nim
@@ -0,0 +1,15 @@
+discard """
+errormsg: "typechecked nodes may not be modified"
+"""
+
+import macros
+
+macro doSomething(arg: typed): untyped =
+  echo arg.treeREpr
+  result = arg
+  result.add(
+    newCall(bindSym"echo", newLit(3)),
+    newCall(bindSym"echo", newLit(1))
+  )
+
+doSomething((echo(1); echo(2)))
diff --git a/tests/macros/tmacro1.nim b/tests/macros/tmacro1.nim
new file mode 100644
index 000000000..18bbeb53d
--- /dev/null
+++ b/tests/macros/tmacro1.nim
@@ -0,0 +1,119 @@
+import  macros
+
+macro test*(a: untyped): untyped =
+  var nodes: tuple[a, b: int]
+  nodes.a = 4
+  nodes[1] = 45
+
+  type
+    TTypeEx = object
+      x, y: int
+      case b: bool
+      of false: nil
+      of true: z: float
+
+  var t: TTypeEx
+  t.b = true
+  t.z = 4.5
+
+
+test:
+  "hi"
+
+
+template assertNot(arg: untyped): untyped =
+  assert(not(arg))
+
+
+proc foo(arg: int): void =
+  discard
+
+proc foo(arg: float): void =
+  discard
+
+static:
+  ## test eqIdent
+  let a = "abc_def"
+  let b = "abcDef"
+  let c = "AbcDef"
+  let d = nnkBracketExpr.newTree() # not an identifier at all
+
+  assert eqIdent(             a ,              b )
+  assert eqIdent(newIdentNode(a),              b )
+  assert eqIdent(             a , newIdentNode(b))
+  assert eqIdent(newIdentNode(a), newIdentNode(b))
+
+  assert eqIdent(               a ,                b )
+  assert eqIdent(genSym(nskLet, a),                b )
+  assert eqIdent(               a , genSym(nskLet, b))
+  assert eqIdent(genSym(nskLet, a), genSym(nskLet, b))
+
+  assert eqIdent(newIdentNode(  a), newIdentNode(  b))
+  assert eqIdent(genSym(nskLet, a), newIdentNode(  b))
+  assert eqIdent(newIdentNode(  a), genSym(nskLet, b))
+  assert eqIdent(genSym(nskLet, a), genSym(nskLet, b))
+
+  assertNot eqIdent(             c ,              b )
+  assertNot eqIdent(newIdentNode(c),              b )
+  assertNot eqIdent(             c , newIdentNode(b))
+  assertNot eqIdent(newIdentNode(c), newIdentNode(b))
+
+  assertNot eqIdent(               c ,                b )
+  assertNot eqIdent(genSym(nskLet, c),                b )
+  assertNot eqIdent(               c , genSym(nskLet, b))
+  assertNot eqIdent(genSym(nskLet, c), genSym(nskLet, b))
+
+  assertNot eqIdent(newIdentNode(  c), newIdentNode(  b))
+  assertNot eqIdent(genSym(nskLet, c), newIdentNode(  b))
+  assertNot eqIdent(newIdentNode(  c), genSym(nskLet, b))
+  assertNot eqIdent(genSym(nskLet, c), genSym(nskLet, b))
+
+  # eqIdent on non identifier at all
+  assertNot eqIdent(a,d)
+
+  # eqIdent on sym choice
+  let fooSym = bindSym"foo"
+  assert fooSym.kind in {nnkOpenSymChoice, nnkClosedSymChoice}
+  assert    fooSym.eqIdent("fOO")
+  assertNot fooSym.eqIdent("bar")
+
+  # eqIdent on exported and backtick quoted identifiers
+  let procName = ident("proc")
+  let quoted = nnkAccQuoted.newTree(procName)
+  let exported = nnkPostfix.newTree(ident"*", procName)
+  let exportedQuoted = nnkPostfix.newTree(ident"*", quoted)
+
+  let nodes = @[procName, quoted, exported, exportedQuoted]
+
+  for i in 0 ..< nodes.len:
+    for j in 0 ..< nodes.len:
+      doAssert eqIdent(nodes[i], nodes[j])
+
+  for node in nodes:
+    doAssert eqIdent(node, "proc")
+
+
+  var empty: NimNode
+  var myLit = newLit("str")
+
+  assert( (empty or myLit) == myLit )
+
+  empty = newEmptyNode()
+
+  assert( (empty or myLit) == myLit )
+
+  proc bottom(): NimNode =
+    quit("may not be evaluated")
+
+  assert( (myLit or bottom()) == myLit )
+
+type
+  Fruit = enum
+    apple
+    banana
+    orange
+
+macro foo(x: typed) =
+  doAssert Fruit(x.intVal) == banana
+
+foo(banana)
diff --git a/tests/macros/tmacro2.nim b/tests/macros/tmacro2.nim
new file mode 100644
index 000000000..1ad63ec8c
--- /dev/null
+++ b/tests/macros/tmacro2.nim
@@ -0,0 +1,36 @@
+discard """
+  output: "ta-da Your value sir: 'HE!!!!o Wor!!d'"
+"""
+
+import macros, strutils
+
+proc testBlock(): string {.compileTime.} =
+  block myBlock:
+    while true:
+      echo "inner block"
+      break myBlock
+    echo "outer block"
+  result = "ta-da"
+
+macro mac(n: typed): string =
+  let n = callsite()
+  expectKind(n, nnkCall)
+  expectLen(n, 2)
+  expectKind(n[1], nnkStrLit)
+  var s: string = n[1].strVal
+  s = s.replace("l", "!!")
+  result = newStrLitNode("Your value sir: '$#'" % [s])
+
+const s = testBlock()
+const t = mac("HEllo World")
+echo s, " ", t
+
+
+#-----------------------------------------------------------------------------
+# issue #15326
+macro m(n:typed):auto =
+  result = n
+
+proc f[T](x:T): T {.m.} = x
+
+discard f(3)
\ No newline at end of file
diff --git a/tests/macros/tmacro3.nim b/tests/macros/tmacro3.nim
new file mode 100644
index 000000000..38e8349e7
--- /dev/null
+++ b/tests/macros/tmacro3.nim
@@ -0,0 +1,30 @@
+discard """
+  output: ""
+"""
+
+import  macros
+
+type
+    TA = tuple[a: int]
+    PA = ref TA
+
+macro test*(a: untyped): untyped =
+  var val: PA
+  new(val)
+  val.a = 4
+
+test:
+  "hi"
+
+macro test2*(a: untyped): untyped =
+  proc testproc(recurse: int) =
+    echo "That's weird"
+    var o : NimNode = nil
+    echo "  no its not!"
+    o = newNimNode(nnkNone)
+    if recurse > 0:
+      testproc(recurse - 1)
+  testproc(5)
+
+test2:
+  "hi"
diff --git a/tests/macros/tmacro4.nim b/tests/macros/tmacro4.nim
new file mode 100644
index 000000000..cb0399894
--- /dev/null
+++ b/tests/macros/tmacro4.nim
@@ -0,0 +1,17 @@
+discard """
+  output: "after"
+"""
+
+import macros
+
+macro test_macro*(s: string, n: untyped): untyped =
+  result = newNimNode(nnkStmtList)
+  var ass : NimNode = newNimNode(nnkAsgn)
+  add(ass, newIdentNode("str"))
+  add(ass, newStrLitNode("after"))
+  add(result, ass)
+when true:
+  var str: string = "before"
+  test_macro(str):
+    var i : integer = 123
+  echo str
diff --git a/tests/macros/tmacro5.nim b/tests/macros/tmacro5.nim
new file mode 100644
index 000000000..802fb28d5
--- /dev/null
+++ b/tests/macros/tmacro5.nim
@@ -0,0 +1,59 @@
+import macros,json
+
+var decls{.compileTime.}: seq[NimNode] = @[]
+var impls{.compileTime.}: seq[NimNode] = @[]
+
+macro importImpl_forward(name, returns: untyped): untyped =
+  result = newNimNode(nnkEmpty)
+  var func_name = newNimNode(nnkAccQuoted)
+  func_name.add newIdentNode("import")
+  func_name.add name
+
+  var res = newNimNode(nnkProcDef)
+  res.add newNimNode(nnkPostfix)
+  res[0].add newIdentNode("*")
+  res[0].add func_name
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkFormalParams)
+  res[3].add returns
+  var p1 = newNimNode(nnkIdentDefs)
+  p1.add newIdentNode("dat")
+  p1.add newIdentNOde("JsonNode")
+  p1.add newNimNode(nnkEmpty)
+  res[3].add p1
+  var p2 = newNimNode(nnkIdentDefs)
+  p2.add newIdentNode("errors")
+  p2.add newNimNode(nnkVarTy)
+  p2.add newNimNode(nnkEmpty)
+  p2[1].add newNimNode(nnkBracketExpr)
+  p2[1][0].add newIdentNode("seq")
+  p2[1][0].add newIdentNode("string")
+  res[3].add p2
+
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkEmpty)
+
+  decls.add res
+  echo(repr(res))
+
+macro importImpl(name, returns, body: untyped) =
+  #var res = getAST(importImpl_forward(name, returns))
+  discard getAST(importImpl_forward(name, returns))
+  var res = copyNimTree(decls[decls.high])
+  res[6] = body
+  echo repr(res)
+  impls.add res
+
+macro okayy() =
+  result = newNimNode(nnkStmtList)
+  for node in decls: result.add node
+  for node in impls: result.add node
+
+importImpl(Item, int):
+  echo 42
+importImpl(Foo, int16):
+  echo 77
+
+okayy
diff --git a/tests/macros/tmacro6.nim b/tests/macros/tmacro6.nim
new file mode 100644
index 000000000..c65d34b6d
--- /dev/null
+++ b/tests/macros/tmacro6.nim
@@ -0,0 +1,75 @@
+discard """
+errormsg: "expression '123' is of type 'int literal(123)' and has to be used (or discarded)"
+line: 71
+"""
+
+import macros
+
+proc foo(a, b, c: int): int =
+  result += a
+  result += b
+  result += c
+
+macro bar(a, b, c: int): int =
+  result = newCall(ident"echo")
+  result.add a
+  result.add b
+  result.add c
+
+macro baz(a, b, c: int): int =
+  let stmt = nnkStmtListExpr.newTree()
+  stmt.add newCall(ident"echo", a)
+  stmt.add newCall(ident"echo", b)
+  stmt.add newCall(ident"echo", c)
+  stmt.add newLit(123)
+  return c
+
+# test no result type with explicit return
+
+macro baz2(a, b, c: int) =
+  let stmt = nnkStmtListExpr.newTree()
+  stmt.add newCall(ident"echo", a)
+  stmt.add newCall(ident"echo", b)
+  stmt.add newCall(ident"echo", c)
+  return stmt
+
+# test explicit void type with explicit return
+
+macro baz3(a, b, c: int): void =
+  let stmt = nnkStmtListExpr.newTree()
+  stmt.add newCall(ident"echo", a)
+  stmt.add newCall(ident"echo", b)
+  stmt.add newCall(ident"echo", c)
+  return stmt
+
+# test no result type with result variable
+
+macro baz4(a, b, c: int) =
+  result = nnkStmtListExpr.newTree()
+  result.add newCall(ident"echo", a)
+  result.add newCall(ident"echo", b)
+  result.add newCall(ident"echo", c)
+
+# test explicit void type with result variable
+
+macro baz5(a, b, c: int): void =
+  let result = nnkStmtListExpr.newTree()
+  result.add newCall(ident"echo", a)
+  result.add newCall(ident"echo", b)
+  result.add newCall(ident"echo", c)
+
+macro foobar1(): int =
+  result = quote do:
+    echo "Hello World"
+    1337
+
+echo foobar1()
+
+# this should create an error message, because 123 has to be discarded.
+
+macro foobar2() =
+  result = quote do:
+    echo "Hello World"
+    123
+
+echo foobar2()
diff --git a/tests/macros/tmacro7.nim b/tests/macros/tmacro7.nim
new file mode 100644
index 000000000..602191506
--- /dev/null
+++ b/tests/macros/tmacro7.nim
@@ -0,0 +1,36 @@
+discard """
+output: '''
+calling!stuff
+calling!stuff
+'''
+disabled: true
+"""
+
+# this test modifies an already semchecked ast (bad things happen)
+# this test relies on the bug #4547
+# issue #7792
+
+import macros
+
+proc callProc(str: string) =
+  echo "calling!" & str
+
+macro testMacro(code: typed): untyped =
+  let stmtList = newNimNode(nnkStmtList)
+
+  let stmts = code[6]
+
+  for n in stmts.children:
+    # the error happens here
+    stmtList.add(newCall(bindSym("callProc"), newLit("stuff")))
+
+  code[6] = stmtList
+
+  result = newEmptyNode()
+
+proc main() {.testMacro.} =
+  echo "test"
+  echo "test2"
+
+when isMainModule:
+  main()
diff --git a/tests/macros/tmacro8.nim b/tests/macros/tmacro8.nim
new file mode 100644
index 000000000..fdcec4dd4
--- /dev/null
+++ b/tests/macros/tmacro8.nim
@@ -0,0 +1,35 @@
+# issue #8573
+
+import
+  macros,
+  strutils,
+  terminal
+
+type LogSeverity* = enum
+  sevError = "Error"
+  sevWarn  = "Warn"
+  sevInfo  = "Info"
+  sevDebug = "Debug"
+
+macro log*(severity: static[LogSeverity], group: static[string], m: varargs[typed]): untyped =
+  let sevStr   = align("[" & toUpperAscii($severity) & "] ", 8)
+  let sevColor = case severity
+    of sevError: fgRed
+    of sevWarn:  fgYellow
+    of sevInfo:  fgWhite
+    of sevDebug: fgBlack
+
+  let groupStr = "[" & $group & "] "
+
+  result = quote do:
+    setStyle({ styleBright })
+    setForegroundColor(sevColor) # <==
+    write(stdout, sevStr)
+
+    setStyle({ styleDim })
+    setForegroundColor(fgWhite)
+    write(stdout, groupStr)
+
+  let wl = newCall(bindSym"styledWriteLine", bindSym"stdout")
+  for arg in m: wl.add(arg)
+  result.add(wl)
diff --git a/tests/macros/tmacroaspragma.nim b/tests/macros/tmacroaspragma.nim
new file mode 100644
index 000000000..5f06f2425
--- /dev/null
+++ b/tests/macros/tmacroaspragma.nim
@@ -0,0 +1,7 @@
+import macros
+
+macro foo(x: untyped): untyped =
+  echo treerepr(callsite())
+  result = newNimNode(nnkStmtList)
+
+proc zoo() {.foo.} = echo "hi"
diff --git a/tests/macros/tmacrogenerics.nim b/tests/macros/tmacrogenerics.nim
new file mode 100644
index 000000000..c31b5564c
--- /dev/null
+++ b/tests/macros/tmacrogenerics.nim
@@ -0,0 +1,38 @@
+discard """
+  nimout: '''
+instantiation 1 with typeDesc[int] and typeDesc[float]
+instantiation 2 with typeDesc[float] and typeDesc[string]
+instantiation 3 with typeDesc[string] and typeDesc[string]
+counter: 3
+'''
+  output: "int\nfloat\nint\nstring"
+"""
+
+import typetraits, macros
+
+var counter {.compileTime.} = 0
+
+macro makeBar(A, B: typedesc): typedesc =
+  inc counter
+  echo "instantiation ", counter, " with ", A.getTypeInst.repr, " and ", B.getTypeInst.repr
+  result = A
+
+type
+  Bar[T, U] = makeBar(T, U)
+
+var bb1: Bar[int, float]
+var bb2: Bar[float, string]
+var bb3: Bar[int, float]
+var bb4: Bar[string, string]
+
+proc match(a: int)    = echo "int"
+proc match(a: string) = echo "string"
+proc match(a: float)  = echo "float"
+
+match(bb1)
+match(bb2)
+match(bb3)
+match(bb4)
+
+static:
+  echo "counter: ", counter
diff --git a/tests/macros/tmacrogensym.nim b/tests/macros/tmacrogensym.nim
new file mode 100644
index 000000000..7c0d75f82
--- /dev/null
+++ b/tests/macros/tmacrogensym.nim
@@ -0,0 +1,65 @@
+import nativesockets, asyncdispatch, macros
+var p = newDispatcher()
+var sock = createAsyncNativeSocket()
+
+proc convertReturns(node, retFutureSym: NimNode): NimNode {.compileTime.} =
+  case node.kind
+  of nnkReturnStmt:
+    result = newCall(newIdentNode("complete"), retFutureSym, node[0])
+  else:
+    result = node
+    for i in 0 ..< node.len:
+      result[i] = convertReturns(node[i], retFutureSym)
+
+macro async2(prc: untyped): untyped =
+  expectKind(prc, nnkProcDef)
+
+  var outerProcBody = newNimNode(nnkStmtList)
+
+  # -> var retFuture = newFuture[T]()
+  var retFutureSym = newIdentNode("retFuture") #genSym(nskVar, "retFuture")
+  outerProcBody.add(
+    newVarStmt(retFutureSym,
+      newCall(
+        newNimNode(nnkBracketExpr).add(
+          newIdentNode("newFuture"),
+          prc[3][0][1])))) # Get type from return type of this proc.
+
+  # -> iterator nameIter(): FutureBase {.closure.} = <proc_body>
+  # Changing this line to: newIdentNode($prc[0].ident & "Iter") # will make it work.
+  var iteratorNameSym = genSym(nskIterator, $prc[0] & "Iter")
+  assert iteratorNameSym.symKind == nskIterator
+  #var iteratorNameSym = newIdentNode($prc[0].ident & "Iter")
+  var procBody = prc[6].convertReturns(retFutureSym)
+
+  var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
+                                procBody, nnkIteratorDef)
+  closureIterator[4] = newNimNode(nnkPragma).add(newIdentNode("closure"))
+  outerProcBody.add(closureIterator)
+
+  # -> var nameIterVar = nameIter
+  # -> var first = nameIterVar()
+  var varNameIterSym = newIdentNode($prc[0] & "IterVar") #genSym(nskVar, $prc[0].ident & "IterVar")
+  var varNameIter = newVarStmt(varNameIterSym, iteratorNameSym)
+  outerProcBody.add varNameIter
+  var varFirstSym = genSym(nskVar, "first")
+  assert varFirstSym.symKind ==  nskVar
+  var varFirst = newVarStmt(varFirstSym, newCall(varNameIterSym))
+  outerProcBody.add varFirst
+
+
+  result = prc
+
+  # Remove the 'closure' pragma.
+  for i in 0 ..< result[4].len:
+    if result[4][i] == newIdentNode("async"):
+      result[4].del(i)
+
+  result[6] = outerProcBody
+
+proc readStuff(): Future[string] {.async2.} =
+  var fut = connect(sock, "irc.freenode.org", Port(6667))
+  yield fut
+  var fut2 = recv(sock, 50)
+  yield fut2
+  return fut2.read
diff --git a/tests/macros/tmacrogetimpl.nim b/tests/macros/tmacrogetimpl.nim
new file mode 100644
index 000000000..1d996ff29
--- /dev/null
+++ b/tests/macros/tmacrogetimpl.nim
@@ -0,0 +1,31 @@
+import macros
+
+# bug #5034
+
+macro copyImpl(srsProc: typed, toSym: untyped) =
+  result = copyNimTree(getImplTransformed(srsProc))
+  result[0] = ident $toSym.toStrLit()
+
+proc foo1(x: float, one: bool = true): float =
+  if one:
+    return 1'f
+  result = x
+
+proc bar1(what: string): string =
+  ## be a little more adversarial with `skResult`
+  proc buzz: string =
+    result = "lightyear"
+  if what == "buzz":
+    result = "buzz " & buzz()
+  else:
+    result = what
+  return result
+
+copyImpl(foo1, foo2)
+doAssert foo1(1'f) == 1.0
+doAssert foo2(10.0, false) == 10.0
+doAssert foo2(10.0) == 1.0
+
+copyImpl(bar1, bar2)
+doAssert bar1("buzz") == "buzz lightyear"
+doAssert bar1("macros") == "macros"
diff --git a/tests/macros/tmacros1.nim b/tests/macros/tmacros1.nim
new file mode 100644
index 000000000..c588ff7e6
--- /dev/null
+++ b/tests/macros/tmacros1.nim
@@ -0,0 +1,81 @@
+discard """
+  output: '''Got: 'nnkCall' hi
+{a}
+{b}
+{a, b}'''
+"""
+
+import macros
+
+macro outterMacro*(n, blck: untyped): untyped =
+  let n = callsite()
+  var j : string = "hi"
+  proc innerProc(i: int): string =
+    echo "Using arg ! " & n.repr
+    result = "Got: '" & $n.kind & "' " & $j
+  var callNode = n[0]
+  expectKind(n, NimNodeKind.nnkCall)
+  if n.len != 3 or n[1].kind != NimNodeKind.nnkIdent:
+    error("Macro " & callNode.repr &
+      " requires the ident passed as parameter (eg: " & callNode.repr &
+      "(the_name_you_want)): statements.")
+  result = newNimNode(NimNodeKind.nnkStmtList)
+  var ass : NimNode = newNimNode(nnkAsgn)
+  ass.add(newIdentNode(n[1].ident))
+  ass.add(newStrLitNode(innerProc(4)))
+  result.add(ass)
+
+var str: string
+outterMacro(str):
+  "hellow"
+echo str
+
+type E = enum a b
+macro enumerators1(): set[E] = newLit({a})
+
+macro enumerators2(): set[E] =
+  return newLit({b})
+
+macro enumerators3(): set[E] =
+  result = newLit({E.low .. E.high})
+
+var myEnums: set[E]
+
+
+myEnums = enumerators1()
+echo myEnums
+myEnums = enumerators2()
+echo myEnums
+myEnums = enumerators3()
+echo myEnums
+
+#10751
+
+type Tuple = tuple
+  a: string
+  b: int
+
+macro foo(t: static Tuple): untyped =
+  doAssert t.a == "foo"
+  doAssert t.b == 12345
+
+foo((a: "foo", b: 12345))
+
+
+# bug #16307
+
+macro bug(x: untyped): string =
+  newLit repr(x)
+
+let res = bug:
+  block:
+    ## one
+    ## two
+    ## three
+
+doAssert res == """
+
+block:
+  ## one
+  ## two
+  ## three"""
diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim
new file mode 100644
index 000000000..a81c51658
--- /dev/null
+++ b/tests/macros/tmacros_issues.nim
@@ -0,0 +1,521 @@
+discard """
+  nimout: '''
+IntLit 5
+proc (x: int): string => typeDesc[proc[string, int]]
+proc (x: int): void => typeDesc[proc[void, int]]
+proc (x: int) => typeDesc[proc[void, int]]
+x => seq[int]
+a
+s
+d
+f
+TTaa
+TTaa
+TTaa
+TTaa
+true
+true
+nil
+42
+false
+true
+@[i0, i1, i2, i3, i4]
+@[tmp, tmp, tmp, tmp, tmp]
+'''
+
+  output: '''
+range[0 .. 100]
+array[0 .. 100, int]
+10
+test
+0o377'i8
+0o000000000755'i32
+1
+2
+3
+foo1
+foo2
+foo3
+true
+false
+true
+false
+1.0
+'''
+"""
+
+
+import macros, parseutils
+
+
+block t7723:
+  macro foo1(): untyped =
+    result = newStmtList()
+    result.add quote do:
+      proc init(foo: int, bar: typedesc[int]): int =
+        foo
+
+  #expandMacros:
+  foo1()
+
+  doAssert init(1, int) == 1
+
+
+
+block t8706:
+  macro varargsLen(args:varargs[untyped]): untyped =
+    doAssert args.kind == nnkArgList
+    doAssert args.len == 0
+    result = newLit(args.len)
+
+  template bar(a0:varargs[untyped]): untyped =
+    varargsLen(a0)
+
+  template foo(x: int, a0:varargs[untyped]): untyped =
+    bar(a0)
+
+  doAssert foo(42) == 0
+  doAssert bar() == 0
+
+
+
+block t9194:
+  type
+    Foo1 = range[0 .. 100]
+    Foo2 = array[0 .. 100, int]
+
+  macro get(T: typedesc): untyped =
+    # Get the X out of typedesc[X]
+    let tmp = getTypeImpl(T)
+    result = newStrLitNode(getTypeImpl(tmp[1]).repr)
+
+  echo Foo1.get
+  echo Foo2.get
+
+
+
+block t1944:
+  template t(e: untyped): untyped =
+    macro m(eNode: untyped): untyped =
+      echo eNode.treeRepr
+    m e
+
+  t 5
+
+
+block t926:
+  proc test(f: var NimNode) {.compileTime.} =
+    f = newNimNode(nnkStmtList)
+    f.add newCall(newIdentNode("echo"), newLit(10))
+
+  macro blah(prc: untyped): untyped =
+    result = prc
+    test(result)
+
+  proc test() {.blah.} =
+    echo 5
+
+
+
+block t2211:
+  macro showType(t:typed): untyped =
+    let ty = t.getType
+    echo t.repr, " => ", ty.repr
+
+  showType(proc(x:int): string)
+  showType(proc(x:int): void)
+  showType(proc(x:int))
+
+  var x: seq[int]
+  showType(x)
+
+
+
+block t1140:
+  proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =
+    var splitValue: string
+    var read = value.parseUntil(splitValue, '$', index)
+
+    # when false:
+    if false:
+        var identifier: string
+        read = value.parseWhile(identifier, {}, index)
+        node.add newCall("add", ident("result"), newCall("$", ident(identifier)))
+
+    if splitValue.len > 0:
+        node.insert node.len, newCall("add", ident("result"), newStrLitNode(splitValue))
+
+  proc parse_template(node: NimNode, value: string) {.compiletime.} =
+      var index = 0
+      while index < value.len and
+          parse_until_symbol(node, value, index): discard
+
+  macro tmpli(body: untyped): typed =
+      result = newStmtList()
+      result.add parseExpr("result = \"\"")
+      result.parse_template body[1].strVal
+
+
+  proc actual: string {.used.} = tmpli html"""
+      <p>Test!</p>
+      """
+
+  proc another: string {.used.} = tmpli html"""
+      <p>what</p>
+      """
+
+
+
+block tbugs:
+  type
+    Foo = object
+      s: char
+
+  iterator test2(f: string): Foo =
+    for i in f:
+      yield Foo(s: i)
+
+  macro test(): untyped =
+    for i in test2("asdf"):
+      echo i.s
+
+  test()
+
+
+  # bug 1297
+
+  type TType = tuple[s: string]
+
+  macro echotest(): untyped =
+    var t: TType
+    t.s = ""
+    t.s.add("test")
+    result = newCall(newIdentNode("echo"), newStrLitNode(t.s))
+
+  echotest()
+
+  # bug #1103
+
+  type
+      Td = tuple
+          a:string
+          b:int
+
+  proc get_data(d: Td) : string {.compileTime.} =
+      result = d.a # Works if a literal string is used here.
+      # Bugs if line A or B is active. Works with C
+      result &= "aa"          # A
+      #result.add("aa")       # B
+      #result = result & "aa" # C
+
+  macro m(s:static[Td]) : untyped =
+      echo get_data(s)
+      echo get_data(s)
+      result = newEmptyNode()
+
+  const s = ("TT", 3)
+  m(s)
+  m(s)
+
+  # bug #933
+
+  proc nilcheck(): NimNode {.compileTime.} =
+    echo(result == nil) # true
+    echo(result.isNil) # true
+    echo(repr(result)) # nil
+
+  macro testnilcheck(): untyped =
+    result = newNimNode(nnkStmtList)
+    discard nilcheck()
+
+  testnilcheck()
+
+  # bug #1323
+
+  proc calc(): array[1, int] =
+    result[0].inc()
+    result[0].inc()
+
+  const c = calc()
+  doAssert c[0] == 2
+
+
+  # bug #3046
+
+  macro sampleMacroInt(i: int): untyped =
+    echo i.intVal
+
+  macro sampleMacroBool(b: bool): untyped =
+    echo b.boolVal
+
+  sampleMacroInt(42)
+  sampleMacroBool(false)
+  sampleMacroBool(system.true)
+
+
+# bug #11131
+macro toRendererBug(n): untyped =
+  result = newLit repr(n)
+
+echo toRendererBug(0o377'i8)
+echo toRendererBug(0o755'i32)
+
+# bug #12129
+macro foobar() =
+  var loopVars = newSeq[NimNode](5)
+  for i, sym in loopVars.mpairs():
+    sym = ident("i" & $i)
+  echo loopVars
+  for sym in loopVars.mitems():
+    sym = ident("tmp")
+  echo loopVars
+
+foobar()
+
+
+# bug #13253
+import macros
+
+type
+  FooBar = object
+    a: seq[int]
+
+macro genFoobar(a: static FooBar): untyped =
+  result = newStmtList()
+  for b in a.a:
+    result.add(newCall(bindSym"echo", newLit b))
+
+proc foobar(a: static FooBar) =
+  genFoobar(a)  # removing this make it work
+  for b in a.a:
+    echo "foo" & $b
+
+proc main() =
+  const a: seq[int] = @[1, 2,3]
+  # Error: type mismatch: got <array[0..2, int]> but expected 'seq[int]'
+  const fb = Foobar(a: a)
+  foobar(fb)
+main()
+
+# bug #13484
+
+proc defForward(id, nid: NimNode): NimNode =
+  result = newProc(id, @[newIdentNode("bool"), newIdentDefs(nid, newIdentNode("int"))], body=newEmptyNode())
+
+proc defEven(evenid, oddid, nid: NimNode): NimNode =
+  result = quote do:
+    proc `evenid`(`nid`: int): bool =
+      if `nid` == 0:
+        return true
+      else:
+        return `oddid`(`nid` - 1)
+
+proc defOdd(evenid, oddid, nid: NimNode): NimNode =
+  result = quote do:
+    proc `oddid`(`nid`: int): bool =
+      if `nid` == 0:
+        return false
+      else:
+        return `evenid`(`nid` - 1)
+
+proc callNode(funid, param: NimNode): NimNode =
+  result = quote do:
+    `funid`(`param`)
+
+macro testEvenOdd3(): untyped =
+  let
+    evenid = newIdentNode("even3")
+    oddid = newIdentNode("odd3")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+macro testEvenOdd4(): untyped =
+  let
+    evenid = newIdentNode("even4")
+    oddid = newIdentNode("odd4")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  # rewrite the body of proc node.
+  oddForward[6] = newStmtList()
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+macro testEvenOdd5(): untyped =
+  let
+    evenid = genSym(nskProc, "even5")
+    oddid = genSym(nskProc, "odd5")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+macro testEvenOdd6(): untyped =
+  let
+    evenid = genSym(nskProc, "even6")
+    oddid = genSym(nskProc, "odd6")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  # rewrite the body of proc node.
+  oddForward[6] = newStmtList()
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+# it works
+testEvenOdd3()
+
+# it causes an error (redefinition of odd4), which is correct
+assert not compiles testEvenOdd4()
+
+# it caused an error (still forwarded: odd5)
+testEvenOdd5()
+
+# it works, because the forward decl and definition share the symbol and the compiler is forgiving here
+#testEvenOdd6() #Don't test it though, the compiler may become more strict in the future
+
+# bug #15385
+var captured_funcs {.compileTime.}: seq[NimNode] = @[]
+
+macro aad*(fns: varargs[typed]): typed =
+  result = newStmtList()
+  for fn in fns:
+    captured_funcs.add fn[0]
+    result.add fn
+
+func exp*(x: float): float ## get different error if you remove forward declaration
+
+func exp*(x: float): float {.aad.} =
+  var x1 = min(max(x, -708.4), 709.8)
+  var result: float   ## looks weird because it is taken from template expansion
+  result = x1 + 1.0
+  result
+
+template check_accuracy(f: untyped, rng: Slice[float], n: int, verbose = false): auto =
+
+  proc check_accuracy: tuple[avg_ulp: float, max_ulp: int] {.gensym.} =
+    let k = (rng.b - rng.a) / (float) n
+    var
+      res, x: float
+      i, max_ulp = 0
+      avg_ulp = 0.0
+
+    x = rng.a
+    while (i < n):
+      res = f(x)
+      i.inc
+      x = x + 0.001
+    (avg_ulp, max_ulp)
+  check_accuracy()
+
+discard check_accuracy(exp, -730.0..709.4, 4)
+
+# And without forward decl
+macro aad2*(fns: varargs[typed]): typed =
+  result = newStmtList()
+  for fn in fns:
+    captured_funcs.add fn[0]
+    result.add fn
+
+func exp2*(x: float): float {.aad2.} =
+  var x1 = min(max(x, -708.4), 709.8)
+  var result: float   ## looks weird because it is taken from template expansion
+  result = x1 + 1.0
+  result
+
+template check_accuracy2(f: untyped, rng: Slice[float], n: int, verbose = false): auto =
+
+  proc check_accuracy2: tuple[avg_ulp: float, max_ulp: int] {.gensym.} =
+    let k = (rng.b - rng.a) / (float) n
+    var
+      res, x: float
+      i, max_ulp = 0
+      avg_ulp = 0.0
+
+    x = rng.a
+    while (i < n):
+      res = f(x)
+      i.inc
+      x = x + 0.001
+    (avg_ulp, max_ulp)
+  check_accuracy2()
+
+discard check_accuracy2(exp2, -730.0..709.4, 4)
+
+# And minimized:
+macro aadMin(fn: typed): typed = fn
+
+func expMin: float
+
+func expMin: float {.aadMin.} = 1
+
+echo expMin()
+
+
+# doubly-typed forward decls
+macro noop(x: typed) = x
+noop:
+  proc cally() = discard
+
+cally()
+
+noop:
+  proc barry()
+
+proc barry() = discard
+
+# some more:
+proc barry2() {.noop.}
+proc barry2() = discard
+
+proc barry3() {.noop.}
+proc barry3() {.noop.} = discard
+
+
+# issue #15389
+block double_sem_for_procs:
+
+  macro aad(fns: varargs[typed]): typed =
+    result = newStmtList()
+    for fn in fns:
+      result.add fn
+
+  func exp(x: float): float {.aad.} =
+    var x1 = min(max(x, -708.4), 709.8)
+    if x1 > 0.0:
+      return x1 + 1.0
+    result = 10.0
+
+  discard exp(5.0)
diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim
new file mode 100644
index 000000000..e351b4527
--- /dev/null
+++ b/tests/macros/tmacros_various.nim
@@ -0,0 +1,391 @@
+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
diff --git a/tests/macros/tmacrostmt.nim b/tests/macros/tmacrostmt.nim
new file mode 100644
index 000000000..817bc8352
--- /dev/null
+++ b/tests/macros/tmacrostmt.nim
@@ -0,0 +1,155 @@
+import macros
+macro case_token(n: varargs[untyped]): untyped =
+  # creates a lexical analyzer from regular expressions
+  # ... (implementation is an exercise for the reader :-)
+  nil
+
+case_token: # this colon tells the parser it is a macro statement
+of r"[A-Za-z_]+[A-Za-z_0-9]*":
+  return tkIdentifier
+of r"0-9+":
+  return tkInteger
+of r"[\+\-\*\?]+":
+  return tkOperator
+else:
+  return tkUnknown
+
+case_token: inc i
+
+#bug #488
+
+macro foo() =
+  var exp = newCall("whatwhat", newIntLitNode(1))
+  if compiles(getAst(exp)):
+    return exp
+  else: echo "Does not compute! (test OK)"
+
+foo()
+
+#------------------------------------
+# bug #8287
+type MyString = distinct string
+
+proc `$` (c: MyString): string {.borrow.}
+
+proc `!!` (c: cstring): int =
+  c.len
+
+proc f(name: MyString): int =
+  !! $ name
+
+macro repr_and_parse(fn: typed) =
+  let fn_impl = fn.getImpl
+  fn_impl.name = genSym(nskProc, $fn_impl.name)
+  echo fn_impl.repr
+  result = parseStmt(fn_impl.repr)
+
+macro repr_to_string(fn: typed): string =
+  let fn_impl = fn.getImpl
+  result = newStrLitNode(fn_impl.repr)
+
+repr_and_parse(f)
+
+
+#------------------------------------
+# bugs #8343 and #8344
+proc one_if_proc(x, y : int): int =
+  if x < y: result = x
+  else: result = y
+
+proc test_block(x, y : int): int =
+  block label:
+    result = x
+    result = y
+
+#------------------------------------
+# bugs #8348
+
+template `>`(x, y: untyped): untyped =
+  ## "is greater" operator. This is the same as ``y < x``.
+  y < x
+
+proc test_cond_stmtlist(x, y: int): int =
+  result = x
+  if x > y:
+    result = x
+
+
+#------------------------------------
+# bug #8762
+proc t2(a, b: int): int =
+  `+`(a, b)
+
+
+#------------------------------------
+# bug #8761
+
+proc fn1(x, y: int):int =
+  2 * (x + y)
+
+proc fn2(x, y: float): float =
+  (y + 2 * x) / (x - y)
+
+proc fn3(x, y: int): bool =
+  (((x and 3) div 4) or (x mod (y xor -1))) == 0 or y notin [1,2]
+
+proc fn4(x: int): int =
+  if x mod 2 == 0: return x + 2
+  else: return 0
+
+proc fn5(a, b: float): float =
+  result = - a * a / (b * b)
+
+proc `{}`(x: seq[float], i: int, j: int): float = 
+  x[i + 0 * j]
+
+proc `{}=`(x: var seq[float], i: int, val: float) = 
+  x[i] = val
+
+proc fn6() =
+  var a = @[1.0, 2.0]
+  let z = a{0, 1} 
+  a{2} = 5.0
+
+
+#------------------------------------
+# bug #10807
+proc fn_unsafeaddr(x: int): int =
+  cast[int](unsafeAddr(x))
+
+static:
+  let fn1s = "proc fn1(x, y: int): int =\n  result = 2 * (x + y)\n"
+  let fn2s = "proc fn2(x, y: float): float =\n  result = (y + 2 * x) / (x - y)\n"
+  let fn3s = "proc fn3(x, y: int): bool =\n  result = ((x and 3) div 4 or x mod (y xor -1)) == 0 or not contains([1, 2], y)\n"
+  let fn4s = "proc fn4(x: int): int =\n  if x mod 2 == 0:\n    return x + 2\n  else:\n    return 0\n"
+  let fn5s = "proc fn5(a, b: float): float =\n  result = -a * a / (b * b)\n"
+  let fn6s = "proc fn6() =\n  var a = @[1.0, 2.0]\n  let z = a{0, 1}\n  a{2} = 5.0\n"
+  let fnAddr = "proc fn_unsafeaddr(x: int): int =\n  result = cast[int](addr(x))\n"
+
+  doAssert fn1.repr_to_string == fn1s
+  doAssert fn2.repr_to_string == fn2s
+  doAssert fn3.repr_to_string == fn3s
+  doAssert fn4.repr_to_string == fn4s
+  doAssert fn5.repr_to_string == fn5s
+  doAssert fn6.repr_to_string == fn6s
+  doAssert fn_unsafeaddr.repr_to_string == fnAddr
+
+#------------------------------------
+# bug #8763
+
+type
+  A {.pure.} = enum
+    X, Y
+  B {.pure.} = enum
+    X, Y
+
+proc test_pure_enums(a: B) =
+  case a
+    of B.X: echo B.X
+    of B.Y: echo B.Y
+
+repr_and_parse(one_if_proc)
+repr_and_parse(test_block)
+repr_and_parse(test_cond_stmtlist)
+repr_and_parse(t2)
+repr_and_parse(test_pure_enums)
diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim
new file mode 100644
index 000000000..13b421303
--- /dev/null
+++ b/tests/macros/tmacrotypes.nim
@@ -0,0 +1,157 @@
+discard """
+  nimout: '''intProc; ntyProc; proc[int, int, float]; proc (a: int; b: float): int {.nimcall.}
+void; ntyVoid; void; void
+int; ntyInt; int; int
+proc () {.nimcall.}; ntyProc; proc[void]; proc () {.nimcall.}
+voidProc; ntyProc; proc[void]; proc () {.nimcall.}
+listing fields for ObjType
+a: string
+b: int
+listing fields for ObjRef
+skipping ref type
+a: string
+b: int
+listing fields for RefType
+skipping ref type
+a: int
+b: float
+listing fields for typeof(a)
+skipping ref type
+a: string
+b: int
+listing fields for typeof(b)
+skipping ref type
+a: string
+b: int
+listing fields for typeof(c)
+skipping ref type
+a: int
+b: float
+listing fields for typeof(x)
+a: string
+b: int
+listing fields for typeof(x)
+a: int
+b: float
+typeDesc[range[1 .. 5]]; ntyTypeDesc; typeDesc[range[1, 5]]; typeDesc[range[1 .. 5]]
+typeDesc[range]; ntyTypeDesc; typeDesc[range[T]]; typeDesc[range]'''
+"""
+
+import macros, typetraits
+
+macro checkType(ex: typed): untyped =
+  echo ex.getTypeInst.repr, "; ", ex.typeKind, "; ", ex.getType.repr, "; ", ex.getTypeImpl.repr
+
+macro checkProcType(fn: typed): untyped =
+  if fn.kind == nnkProcDef:
+    result = fn
+  let fn_sym = if fn.kind == nnkProcDef: fn[0] else: fn
+  echo fn_sym, "; ", fn_sym.typeKind, "; ", fn_sym.getType.repr, "; ", fn_sym.getTypeImpl.repr
+
+proc voidProc = echo "hello"
+proc intProc(a: int, b: float): int {.checkProcType.} = 10
+
+checkType(voidProc())
+checkType(intProc(10, 20.0))
+checkType(voidProc)
+checkProcType(voidProc)
+
+macro listFields(T: typed) =
+  echo "listing fields for ", repr(T)
+  let inputExprType = getType(T)
+
+  var objType = inputExprType[1]
+  if objType.kind == nnkBracketExpr and objType.len > 1:
+    if ((objType[0].kind == nnkRefTy) or
+        (objType[0].kind == nnkSym and eqIdent(objType[0], "ref"))):
+      echo "skipping ref type"
+      objType = objType[1]
+
+  let typeAst = objType.getImpl
+
+  var objectDef = typeAst[2]
+  if objectDef.kind == nnkRefTy:
+    objectDef = objectDef[0]
+
+  let recList = objectDef[2]
+  for rec in recList:
+    echo $rec[0], ": ", $rec[1]
+
+type
+  ObjType* = object of RootObj
+    a: string
+    b: int
+
+  ObjRef = ref ObjType
+
+  RefType* = ref object of RootObj
+    a: int
+    b: float
+
+listFields ObjType
+listFields ObjRef
+listFields RefType
+
+let
+  a = new ObjType
+  b = new ObjRef
+  c = new RefType
+
+listFields typeOf(a)
+listFields typeOf(b)
+listFields typeOf(c)
+
+proc genericProc(x: object) =
+  listFields typeOf(x)
+
+genericProc a[]
+genericProc b[]
+genericProc c[]
+
+# bug #10548
+block:
+  var c {.compileTime.} = 0
+
+  macro meshImpl(arg: typed): untyped =
+    inc c
+    result = arg
+
+  type
+    Blub = int32
+    Mesh = meshImpl(Club)
+    Club = Blub
+
+  static: doAssert(c == 1)
+
+# bug #10702
+type
+  VectorElementType = SomeNumber | bool
+  Vec*[N : static[int], T: VectorElementType] = object
+    arr*: array[N, T]
+
+type
+  Vec4*[T: VectorElementType] = Vec[4,T]
+  Vec3*[T: VectorElementType] = Vec[3,T]
+  Vec2*[T: VectorElementType] = Vec[2,T]
+
+template vecGen(U:untyped,V:typed):typed=
+  ## ``U`` suffix
+  ## ``V`` valType
+  ##
+  type
+    `Vec2 U`* {.inject.} = Vec2[V]
+    `Vec3 U`* {.inject.} = Vec3[V]
+    `Vec4 U`* {.inject.} = Vec4[V]
+
+vecGen(f, float32)
+
+macro foobar(arg: typed): untyped =
+  let typ = arg.getTypeInst
+  doAssert typ.getImpl[^1].kind == nnkCall
+
+var x: Vec2f
+
+foobar(x)
+
+checkType(range[1..5])
+checkType(range)
diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim
new file mode 100644
index 000000000..6c9f9f935
--- /dev/null
+++ b/tests/macros/tmemit.nim
@@ -0,0 +1,38 @@
+discard """
+  output: '''
+c_func
+12
+'''
+"""
+
+import macros, strutils
+
+# bug #1025
+
+macro foo(icname): untyped =
+  let ic = newStrLitNode($icname)
+  result = quote do:
+    proc x* =
+      proc private {.exportc: `ic`.} = discard
+      echo `ic`
+      private()
+
+foo(c_func)
+x()
+
+
+template volatileLoad[T](x: ptr T): T =
+  var res: T
+  {.emit: [res, " = (*(", type(x[]), " volatile*)", x, ");"].}
+  res
+
+template volatileStore[T](x: ptr T; y: T) =
+  {.emit: ["*((", type(x[]), " volatile*)(", x, ")) = ", y, ";"].}
+
+proc main =
+  var st: int
+  var foo: ptr int = addr st
+  volatileStore(foo, 12)
+  echo volatileLoad(foo)
+
+main()
diff --git a/tests/macros/tmsginfo.nim b/tests/macros/tmsginfo.nim
new file mode 100644
index 000000000..f08a231fb
--- /dev/null
+++ b/tests/macros/tmsginfo.nim
@@ -0,0 +1,24 @@
+discard """
+  nimout: '''tmsginfo.nim(21, 1) Warning: foo1 [User]
+tmsginfo.nim(22, 13) template/generic instantiation of `foo2` from here
+tmsginfo.nim(15, 10) Warning: foo2 [User]
+tmsginfo.nim(23, 1) Hint: foo3 [User]
+tmsginfo.nim(19, 7) Hint: foo4 [User]
+'''
+"""
+
+import macros
+
+macro foo1(y: untyped): untyped =
+  warning("foo1", y)
+macro foo2(y: untyped): untyped =
+  warning("foo2")
+macro foo3(y: untyped): untyped =
+  hint("foo3", y)
+macro foo4(y: untyped): untyped =
+  hint("foo4")
+
+proc x1() {.foo1.} = discard
+proc x2() {.foo2.} = discard
+proc x3() {.foo3.} = discard
+proc x4() {.foo4.} = discard
diff --git a/tests/macros/tnewlit.nim b/tests/macros/tnewlit.nim
new file mode 100644
index 000000000..70683f880
--- /dev/null
+++ b/tests/macros/tnewlit.nim
@@ -0,0 +1,194 @@
+import macros
+
+type
+  MyType = object
+    a : int
+    b : string
+
+  RefObject = ref object
+    x: int
+
+  RegularObject = object
+    x: int
+
+  ObjectRefAlias = ref RegularObject
+
+macro test_newLit_MyType: untyped =
+  let mt = MyType(a: 123, b:"foobar")
+  result = newLit(mt)
+
+doAssert test_newLit_MyType == MyType(a: 123, b:"foobar")
+
+macro test_newLit_array: untyped =
+  let arr = [1,2,3,4,5]
+  result = newLit(arr)
+
+doAssert test_newLit_array == [1,2,3,4,5]
+
+macro test_newLit_seq_int: untyped =
+  let s: seq[int] = @[1,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int] = test_newLit_seq_int
+  doAssert tmp == @[1,2,3,4,5]
+
+macro test_newLit_seq_int8: untyped =
+  let s: seq[int8] = @[1'i8,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int8] = test_newLit_seq_int8
+  doAssert tmp == @[1'i8,2,3,4,5]
+
+macro test_newLit_seq_int16: untyped =
+  let s: seq[int16] = @[1'i16,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int16] = test_newLit_seq_int16
+  doAssert tmp == @[1'i16,2,3,4,5]
+
+macro test_newLit_seq_int32: untyped =
+  let s: seq[int32] = @[1'i32,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int32] = test_newLit_seq_int32
+  doAssert tmp == @[1'i32,2,3,4,5]
+
+macro test_newLit_seq_int64: untyped =
+  let s: seq[int64] = @[1'i64,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int64] = test_newLit_seq_int64
+  doAssert tmp == @[1'i64,2,3,4,5]
+
+macro test_newLit_seq_uint: untyped =
+  let s: seq[uint] = @[1u,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint] = test_newLit_seq_uint
+  doAssert tmp == @[1u,2,3,4,5]
+
+macro test_newLit_seq_uint8: untyped =
+  let s: seq[uint8] = @[1'u8,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint8] = test_newLit_seq_uint8
+  doAssert tmp == @[1'u8,2,3,4,5]
+
+macro test_newLit_seq_uint16: untyped =
+  let s: seq[uint16] = @[1'u16,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint16] = test_newLit_seq_uint16
+  doAssert tmp == @[1'u16,2,3,4,5]
+
+macro test_newLit_seq_uint32: untyped =
+  let s: seq[uint32] = @[1'u32,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint32] = test_newLit_seq_uint32
+  doAssert tmp == @[1'u32,2,3,4,5]
+
+macro test_newLit_seq_uint64: untyped =
+  let s: seq[uint64] = @[1'u64,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint64] = test_newLit_seq_uint64
+  doAssert tmp == @[1'u64,2,3,4,5]
+
+macro test_newLit_seq_float: untyped =
+  let s: seq[float] = @[1.0, 2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[float] = test_newLit_seq_float
+  doAssert tmp == @[1.0, 2,3,4,5]
+
+macro test_newLit_seq_float32: untyped =
+  let s: seq[float32] = @[1.0'f32, 2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[float32] = test_newLit_seq_float32
+  doAssert tmp == @[1.0'f32, 2,3,4,5]
+
+macro test_newLit_seq_float64: untyped =
+  let s: seq[float64] = @[1.0'f64, 2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[float64] = test_newLit_seq_float64
+  doAssert tmp == @[1.0'f64, 2,3,4,5]
+
+macro test_newLit_tuple: untyped =
+  let tup: tuple[a:int,b:string] = (a: 123, b: "223")
+  result = newLit(tup)
+
+doAssert test_newLit_tuple == (a: 123, b: "223")
+
+type
+  ComposedType = object
+    mt: MyType
+    arr: array[4,int]
+    data: seq[byte]
+
+macro test_newLit_ComposedType: untyped =
+  let ct = ComposedType(mt: MyType(a: 123, b:"abc"), arr: [1,2,3,4], data: @[1.byte, 3, 7, 127])
+  result = newLit(ct)
+
+doAssert test_newLit_ComposedType == ComposedType(mt: MyType(a: 123, b:"abc"), arr: [1,2,3,4], data: @[1.byte, 3, 7, 127])
+
+macro test_newLit_empty_seq_string: untyped =
+  var strSeq = newSeq[string](0)
+  result = newLit(strSeq)
+
+block:
+  # x needs to be of type seq[string]
+  var x = test_newLit_empty_seq_string
+  x.add("xyz")
+
+type
+  MyEnum = enum
+    meA
+    meB
+
+macro test_newLit_Enum: untyped =
+  result = newLit(meA)
+
+block:
+  let tmp: MyEnum = meA
+  doAssert tmp == test_newLit_Enum
+
+macro test_newLit_set: untyped =
+  let myset = {MyEnum.low .. MyEnum.high}
+  result = newLit(myset)
+
+block:
+  let tmp: set[MyEnum] = {MyEnum.low .. MyEnum.high}
+  doAssert tmp == test_newLit_set
+
+macro test_newLit_ref_object: untyped =
+  var x = RefObject(x: 10)
+  return newLit(x)
+
+block:
+  let x = test_newLit_ref_object()
+  doAssert $(x[]) == "(x: 10)"
+
+macro test_newLit_object_ref_alias: untyped =
+  var x = ObjectRefAlias(x: 10)
+  return newLit(x)
+
+block:
+  let x = test_newLit_object_ref_alias()
+  doAssert $(x[]) == "(x: 10)"
+
diff --git a/tests/macros/tnewproc.nim b/tests/macros/tnewproc.nim
new file mode 100644
index 000000000..a5bfd6dca
--- /dev/null
+++ b/tests/macros/tnewproc.nim
@@ -0,0 +1,51 @@
+import macros
+
+macro test(a: untyped): untyped =
+  # proc hello*(x: int = 3, y: float32): int {.inline.} = discard
+  let
+    nameNode = nnkPostfix.newTree(
+      newIdentNode("*"),
+      newIdentNode("hello")
+    )
+    params = @[
+      newIdentNode("int"),
+      nnkIdentDefs.newTree(
+        newIdentNode("x"),
+        newIdentNode("int"),
+        newLit(3)
+      ),
+      nnkIdentDefs.newTree(
+        newIdentNode("y"),
+        newIdentNode("float32"),
+        newEmptyNode()
+      )
+    ]
+    paramsNode = nnkFormalParams.newTree(params)
+    pragmasNode = nnkPragma.newTree(
+      newIdentNode("inline")
+    )
+    bodyNode = nnkStmtList.newTree(
+      nnkDiscardStmt.newTree(
+        newEmptyNode()
+      )
+    )
+
+  var
+    expected = nnkProcDef.newTree(
+      nameNode,
+      newEmptyNode(),
+      newEmptyNode(),
+      paramsNode,
+      pragmasNode,
+      newEmptyNode(),
+      bodyNode
+    )
+
+  doAssert expected == newProc(name=nameNode, params=params,
+                                    body = bodyNode, pragmas=pragmasNode)
+  expected.pragma = newEmptyNode()
+  doAssert expected == newProc(name=nameNode, params=params,
+                                    body = bodyNode)
+
+test:
+  42
diff --git a/tests/macros/tnodecompare.nim b/tests/macros/tnodecompare.nim
new file mode 100644
index 000000000..5ffb495b1
--- /dev/null
+++ b/tests/macros/tnodecompare.nim
@@ -0,0 +1,39 @@
+import macros
+
+static:
+  let nodeA = newCommentStmtNode("this is a comment")
+  doAssert nodeA.repr == "## this is a comment"
+  doAssert nodeA.strVal == "this is a comment"
+  doAssert $nodeA == "this is a comment"
+
+  let nodeB = newCommentStmtNode("this is a comment")
+  doAssert nodeA == nodeB
+  nodeB.strVal = "this is a different comment"
+  doAssert nodeA != nodeB
+
+macro test(a: typed, b: typed): untyped =
+  newLit(a == b)
+
+doAssert test(1, 1) == true
+doAssert test(1, 2) == false
+
+type
+  Obj = object of RootObj
+  Other = object of RootObj
+
+doAssert test(Obj, Obj) == true
+doAssert test(Obj, Other) == false
+
+var a, b: int
+
+doAssert test(a, a) == true
+doAssert test(a, b) == false
+
+macro test2: untyped =
+  newLit(bindSym"Obj" == bindSym"Obj")
+
+macro test3: untyped =
+  newLit(bindSym"Obj" == bindSym"Other")
+
+doAssert test2() == true
+doAssert test3() == false
diff --git a/tests/macros/tparsefile.nim b/tests/macros/tparsefile.nim
new file mode 100644
index 000000000..a41223f80
--- /dev/null
+++ b/tests/macros/tparsefile.nim
@@ -0,0 +1,11 @@
+import macros
+
+static:
+  let fn = "mparsefile.nim"
+  var raised = false
+  try:
+    discard parseStmt(staticRead(fn), filename = fn)
+  except ValueError as e:
+    raised = true
+    doAssert e.msg == "mparsefile.nim(4, 1) Error: invalid indentation"
+  doAssert raised
diff --git a/tests/macros/tprocgettype.nim b/tests/macros/tprocgettype.nim
new file mode 100644
index 000000000..0c1cc4270
--- /dev/null
+++ b/tests/macros/tprocgettype.nim
@@ -0,0 +1,28 @@
+discard """
+  nimout: '''
+var x: proc () {.cdecl.} = foo
+var x: iterator (): int {.closure.} = bar
+'''
+"""
+
+# issue #19010
+
+import macros
+
+macro createVar(x: typed): untyped =
+  result = nnkVarSection.newTree:
+    newIdentDefs(ident"x", getTypeInst(x), copy(x))
+  
+  echo repr result
+
+block:
+  proc foo() {.cdecl.} = discard
+
+  createVar(foo)
+  x()
+
+block:
+  iterator bar(): int {.closure.} = discard
+
+  createVar(bar)
+  for a in x(): discard
diff --git a/tests/macros/tprochelpers.nim b/tests/macros/tprochelpers.nim
new file mode 100644
index 000000000..d95a2ced8
--- /dev/null
+++ b/tests/macros/tprochelpers.nim
@@ -0,0 +1,22 @@
+import std/macros
+import stdtest/testutils
+
+macro test1(prc: untyped): untyped =
+  assertAll:
+    prc.params.len == 2
+    prc.params[1].len == 4
+    prc.pragma.len == 2
+
+  prc.params = nnkFormalParams.newTree(
+    ident("int")
+  )
+  prc.pragma = newEmptyNode()
+
+  assertAll:
+    prc.params.len == 1
+    prc.pragma.len == 0
+  prc
+
+proc test(a, b: int): int {.gcsafe, raises: [], test1.} = 5
+
+type hello = proc(a, b: int): int {.gcsafe, raises: [], test1.}
diff --git a/tests/macros/tquotedo.nim b/tests/macros/tquotedo.nim
new file mode 100644
index 000000000..6acb8ef4e
--- /dev/null
+++ b/tests/macros/tquotedo.nim
@@ -0,0 +1,51 @@
+discard """
+output: '''
+123
+Hallo Welt
+Hallo Welt
+1
+()
+'''
+"""
+
+import macros
+
+macro mac(): untyped =
+  quote do:
+    proc test(): int =
+      (proc(): int = result = 123)()
+
+mac()
+echo test()
+
+macro foobar(arg: untyped): untyped =
+  result = arg
+  result.add quote do:
+    `result`
+
+foobar:
+  echo "Hallo Welt"
+
+# bug #3744
+import macros
+macro t(): untyped =
+  return quote do:
+    proc tp(): int =
+      result = 1
+t()
+
+echo tp()
+
+
+# https://github.com/nim-lang/Nim/issues/9866
+type
+  # Foo = int # works
+  Foo = object # fails
+
+macro dispatchGen(): untyped =
+  var shOpt: Foo
+  result = quote do:
+    let baz = `shOpt`
+    echo `shOpt`
+
+dispatchGen()
diff --git a/tests/macros/tquotewords.nim b/tests/macros/tquotewords.nim
new file mode 100644
index 000000000..e718d25f9
--- /dev/null
+++ b/tests/macros/tquotewords.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "thisanexample"
+"""
+# Test an idea I recently had:
+
+import macros
+
+macro quoteWords(n: varargs[untyped]): untyped =
+  let n = callsite()
+  result = newNimNode(nnkBracket, n)
+  for i in 1..n.len-1:
+    expectKind(n[i], nnkIdent)
+    result.add(toStrLit(n[i]))
+
+const
+  myWordList = quoteWords(this, an, example)
+
+var s = ""
+for w in items(myWordList):
+  s.add(w)
+
+echo s #OUT thisanexample
diff --git a/tests/macros/trecmacro.nim b/tests/macros/trecmacro.nim
new file mode 100644
index 000000000..d804178bc
--- /dev/null
+++ b/tests/macros/trecmacro.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "recursive dependency: 'dump'"
+  file: "trecmacro.nim"
+  line: 8
+"""
+
+macro dump(n: untyped): untyped =
+  dump(n)
+  if kind(n) == nnkNone:
+    nil
+  else:
+    hint($kind(n))
+    for i in countUp(0, len(n)-1):
+      nil
diff --git a/tests/macros/treturnsempty.nim b/tests/macros/treturnsempty.nim
new file mode 100644
index 000000000..a5a678af3
--- /dev/null
+++ b/tests/macros/treturnsempty.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "type mismatch"
+  line: 11
+"""
+# bug #2372
+macro foo(dummy: int): untyped =
+  discard
+
+proc takeStr(s: string) = echo s
+
+takeStr foo(12)
diff --git a/tests/macros/tsame_name_497.nim b/tests/macros/tsame_name_497.nim
new file mode 100644
index 000000000..9f26a4024
--- /dev/null
+++ b/tests/macros/tsame_name_497.nim
@@ -0,0 +1,6 @@
+
+import macro_bug
+
+type TObj = object
+
+proc f(o: TObj) {.macro_bug.} = discard
diff --git a/tests/macros/tsametype.nim b/tests/macros/tsametype.nim
new file mode 100644
index 000000000..5219a3767
--- /dev/null
+++ b/tests/macros/tsametype.nim
@@ -0,0 +1,42 @@
+discard """
+output: '''true
+false
+true
+false
+true
+false
+true
+false
+true
+false'''
+joinable: false
+"""
+
+import macros
+
+macro same(a: typedesc, b: typedesc): untyped =
+  newLit(a.getType[1].sameType b.getType[1])
+
+echo same(int, int)
+echo same(int, float)
+
+type
+  SomeInt = int
+  DistinctInt = distinct int
+  SomeFloat = float
+  DistinctFloat = distinct float
+
+echo same(int, SomeInt)
+echo same(int, DistinctInt)
+echo same(float, SomeFloat)
+echo same(float, DistinctFloat)
+
+type
+  Obj = object of RootObj
+  SubObj = object of Obj
+  Other = object of RootObj
+
+echo same(Obj, Obj)
+echo same(int, Obj)
+echo same(SubObj, SubObj)
+echo same(Other, Obj)
diff --git a/tests/macros/tslice.nim b/tests/macros/tslice.nim
new file mode 100644
index 000000000..c64289ec6
--- /dev/null
+++ b/tests/macros/tslice.nim
@@ -0,0 +1,38 @@
+import macros
+
+macro test(): untyped =
+  result = nnkStmtList.newTree()
+  let n = nnkStmtList.newTree(
+    newIdentNode("one"),
+    newIdentNode("two"),
+    newIdentNode("three"),
+    newIdentNode("four"),
+    newIdentNode("five"),
+    newIdentNode("six")
+  )
+
+  var i = 1
+  for x in n[1 .. ^2]:
+    assert x == n[i]
+    i.inc
+  assert i == 5
+
+  i = 3
+  for x in n[3..^1]:
+    assert x == n[i]
+    i.inc
+  assert i == 6
+
+  i = 0
+  for x in n[0..3]:
+    assert x == n[i]
+    i.inc
+  assert i == 4
+
+  i = 0
+  for x in n[0..5]:
+    assert x == n[i]
+    i.inc
+  assert i == 6
+
+test()
diff --git a/tests/macros/tstaticparamsmacro.nim b/tests/macros/tstaticparamsmacro.nim
new file mode 100644
index 000000000..2632ca730
--- /dev/null
+++ b/tests/macros/tstaticparamsmacro.nim
@@ -0,0 +1,75 @@
+discard """
+  nimout: '''
+letters
+aa
+bb
+numbers
+11
+22
+AST a
+@[(c: 11, d: 22), (c: 33, d: 44)]
+AST b
+(e: @[55, 66], f: @[77, 88])
+55
+10
+20Test
+20
+'''
+"""
+
+import macros
+
+type
+  TConfig = tuple
+    letters: seq[string]
+    numbers:seq[int]
+
+const data: Tconfig = (@["aa", "bb"], @[11, 22])
+
+macro mymacro(data: static[TConfig]): untyped =
+  echo "letters"
+  for s in items(data.letters):
+    echo s
+  echo "numbers"
+  for n in items(data.numbers):
+    echo n
+
+mymacro(data)
+
+type
+  Ta = seq[tuple[c:int, d:int]]
+  Tb = tuple[e:seq[int], f:seq[int]]
+
+const
+  a : Ta = @[(11, 22), (33, 44)]
+  b : Tb = (@[55,66], @[77, 88])
+
+macro mA(data: static[Ta]): untyped =
+  echo "AST a\n", repr(data)
+
+macro mB(data: static[Tb]): untyped =
+  echo "AST b\n", repr(data)
+  echo data.e[0]
+
+mA(a)
+mB(b)
+
+type
+  Foo[N: static[int], Z: static[string]] = object
+
+macro staticIntMacro(f: static[int]): untyped = echo f
+staticIntMacro 10
+
+var
+  x: Foo[20, "Test"]
+
+macro genericMacro[N; Z: static[string]](f: Foo[N, Z], ll = 3, zz = 12): untyped =
+  echo N, Z
+
+genericMacro x
+
+template genericTemplate[N, Z](f: Foo[N, Z], ll = 3, zz = 12): int = N
+
+static:
+  echo genericTemplate(x)
+
diff --git a/tests/macros/tstringinterp.nim b/tests/macros/tstringinterp.nim
new file mode 100644
index 000000000..74c73599b
--- /dev/null
+++ b/tests/macros/tstringinterp.nim
@@ -0,0 +1,73 @@
+discard """
+  output: "Hello Alice, 64 | Hello Bob, 10$"
+"""
+
+import macros, parseutils, strutils
+
+proc concat(strings: varargs[string]): string =
+  result = newString(0)
+  for s in items(strings): result.add(s)
+
+template processInterpolations(e) =
+  var s = e[1].strVal
+  for f in interpolatedFragments(s):
+    case f.kind
+    of ikStr:         addString(f.value)
+    of ikDollar:      addDollar()
+    of ikVar, ikExpr: addExpr(newCall("$", parseExpr(f.value)))
+
+macro formatStyleInterpolation(e: untyped): untyped =
+  let e = callsite()
+  var
+    formatString = ""
+    arrayNode = newNimNode(nnkBracket)
+    idx = 1
+
+  proc addString(s: string) =
+    formatString.add(s)
+
+  proc addExpr(e: NimNode) =
+    arrayNode.add(e)
+    formatString.add("$" & $(idx))
+    inc idx
+
+  proc addDollar() =
+    formatString.add("$$")
+
+  processInterpolations(e)
+
+  result = parseExpr("\"x\" % [y]")
+  result[1].strVal = formatString
+  result[2] = arrayNode
+
+macro concatStyleInterpolation(e: untyped): untyped =
+  let e = callsite()
+  var args: seq[NimNode]
+  newSeq(args, 0)
+
+  proc addString(s: string)    = args.add(newStrLitNode(s))
+  proc addExpr(e: NimNode) = args.add(e)
+  proc addDollar()             = args.add(newStrLitNode"$")
+
+  processInterpolations(e)
+
+  result = newCall("concat", args)
+
+###
+
+proc sum(a, b, c: int): int =
+  return (a + b + c)
+
+var
+  alice = "Alice"
+  bob = "Bob"
+  a = 10
+  b = 20
+  c = 34
+
+var
+  s1 = concatStyleInterpolation"Hello ${alice}, ${sum(a, b, c)}"
+  s2 = formatStyleInterpolation"Hello ${bob}, ${sum(alice.len, bob.len, 2)}$$"
+
+write(stdout, s1 & " | " & s2)
+write(stdout, "\n")
diff --git a/tests/macros/tstructuredlogging.nim b/tests/macros/tstructuredlogging.nim
new file mode 100644
index 000000000..649c6c0bd
--- /dev/null
+++ b/tests/macros/tstructuredlogging.nim
@@ -0,0 +1,154 @@
+discard """
+output: '''
+main started: a=10, b=inner-b, c=10, d=some-d, x=16, z=20
+exiting: a=12, b=overridden-b, c=100, msg=bye bye, x=16
+'''
+"""
+
+import macros, tables
+
+template scopeHolder =
+  0 # scope revision number
+
+type
+  BindingsSet = Table[string, NimNode]
+
+proc actualBody(n: NimNode): NimNode =
+  # skip over the double StmtList node introduced in `mergeScopes`
+  result = n.body
+  if result.kind == nnkStmtList and result[0].kind == nnkStmtList:
+    result = result[0]
+
+iterator bindings(n: NimNode, skip = 0): (string, NimNode) =
+  for i in skip ..< n.len:
+    let child = n[i]
+    if child.kind in {nnkAsgn, nnkExprEqExpr}:
+      let name = $child[0]
+      let value = child[1]
+      yield (name, value)
+
+proc scopeRevision(scopeHolder: NimNode): int =
+  # get the revision number from a scopeHolder sym
+  assert scopeHolder.kind == nnkSym
+  var revisionNode = scopeHolder.getImpl.actualBody[0]
+  result = int(revisionNode.intVal)
+
+proc lastScopeHolder(scopeHolders: NimNode): NimNode =
+  # get the most recent scopeHolder from a symChoice node
+  if scopeHolders.kind in {nnkClosedSymChoice, nnkOpenSymChoice}:
+    var bestScopeRev = 0
+    assert scopeHolders.len > 0
+    for scope in scopeHolders:
+      let rev = scope.scopeRevision
+      if result == nil or rev > bestScopeRev:
+        result = scope
+        bestScopeRev = rev
+  else:
+    result = scopeHolders
+
+  assert result.kind == nnkSym
+
+macro mergeScopes(scopeHolders: typed, newBindings: untyped): untyped =
+  var
+    bestScope = scopeHolders.lastScopeHolder
+    bestScopeRev = bestScope.scopeRevision
+
+  var finalBindings = initTable[string, NimNode]()
+  for k, v in bindings(bestScope.getImpl.actualBody, skip = 1):
+    finalBindings[k] = v
+
+  for k, v in bindings(newBindings):
+    finalBindings[k] = v
+
+  var newScopeDefinition = newStmtList(newLit(bestScopeRev + 1))
+
+  for k, v in finalBindings:
+    newScopeDefinition.add newAssignment(newIdentNode(k), v)
+
+  result = quote:
+    template scopeHolder {.redefine.} = `newScopeDefinition`
+
+template scope(newBindings: untyped) {.dirty.} =
+  mergeScopes(bindSym"scopeHolder", newBindings)
+
+type
+  TextLogRecord = object
+    line: string
+
+  StdoutLogRecord = object
+
+template setProperty(r: var TextLogRecord, key: string, val: string, isFirst: bool) =
+  if not first: r.line.add ", "
+  r.line.add key
+  r.line.add "="
+  r.line.add val
+
+template setEventName(r: var StdoutLogRecord, name: string) =
+  stdout.write(name & ": ")
+
+template setProperty(r: var StdoutLogRecord, key: string, val: auto, isFirst: bool) =
+  when not isFirst: stdout.write ", "
+  stdout.write key
+  stdout.write "="
+  stdout.write $val
+
+template flushRecord(r: var StdoutLogRecord) =
+  stdout.write "\n"
+  stdout.flushFile
+
+macro logImpl(scopeHolders: typed,
+              logStmtProps: varargs[untyped]): untyped =
+  let lexicalScope = scopeHolders.lastScopeHolder.getImpl.actualBody
+  var finalBindings = initOrderedTable[string, NimNode]()
+
+  for k, v in bindings(lexicalScope, skip = 1):
+    finalBindings[k] = v
+
+  for k, v in bindings(logStmtProps, skip = 1):
+    finalBindings[k] = v
+
+  finalBindings.sort(system.cmp)
+
+  let eventName = logStmtProps[0]
+  assert eventName.kind in {nnkStrLit}
+  let record = genSym(nskVar, "record")
+
+  result = quote:
+    var `record`: StdoutLogRecord
+    setEventName(`record`, `eventName`)
+
+  var isFirst = true
+  for k, v in finalBindings:
+    result.add newCall(newIdentNode"setProperty",
+                       record, newLit(k), v, newLit(isFirst))
+    isFirst = false
+
+  result.add newCall(newIdentNode"flushRecord", record)
+
+template log(props: varargs[untyped]) {.dirty.} =
+  logImpl(bindSym"scopeHolder", props)
+
+scope:
+  a = 12
+  b = "original-b"
+
+scope:
+  x = 16
+  b = "overridden-b"
+
+scope:
+  c = 100
+
+proc main =
+  scope:
+    c = 10
+
+  scope:
+    z = 20
+
+  log("main started", a = 10, b = "inner-b", d = "some-d")
+
+main()
+
+log("exiting", msg = "bye bye")
+
diff --git a/tests/macros/ttemplatesymbols.nim b/tests/macros/ttemplatesymbols.nim
new file mode 100644
index 000000000..3182de79d
--- /dev/null
+++ b/tests/macros/ttemplatesymbols.nim
@@ -0,0 +1,171 @@
+import
+  macros, algorithm, strutils
+
+proc normalProc(x: int) =
+  echo x
+
+template templateWithtouParams =
+  echo 10
+
+proc overloadedProc(x: int) =
+  echo x
+
+proc overloadedProc(x: string) =
+  echo x
+
+proc overloadedProc[T](x: T) =
+  echo x
+
+template normalTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: string) =
+  echo x
+
+macro normalMacro(x: int): untyped =
+  discard
+
+macro macroWithoutParams: untyped =
+  discard
+
+macro inspectSymbol(sym: typed, expected: static[string]): untyped =
+  if sym.kind == nnkSym:
+    echo "Symbol node:"
+    let res = sym.getImpl.repr & "\n"
+    echo res
+    # echo "|", res, "|"
+    # echo "|", expected, "|"
+    if expected.len > 0: assert res == expected
+  elif sym.kind in {nnkClosedSymChoice, nnkOpenSymChoice}:
+    echo "Begin sym choice:"
+    var results = newSeq[string](0)
+    for innerSym in sym:
+      results.add innerSym.getImpl.repr
+    sort(results, cmp[string])
+    let res = results.join("\n") & "\n"
+    echo res
+    if expected.len > 0: assert res == expected
+    echo "End symchoice."
+  else:
+    echo "Non-symbol node: ", sym.kind
+    if expected.len > 0: assert $sym.kind == expected
+
+macro inspectUntyped(sym: untyped, expected: static[string]): untyped =
+  let res = sym.repr
+  echo "Untyped node: ", res
+  assert res == expected
+
+inspectSymbol templateWithtouParams, "nnkCommand"
+  # this template is expanded, because bindSym was not used
+  # the end result is the template body (nnkCommand)
+
+inspectSymbol bindSym("templateWithtouParams"), """
+template templateWithtouParams() =
+  echo 10
+
+"""
+
+inspectSymbol macroWithoutParams, "nnkEmpty"
+  # Just like the template above, the macro was expanded
+
+inspectSymbol bindSym("macroWithoutParams"), """
+macro macroWithoutParams(): untyped =
+  discard
+
+"""
+
+inspectSymbol normalMacro, """
+macro normalMacro(x: int): untyped =
+  discard
+
+"""
+  # Since the normalMacro has params, it's automatically
+  # treated as a symbol here (no need for `bindSym`)
+
+inspectSymbol bindSym("normalMacro"), """
+macro normalMacro(x: int): untyped =
+  discard
+
+"""
+
+inspectSymbol normalTemplate, """
+template normalTemplate(x: int) =
+  echo x
+
+"""
+
+inspectSymbol bindSym("normalTemplate"), """
+template normalTemplate(x: int) =
+  echo x
+
+"""
+
+inspectSymbol overloadedTemplate, """
+template overloadedTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: string) =
+  echo x
+
+"""
+
+inspectSymbol bindSym("overloadedTemplate"), """
+template overloadedTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: string) =
+  echo x
+
+"""
+
+inspectUntyped bindSym("overloadedTemplate"), """bindSym("overloadedTemplate")"""
+  # binSym is active only in the presence of `typed` params.
+  # `untyped` params still get the raw AST
+
+inspectSymbol normalProc, """
+proc normalProc(x: int) =
+  echo [x]
+
+"""
+
+inspectSymbol bindSym("normalProc"), """
+proc normalProc(x: int) =
+  echo [x]
+
+"""
+
+inspectSymbol overloadedProc, """
+proc overloadedProc(x: int) =
+  echo [x]
+
+proc overloadedProc(x: string) =
+  echo [x]
+
+proc overloadedProc[T](x: T) =
+  echo x
+
+"""
+
+inspectSymbol overloadedProc[float], """
+proc overloadedProc(x: T) =
+  echo [x]
+
+"""
+  # As expected, when we select a specific generic, the
+  # AST is no longer a symChoice
+
+inspectSymbol bindSym("overloadedProc"), """
+proc overloadedProc(x: int) =
+  echo [x]
+
+proc overloadedProc(x: string) =
+  echo [x]
+
+proc overloadedProc[T](x: T) =
+  echo x
+
+"""
+
diff --git a/tests/macros/ttryparseexpr.nim b/tests/macros/ttryparseexpr.nim
new file mode 100644
index 000000000..e6e9e9880
--- /dev/null
+++ b/tests/macros/ttryparseexpr.nim
@@ -0,0 +1,24 @@
+discard """
+  outputsub: '''Error: expression expected, but found '[EOF]' 45'''
+"""
+
+# feature request #1473
+import macros
+
+macro test(text: string): untyped =
+  try:
+    result = parseExpr(text.strVal)
+  except ValueError:
+    result = newLit getCurrentExceptionMsg()
+
+const
+  valid = 45
+  a = test("foo&&")
+  b = test("valid")
+  c = test("\"") # bug #2504
+
+echo a, " ", b
+
+static:
+  # Issue #9918
+  discard parseStmt("echo(1+1);")
diff --git a/tests/macros/ttypenodes.nim b/tests/macros/ttypenodes.nim
new file mode 100644
index 000000000..233ea9780
--- /dev/null
+++ b/tests/macros/ttypenodes.nim
@@ -0,0 +1,16 @@
+import macros
+
+macro makeEnum(): untyped =
+  newTree(nnkEnumTy, newEmptyNode(), ident"a", ident"b", ident"c")
+
+macro makeObject(): untyped =
+  newTree(nnkObjectTy, newEmptyNode(), newEmptyNode(), newTree(nnkRecList,
+    newTree(nnkIdentDefs, ident"x", ident"y", ident"int", newEmptyNode())))
+
+type
+  Foo = makeEnum()
+  Bar = makeObject()
+
+doAssert {a, b, c} is set[Foo]
+let bar = Bar(x: 3, y: 4)
+doAssert (bar.x, bar.y) == (3, 4)
diff --git a/tests/macros/tvarargsuntyped.nim b/tests/macros/tvarargsuntyped.nim
new file mode 100644
index 000000000..5a06adcca
--- /dev/null
+++ b/tests/macros/tvarargsuntyped.nim
@@ -0,0 +1,108 @@
+discard """
+  output: '''Let's go!
+(left: 2, r: 7, x: 8, height: 4, s: test, width: 3, y: 9, top: 1, g: 7, b: 8)
+(left: 2, r: 7, x: 8, height: 4, s: text, width: 3, y: 9, top: 1, g: 7, b: 8)
+(left: 2, r: 7, x: 8, height: 4, s: text, width: 3, y: 9, top: 4, g: 7, b: 8)
+(left: 2, r: 7, x: 8, height: 4, s: test, width: 3, y: 9, top: 1, g: 7, b: 8)
+10
+hello 18.0'''
+"""
+
+import macros
+
+proc internalBar(top, left, width, height: cint, s: string, x, y: int, r,g,b: int) =
+  echo "(left: ", left, ", r: ", r, ", x: ", x, ", height: ", height, ", s: ", s,
+    ", width: ", width, ", y: ", y, ", top: ", top, ", g: ", g, ", b: ", b, ")"
+
+# we need these dummy constructors due to the wrong implementation
+# of 'varargs[untyped]' in the compiler:
+
+proc point(x, y: int): int = discard
+proc color(r, g, b: int): int = discard
+proc rect(a, b, c, d: int): int = discard
+
+template declareUnpackingMacro(nimname,extname) =
+  macro nimname(n: varargs[untyped]): untyped =
+    var s: string = astToStr(extname) & "("
+    var first = true
+    echo repr n
+    for x in n.children:
+      var unpack = false
+      if x.kind in nnkCallKinds:
+        case $x[0]
+        of "point":
+          expectLen(x, 3)
+          unpack = true
+        of "rect":
+          expectLen(x, 5)
+          unpack = true
+        of "color":
+          expectLen(x, 4)
+          unpack = true
+        else: discard
+      if unpack:
+        for i in 1..<x.len:
+          if first:
+            first = false
+          else:
+            add(s, ", ")
+          add(s, repr(x[i]))
+      else:
+        if first:
+          first = false
+        else:
+          add(s, ", ")
+        add(s, repr(x))
+
+    add(s, ")")
+    echo s
+    result = parseStmt(s)
+
+declareUnpackingMacro(bar,internalBar)
+
+type MyInt = distinct int
+
+proc myInt(i: int): MyInt = cast[MyInt](i)
+
+converter toCInt(mi: MyInt): cint = cast[cint](mi)
+
+echo "Let's go!"
+
+bar(rect(1, 2, 3, 4), "test", point(8, 9), color(7,7,8))
+
+bar(1,2,3,4,"text",8,9,7,7,8)
+
+bar(myInt(4),2,3,4,"text",8,9,7,7,8)
+
+let top: cint = 1
+let left: cint = 2
+let width: cint = 3
+let height: cint = 4
+
+bar(rect(top, left, width, height), "test", point(8, 9), color(7,7,8))
+
+
+# bug #10075
+
+import macros
+
+proc convert_hidden_stdconv(args: NimNode): NimNode =
+  var n = args
+  while n.len == 1 and n[0].kind == nnkHiddenStdConv:
+    n = n[0][1]
+  return n
+
+macro t2(s: int, v: varargs[untyped]): untyped =
+  let v = convert_hidden_stdconv(v)
+  echo v.treeRepr
+  let (v1, v2) = (v[0], v[1])
+  quote do:
+    echo `v1`, " ", `v2`
+
+template t1(s: int, v: varargs[typed]) =
+  #static:
+  #   dumpTree v
+  echo s
+  t2(s, v)
+
+t1(10, "hello", 18.0)
diff --git a/tests/macros/tvtable.nim b/tests/macros/tvtable.nim
new file mode 100644
index 000000000..0f322b7d5
--- /dev/null
+++ b/tests/macros/tvtable.nim
@@ -0,0 +1,74 @@
+discard """
+  output: '''
+OBJ 1 foo
+10
+OBJ 1 bar
+OBJ 2 foo
+5
+OBJ 2 bar
+'''
+"""
+
+type
+  # these are the signatures of the virtual procs for each type
+  fooProc[T] = proc (o: var T): int {.nimcall.}
+  barProc[T] = proc (o: var T) {.nimcall.}
+
+  # an untyped table to store the proc pointers
+  # it's also possible to use a strongly typed tuple here
+  VTable = array[0..1, pointer]
+
+  TBase {.inheritable.} = object
+    vtbl: ptr VTable
+
+  TUserObject1 = object of TBase
+    x: int
+
+  TUserObject2 = object of TBase
+    y: int
+
+proc foo(o: var TUserObject1): int =
+  echo "OBJ 1 foo"
+  return 10
+
+proc bar(o: var TUserObject1) =
+  echo "OBJ 1 bar"
+
+proc foo(o: var TUserObject2): int =
+  echo "OBJ 2 foo"
+  return 5
+
+proc bar(o: var TUserObject2) =
+  echo "OBJ 2 bar"
+
+proc getVTable(T: typedesc): ptr VTable =
+  # pay attention to what's going on here
+  # this will initialize the vtable for each type at program start-up
+  #
+  # fooProc[T](foo) is a type coercion - it looks for a proc named foo
+  # matching the signature fooProc[T] (e.g. proc (o: var TUserObject1): int)
+  var vtbl {.global.} = [
+    cast[pointer](fooProc[T](foo)),
+    cast[pointer](barProc[T](bar))
+  ]
+
+  return vtbl.addr
+
+proc create(T: typedesc): T =
+  result.vtbl = getVTable(T)
+
+proc baseFoo(o: var TBase): int =
+  return cast[fooProc[TBase]](o.vtbl[0])(o)
+
+proc baseBar(o: var TBase) =
+  cast[barProc[TBase]](o.vtbl[1])(o)
+
+var a = TUserObject1.create
+var b = TUserObject2.create
+
+echo a.baseFoo
+a.baseBar
+
+echo b.baseFoo
+b.baseBar
+
diff --git a/tests/macros/twrapiterator.nim b/tests/macros/twrapiterator.nim
new file mode 100644
index 000000000..e153ae980
--- /dev/null
+++ b/tests/macros/twrapiterator.nim
@@ -0,0 +1,19 @@
+
+import macros
+
+# bug #7093
+
+macro foobar(arg: untyped): untyped =
+  let procDef = quote do:
+    proc foo(): void =
+      echo "bar"
+
+
+  result = newStmtList(
+    arg, procDef
+  )
+
+  echo result.repr
+
+iterator bar(): int {.foobar.} =
+  discard
diff --git a/tests/macros/typesafeprintf.nim b/tests/macros/typesafeprintf.nim
new file mode 100644
index 000000000..daf213bd3
--- /dev/null
+++ b/tests/macros/typesafeprintf.nim
@@ -0,0 +1,49 @@
+discard """
+  output: '''test 10'''
+"""
+
+# bug #1152
+
+import macros, typetraits
+proc printfImpl(formatstr: cstring) {.importc: "printf", varargs.}
+
+iterator tokenize(format: string): char =
+  var i = 0
+  while i < format.len:
+    case format[i]
+    of '%':
+      case format[i+1]
+      of '\0': break
+      else: yield format[i+1]
+      i.inc
+    of '\0': break
+    else: discard
+    i.inc
+
+macro printf(formatString: string{lit}, args: varargs[typed]): untyped =
+  var i = 0
+  let err = getType(bindSym"ValueError")
+  for c in tokenize(formatString.strVal):
+    var expectedType = case c
+      of 'c': getType(bindSym"char")
+      of 'd', 'i', 'x', 'X': getType(bindSym"int")
+      of 'f', 'e', 'E', 'g', 'G': getType(bindSym"float")
+      of 's': getType(bindSym"string")
+      of 'p': getType(bindSym"pointer")
+      else: err
+
+    var actualType = getType(args[i])
+    inc i
+
+    if sameType(expectedType, err):
+      error c & " is not a valid format character"
+    elif not sameType(expectedType, actualType):
+      error "type mismatch for argument " & $i & ". expected type: " &
+            $expectedType & ", actual type: " & $actualType
+
+  # keep the original callsite, but use cprintf instead
+  result = newCall(bindSym"printfImpl")
+  result.add formatString
+  for a in args: result.add a
+
+printf("test %d\n", 10)
diff --git a/tests/macros/typesapi2.nim b/tests/macros/typesapi2.nim
new file mode 100644
index 000000000..0130049c0
--- /dev/null
+++ b/tests/macros/typesapi2.nim
@@ -0,0 +1,48 @@
+# tests to see if a symbol returned from macros.getType() can
+# be used as a type
+import macros
+
+macro testTypesym (t:typed): untyped =
+    var ty = t.getType
+    if ty.typekind == ntyTypedesc:
+        # skip typedesc get to the real type
+        ty = ty[1].getType
+
+    if ty.kind == nnkSym: return ty
+    assert ty.kind == nnkBracketExpr
+    assert ty[0].kind == nnkSym
+    result = ty[0]
+    return
+
+type TestFN = proc(a,b:int):int
+var iii: testTypesym(TestFN)
+static: assert iii is TestFN
+
+proc foo11 : testTypesym(void) =
+    echo "HI!"
+static: assert foo11 is (proc():void {.nimcall.})
+
+var sss: testTypesym(seq[int])
+static: assert sss is seq[int]
+# very nice :>
+
+static: assert array[2,int] is testTypesym(array[2,int])
+static: assert(ref int is testTypesym(ref int))
+static: assert(void is testTypesym(void))
+
+
+macro tts2 (t:typed, idx:int): untyped =
+    var ty = t.getType
+    if ty.typekind == ntyTypedesc:
+        # skip typedesc get to the real type
+        ty = ty[1].getType
+
+    if ty.kind == nnkSym: return ty
+    assert ty.kind == nnkBracketExpr
+    return ty[idx.intval.int]
+type TestFN2 = proc(a:int,b:float):string
+static:
+    assert(tts2(TestFN2, 0) is TestFN2)
+    assert(tts2(TestFN2, 1) is string)
+    assert(tts2(TestFN2, 2) is int)
+    assert(tts2(TestFN2, 3) is float)