From 97ef94d3ff7c33a814223589b24c6d9124a142da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Arne=20D=C3=B6ring?= <arne.doering@gmx.net>
Date: Fri, 18 Jan 2019 00:45:15 +0100
Subject: [PATCH 1/5] new experimental quoteAst as a potential successor of
 macros.quote

---
 lib/experimental/quote2.nim | 85 +++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)
 create mode 100644 lib/experimental/quote2.nim

diff --git a/lib/experimental/quote2.nim b/lib/experimental/quote2.nim
new file mode 100644
index 0000000000000..173cb08e36fe4
--- /dev/null
+++ b/lib/experimental/quote2.nim
@@ -0,0 +1,85 @@
+import macros
+
+proc newTreeExpr(stmtListExpr, exprNode, unquoteIdent: NimNode): NimNode {.compileTime.} =
+  # stmtList is a buffer to generate statements
+  if exprNode.kind in nnkLiterals:
+    result = newCall(bindSym"newLit", exprNode)
+  elif exprNode.kind == nnkIdent:
+    result = newCall(bindSym"ident", newLit(exprNode.strVal))
+  elif exprNode.kind in nnkCallKinds and exprNode.len == 2 and exprNode[0].eqIdent unquoteIdent:
+    result = exprNode[1]
+  elif exprNode.kind == nnkSym:
+    error("for quoting the ast needs to be untyped", exprNode)
+  elif exprNode.kind == nnkEmpty:
+    # bug newTree(nnkEmpty) raises exception:
+    result = newCall(bindSym"newEmptyNode")
+  else:
+    result = genSym(nskLet)
+    stmtListExpr.add newLetStmt(result, newCall(bindSym"newNimNode", newLit(exprNode.kind))) #, exprNode )
+    for child in exprNode:
+      stmtListExpr.add newCall(bindSym"add", result, newTreeExpr(stmtListExpr, child, unquoteIdent))
+
+macro quoteAst(ast: untyped): untyped =
+  ## Substitute for ``quote do`` but with ``uq`` for unquoting instead of backticks.
+  result = newNimNode(nnkStmtListExpr)
+  result.add result.newTreeExpr(ast, ident"uq")
+
+macro quoteAst(unquoteIdent, ast: untyped): untyped =
+  unquoteIdent.expectKind nnkIdent
+  result = newNimNode(nnkStmtListExpr)
+  result.add result.newTreeExpr(ast, unquoteIdent)
+
+macro foobar(arg: untyped): untyped =
+  # simple generation of source code:
+  result = quoteAst:
+    echo "Hello world!"
+
+  echo result.treeRepr
+
+  # inject subtrees from local scope, like `` in quote do:
+  let world = newLit("world")
+  result = quoteAst:
+    echo "Hello ", uq(world), "!"
+
+  echo result.treeRepr
+
+  # inject subtree from expression:
+  result = quoteAst:
+    echo "Hello ", uq(newLit("world")), "!"
+
+  echo result.treeRepr
+
+  # custom name for unquote in case `uq` should collide with anything.
+  let x = newLit(123)
+  result = quoteAst myUnquote:
+    echo "abc ", myUnquote(x), " ", myUnquote(newLit("xyz")), " ", myUnquote(arg)
+
+  echo result.treeRepr
+
+let myVal = "Hallo Welt!"
+foobar(myVal)
+
+# example from #10326
+
+template id*(val: int) {.pragma.}
+macro m1(): untyped =
+   let x = newLit(10)
+   let r1 = quote do:
+      type T1 {.id(`x`).} = object
+
+   let r2 = quoteAst:
+     type T1 {.id(uq(x)).} = object
+
+
+   echo "from #10326:"
+   echo r1[0][0].treeRepr
+   echo r2[0][0].treeRepr
+
+m1()
+
+macro lineinfoTest(): untyped =
+  # line info is preserved as if the content of ``quoteAst`` is written in a template
+  result = quoteAst:
+    assert(false)
+
+lineinfoTest()

From 6c9a5db120ef44d764ee06cdb8785c34c03db183 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Arne=20D=C3=B6ring?= <arne.doering@gmx.net>
Date: Wed, 23 Jan 2019 09:33:42 +0100
Subject: [PATCH 2/5] new examples

---
 compiler/renderer.nim       |   7 +-
 compiler/vm.nim             |  38 ++++++++-
 compiler/vmgen.nim          |   7 +-
 lib/core/macros.nim         |   8 ++
 lib/experimental/quote2.nim | 153 +++++++++++++++++++++++++++++++++---
 5 files changed, 197 insertions(+), 16 deletions(-)

diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index ce47cf2197e01..4a41c12525d33 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -999,9 +999,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gsub(g, n, 0)
     gcomma(g, n, 1)
   of nkCommand:
-    accentedName(g, n[0])
-    put(g, tkSpaces, Space)
-    gcomma(g, n, 1)
+    if n.len > 0:
+      accentedName(g, n[0])
+      put(g, tkSpaces, Space)
+      gcomma(g, n, 1)
   of nkExprEqExpr, nkAsgn, nkFastAsgn:
     gsub(g, n, 0)
     put(g, tkSpaces, Space)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 131501380f1a5..d4659e77521c4 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1498,8 +1498,44 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         internalAssert c.config, false
       regs[ra].node.info = n.info
       regs[ra].node.typ = n.typ
-    of opcNSetLineInfo:
+    of opcNSetLineInfoObj:
+      let n = regs[rb].node
+      assert(n.kind == nkObjConstr)
+      assert(n.len == 4)
+      assert(n[1][0].sym.name.s == "filename")
+      let filename = n[1][1].strVal
+      assert(n[2][0].sym.name.s == "line")
+      let line = n[2][1].intVal
+      assert(n[3][0].sym.name.s == "column")
+      let column = n[3][1].intVal
+
+
+      proc semInstantiationInfo(c: PContext, n: PNode): PNode =
+        result = newNodeIT(nkTupleConstr, n.info, n.typ)
+        let idx = expectIntLit(c, n.sons[1])
+        let useFullPaths = expectIntLit(c, n.sons[2])
+        let info = getInfoContext(c.config, idx)
+        var filename = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
+        filename.strVal = if useFullPaths != 0: toFullPath(c.config, info) else: toFilename(c.config, info)
+        var line = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt))
+        line.intVal = toLinenumber(info)
+        var column = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt))
+        column.intVal = toColumn(info)
+        result.add(filename)
+        result.add(line)
+        result.add(column)
+
+      n.
+      proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
+      proc toAbsolute*(file: string; base: AbsoluteDir): AbsoluteFile =
+
+      regs
       decodeB(rkNode)
+      echo regs[rb].kind
+      debug(regs[rb].node)
+      regs[ra].node.info = regs[rb].node.info
+    of opcNCopyLineInfo:
+      debug(regs[rb].node)
       regs[ra].node.info = regs[rb].node.info
     of opcEqIdent:
       decodeBC(rkInt)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index e7993dfb21270..930dd69765d95 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1231,11 +1231,16 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     of "getFile": genUnaryABI(c, n, dest, opcNGetLineInfo, 0)
     of "getLine": genUnaryABI(c, n, dest, opcNGetLineInfo, 1)
     of "getColumn": genUnaryABI(c, n, dest, opcNGetLineInfo, 2)
+    of "setFile": genBinaryStmt(c, n, opcNSetLineInfo)
+    of "setLine": genBinaryStmt(c, n, opcNSetLineInfo)
+    of "setColumn": genBinaryStmt(c, n, opcNSetLineInfo)
+    of "lineInfoObj=": genBinaryStmt(c, n, opcNSetLineInfo)
     of "copyLineInfo":
       internalAssert c.config, n.len == 3
       unused(c, n, dest)
       genBinaryStmt(c, n, opcNSetLineInfo)
-    else: internalAssert c.config, false
+    else:
+      internalAssert c.config, false
   of mNHint:
     unused(c, n, dest)
     genBinaryStmt(c, n, opcNHint)
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 3a85324bac03a..17cb4e87c525c 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -489,6 +489,14 @@ proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} =
 proc lineInfo*(arg: NimNode): string {.compileTime.} =
   $arg.lineInfoObj
 
+
+proc `lineInfoObj=`*(n: NimNode; lineinfo: LineInfo) {.magic: "NLineInfo".}
+
+proc setLine(arg: NimNode; line: int) {.magic: "NLineInfo".}
+proc setColumn(arg: NimNode; column: int) {.magic: "NLineInfo".}
+proc setFile(arg: NimNode; filename: string) {.magic: "NLineInfo".}
+
+
 proc internalParseExpr(s: string): NimNode {.
   magic: "ParseExprToAst", noSideEffect.}
 
diff --git a/lib/experimental/quote2.nim b/lib/experimental/quote2.nim
index 173cb08e36fe4..af9b6ae0a1290 100644
--- a/lib/experimental/quote2.nim
+++ b/lib/experimental/quote2.nim
@@ -1,33 +1,57 @@
 import macros
 
-proc newTreeExpr(stmtListExpr, exprNode, unquoteIdent: NimNode): NimNode {.compileTime.} =
+
+#template expectNimNode(arg: NimNode): NimNode = arg
+
+#macro expectNimNode(arg: typed): NimNode =
+#  error("expressions needs to be of type NimNode", arg)
+
+proc expectNimNode[T](arg: T): NimNode = arg
+
+proc newTreeWithLineinfo*(kind: NimNodeKind; lineInfo: LineInfo; children: varargs[NimNode]): NimNode {.compileTime.} =
+  ## like ``macros.newTree``, just that the first argument is a node to take lineinfo from.
+  # TODO lineinfo cannot be forwarded to new node.  I am forced to drop it here.
+  result = newNimNode(kind, nil)
+  result.add(children)
+
+# TODO restrict unquote to nimnode expressions (error message)
+
+const forwardLineinfo = false
+
+proc newTreeExpr(stmtList, exprNode, unquoteIdent: NimNode): NimNode {.compileTime.} =
   # stmtList is a buffer to generate statements
   if exprNode.kind in nnkLiterals:
     result = newCall(bindSym"newLit", exprNode)
   elif exprNode.kind == nnkIdent:
     result = newCall(bindSym"ident", newLit(exprNode.strVal))
   elif exprNode.kind in nnkCallKinds and exprNode.len == 2 and exprNode[0].eqIdent unquoteIdent:
-    result = exprNode[1]
+    result = newCall(bindSym"expectNimNode", exprNode[1])
+    echo result.lispRepr
   elif exprNode.kind == nnkSym:
     error("for quoting the ast needs to be untyped", exprNode)
   elif exprNode.kind == nnkEmpty:
     # bug newTree(nnkEmpty) raises exception:
     result = newCall(bindSym"newEmptyNode")
   else:
-    result = genSym(nskLet)
-    stmtListExpr.add newLetStmt(result, newCall(bindSym"newNimNode", newLit(exprNode.kind))) #, exprNode )
+    if forwardLineInfo:
+      result = newCall(bindSym"newTreeWithLineinfo", newLit(exprNode.kind), newLit(exprNode.lineinfoObj))
+    else:
+      result = newCall(bindSym"newTree", newLit(exprNode.kind))
     for child in exprNode:
-      stmtListExpr.add newCall(bindSym"add", result, newTreeExpr(stmtListExpr, child, unquoteIdent))
+      result.add newTreeExpr(stmtList, child, unquoteIdent)
 
-macro quoteAst(ast: untyped): untyped =
+macro quoteAst*(ast: untyped): untyped =
   ## Substitute for ``quote do`` but with ``uq`` for unquoting instead of backticks.
   result = newNimNode(nnkStmtListExpr)
   result.add result.newTreeExpr(ast, ident"uq")
 
-macro quoteAst(unquoteIdent, ast: untyped): untyped =
+macro quoteAst*(unquoteIdent, ast: untyped): untyped =
   unquoteIdent.expectKind nnkIdent
-  result = newNimNode(nnkStmtListExpr)
-  result.add result.newTreeExpr(ast, unquoteIdent)
+  result = newStmtList()
+  result.add newTreeExpr(result, ast, unquoteIdent)
+
+proc foo(arg1: int, arg2: string): string =
+  "xxx"
 
 macro foobar(arg: untyped): untyped =
   # simple generation of source code:
@@ -54,6 +78,12 @@ macro foobar(arg: untyped): untyped =
   result = quoteAst myUnquote:
     echo "abc ", myUnquote(x), " ", myUnquote(newLit("xyz")), " ", myUnquote(arg)
 
+  #result = quoteAst:
+  #  echo uq(bindSym"foo")(123, "abc")
+
+  result = newTree(NimNodeKind(115), newTree(NimNodeKind(26), ident("echo"), newTree(
+    NimNodeKind(27), expectNimNode(bindSym"foo"), newLit(123), newLit("abc"))))
+
   echo result.treeRepr
 
 let myVal = "Hallo Welt!"
@@ -70,7 +100,6 @@ macro m1(): untyped =
    let r2 = quoteAst:
      type T1 {.id(uq(x)).} = object
 
-
    echo "from #10326:"
    echo r1[0][0].treeRepr
    echo r2[0][0].treeRepr
@@ -82,4 +111,106 @@ macro lineinfoTest(): untyped =
   result = quoteAst:
     assert(false)
 
-lineinfoTest()
+#lineinfoTest()
+
+# example from #7375
+
+macro fails(b: static[bool]): untyped =
+  echo b
+  result = newStmtList()
+
+macro works(b: static[int]): untyped =
+  echo b
+  result = newStmtList()
+
+macro foo(): untyped =
+
+  var b = newLit(false)
+
+  ## Fails
+  result = quote do:
+    fails(`b`)
+
+  ## Works
+  # result = quote do:
+  #   works(`b`)
+
+foo()
+
+
+# example from #9745  (does not work yet)
+# import macros
+
+# var
+#   typ {.compiletime.} = newLit("struct ABC")
+#   name {.compiletime.} = ident("ABC")
+
+# macro abc(): untyped =
+#   result = newNimNode(nnkStmtList)
+
+#   let x = quoteAst:
+#     type
+#       uq(name) {.importc: uq(typ).} = object
+
+#   echo result.repr
+
+# abc()
+
+# example from #7889
+
+from streams import newStringStream, readData, writeData
+import macros
+
+macro bindme*(): untyped =
+  quoteAst:
+    var tst = "sometext"
+    var ss = uq(bindSym"newStringStream")("anothertext")
+    uq(bindSym"writeData")(ss, tst[0].addr, 2)
+    discard uq(bindSym"readData")(ss, tst[0].addr, 2) # <= comment this out to make compilation successful
+
+# test.nim
+# from binder import bindme
+# bindme()
+
+
+# example from #8220
+
+macro fooA(): untyped =
+  result = quoteAst:
+    let bar = "Hello, World"
+    echo &"Let's interpolate {bar} in the string"
+
+foo()
+
+
+# example from #7589
+
+macro fooB(x: untyped): untyped =
+  result = quoteAst:
+    echo uq(bindSym"==")(3,4) # echo ["false"]' has no type (or is ambiguous)
+  echo result.treerepr
+
+# example from #7726
+
+import macros
+
+macro fooC(): untyped =
+  let a = @[1, 2, 3, 4, 5]
+  result = quoteAst:
+    uq(newLit(a.len))
+
+macro fooD(): untyped =
+  let a = @[1, 2, 3, 4, 5]
+  let len = a.len
+  result = quoteAst:
+    uq(newLit(len))
+
+macro fooE(): untyped =
+  let a = @[1, 2, 3, 4, 5]
+  let len = a.len
+  result = quoteAst:
+    uq(newLit(a[2]))
+
+echo fooC() # Outputs 5
+echo fooD() # Outputs 5
+echo fooE() # Outputs 3

From 36e873c8c4d0eb39f650bbe87b73d3d159dc2298 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Arne=20D=C3=B6ring?= <arne.doering@gmx.net>
Date: Wed, 23 Jan 2019 15:23:35 +0100
Subject: [PATCH 3/5] nnkCommentStmt

---
 lib/experimental/quote2.nim | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/lib/experimental/quote2.nim b/lib/experimental/quote2.nim
index af9b6ae0a1290..eca016d40f5a5 100644
--- a/lib/experimental/quote2.nim
+++ b/lib/experimental/quote2.nim
@@ -29,6 +29,8 @@ proc newTreeExpr(stmtList, exprNode, unquoteIdent: NimNode): NimNode {.compileTi
     echo result.lispRepr
   elif exprNode.kind == nnkSym:
     error("for quoting the ast needs to be untyped", exprNode)
+  elif exprNode.kind == nnkCommentStmt:
+    result = newCall(bindSym"newCommentStmtNode", newLit(exprNode.strVal))
   elif exprNode.kind == nnkEmpty:
     # bug newTree(nnkEmpty) raises exception:
     result = newCall(bindSym"newEmptyNode")
@@ -214,3 +216,23 @@ macro fooE(): untyped =
 echo fooC() # Outputs 5
 echo fooD() # Outputs 5
 echo fooE() # Outputs 3
+
+
+# example from #10430
+
+import macros
+
+macro commentTest(arg: untyped): untyped =
+  let tmp = quoteAst:
+    ## comment 1
+    echo "abc"
+    ## comment 2
+    ## still comment 2
+
+  doAssert tmp.treeRepr == arg.treeRepr
+
+commentTest:
+  ## comment 1
+  echo "abc"
+  ## comment 2
+  ## still comment 2

From 62e4707651d0e60580413013cd2779746f682d79 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Arne=20D=C3=B6ring?= <arne.doering@gmx.net>
Date: Thu, 24 Jan 2019 10:16:18 +0100
Subject: [PATCH 4/5] set lineinfoobj

---
 compiler/vm.nim | 32 ++++----------------------------
 1 file changed, 4 insertions(+), 28 deletions(-)

diff --git a/compiler/vm.nim b/compiler/vm.nim
index d4659e77521c4..5bd7e21ed1b64 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1503,39 +1503,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       assert(n.kind == nkObjConstr)
       assert(n.len == 4)
       assert(n[1][0].sym.name.s == "filename")
-      let filename = n[1][1].strVal
+      var filename = n[1][1].strVal
+      if not isAbsolute(filename):
+         filename = parentDir(toFullPath(c.config, c.debug[pc])) / filename
       assert(n[2][0].sym.name.s == "line")
       let line = n[2][1].intVal
       assert(n[3][0].sym.name.s == "column")
       let column = n[3][1].intVal
-
-
-      proc semInstantiationInfo(c: PContext, n: PNode): PNode =
-        result = newNodeIT(nkTupleConstr, n.info, n.typ)
-        let idx = expectIntLit(c, n.sons[1])
-        let useFullPaths = expectIntLit(c, n.sons[2])
-        let info = getInfoContext(c.config, idx)
-        var filename = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
-        filename.strVal = if useFullPaths != 0: toFullPath(c.config, info) else: toFilename(c.config, info)
-        var line = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt))
-        line.intVal = toLinenumber(info)
-        var column = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt))
-        column.intVal = toColumn(info)
-        result.add(filename)
-        result.add(line)
-        result.add(column)
-
-      n.
-      proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
-      proc toAbsolute*(file: string; base: AbsoluteDir): AbsoluteFile =
-
-      regs
-      decodeB(rkNode)
-      echo regs[rb].kind
-      debug(regs[rb].node)
-      regs[ra].node.info = regs[rb].node.info
+      regs[ra].node.info = newLineInfo(c.config, AbsoluteFile(filename), line, column)
     of opcNCopyLineInfo:
-      debug(regs[rb].node)
       regs[ra].node.info = regs[rb].node.info
     of opcEqIdent:
       decodeBC(rkInt)

From f99927f7a22e88d836ff44f77970e93ded475252 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Arne=20D=C3=B6ring?= <arne.doering@gmx.net>
Date: Thu, 24 Jan 2019 12:53:13 +0100
Subject: [PATCH 5/5] setting lineinfo works

---
 compiler/vm.nim             |  7 +++++--
 compiler/vmdef.nim          |  2 +-
 compiler/vmgen.nim          |  7 ++-----
 lib/core/macros.nim         |  6 ------
 lib/experimental/quote2.nim | 25 ++++++++++++++-----------
 5 files changed, 22 insertions(+), 25 deletions(-)

diff --git a/compiler/vm.nim b/compiler/vm.nim
index 5bd7e21ed1b64..3951f76f674a1 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -19,6 +19,7 @@ import
 
 from semfold import leValueConv, ordinalValToString
 from evaltempl import evalTemplate
+from os import isAbsolute, parentDir, `/`
 
 from modulegraphs import ModuleGraph, PPassContext
 
@@ -1499,6 +1500,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       regs[ra].node.info = n.info
       regs[ra].node.typ = n.typ
     of opcNSetLineInfoObj:
+      decodeB(rkNode)
       let n = regs[rb].node
       assert(n.kind == nkObjConstr)
       assert(n.len == 4)
@@ -1507,11 +1509,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       if not isAbsolute(filename):
          filename = parentDir(toFullPath(c.config, c.debug[pc])) / filename
       assert(n[2][0].sym.name.s == "line")
-      let line = n[2][1].intVal
+      let line = n[2][1].intVal.int
       assert(n[3][0].sym.name.s == "column")
-      let column = n[3][1].intVal
+      let column = n[3][1].intVal.int
       regs[ra].node.info = newLineInfo(c.config, AbsoluteFile(filename), line, column)
     of opcNCopyLineInfo:
+      decodeB(rkNode)
       regs[ra].node.info = regs[rb].node.info
     of opcEqIdent:
       decodeBC(rkInt)
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index a43f8dbba52a8..1a2e5c0d9ea15 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -107,7 +107,7 @@ type
     opcNError,
     opcNWarning,
     opcNHint,
-    opcNGetLineInfo, opcNSetLineInfo,
+    opcNGetLineInfo, opcNSetLineInfoObj, opcNCopyLineInfo,
     opcEqIdent,
     opcStrToIdent,
     opcGetImpl,
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 930dd69765d95..353df363b0336 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1231,14 +1231,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     of "getFile": genUnaryABI(c, n, dest, opcNGetLineInfo, 0)
     of "getLine": genUnaryABI(c, n, dest, opcNGetLineInfo, 1)
     of "getColumn": genUnaryABI(c, n, dest, opcNGetLineInfo, 2)
-    of "setFile": genBinaryStmt(c, n, opcNSetLineInfo)
-    of "setLine": genBinaryStmt(c, n, opcNSetLineInfo)
-    of "setColumn": genBinaryStmt(c, n, opcNSetLineInfo)
-    of "lineInfoObj=": genBinaryStmt(c, n, opcNSetLineInfo)
+    of "lineInfoObj=": genBinaryStmt(c, n, opcNSetLineInfoObj)
     of "copyLineInfo":
       internalAssert c.config, n.len == 3
       unused(c, n, dest)
-      genBinaryStmt(c, n, opcNSetLineInfo)
+      genBinaryStmt(c, n, opcNCopyLineInfo)
     else:
       internalAssert c.config, false
   of mNHint:
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 17cb4e87c525c..5300766b9e301 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -489,14 +489,8 @@ proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} =
 proc lineInfo*(arg: NimNode): string {.compileTime.} =
   $arg.lineInfoObj
 
-
 proc `lineInfoObj=`*(n: NimNode; lineinfo: LineInfo) {.magic: "NLineInfo".}
 
-proc setLine(arg: NimNode; line: int) {.magic: "NLineInfo".}
-proc setColumn(arg: NimNode; column: int) {.magic: "NLineInfo".}
-proc setFile(arg: NimNode; filename: string) {.magic: "NLineInfo".}
-
-
 proc internalParseExpr(s: string): NimNode {.
   magic: "ParseExprToAst", noSideEffect.}
 
diff --git a/lib/experimental/quote2.nim b/lib/experimental/quote2.nim
index eca016d40f5a5..7e91e40d3aaae 100644
--- a/lib/experimental/quote2.nim
+++ b/lib/experimental/quote2.nim
@@ -1,22 +1,21 @@
 import macros
 
-
-#template expectNimNode(arg: NimNode): NimNode = arg
-
-#macro expectNimNode(arg: typed): NimNode =
-#  error("expressions needs to be of type NimNode", arg)
+# template expectNimNode(arg: NimNode): NimNode = arg
+# macro expectNimNode(arg: typed): NimNode =
+#   error("expressions needs to be of type NimNode", arg)
 
 proc expectNimNode[T](arg: T): NimNode = arg
 
-proc newTreeWithLineinfo*(kind: NimNodeKind; lineInfo: LineInfo; children: varargs[NimNode]): NimNode {.compileTime.} =
+proc newTreeWithLineinfo*(kind: NimNodeKind; lineinfo: LineInfo; children: varargs[NimNode]): NimNode {.compileTime.} =
   ## like ``macros.newTree``, just that the first argument is a node to take lineinfo from.
   # TODO lineinfo cannot be forwarded to new node.  I am forced to drop it here.
   result = newNimNode(kind, nil)
+  result.lineinfoObj = lineinfo
   result.add(children)
 
 # TODO restrict unquote to nimnode expressions (error message)
 
-const forwardLineinfo = false
+const forwardLineinfo = true
 
 proc newTreeExpr(stmtList, exprNode, unquoteIdent: NimNode): NimNode {.compileTime.} =
   # stmtList is a buffer to generate statements
@@ -26,7 +25,6 @@ proc newTreeExpr(stmtList, exprNode, unquoteIdent: NimNode): NimNode {.compileTi
     result = newCall(bindSym"ident", newLit(exprNode.strVal))
   elif exprNode.kind in nnkCallKinds and exprNode.len == 2 and exprNode[0].eqIdent unquoteIdent:
     result = newCall(bindSym"expectNimNode", exprNode[1])
-    echo result.lispRepr
   elif exprNode.kind == nnkSym:
     error("for quoting the ast needs to be untyped", exprNode)
   elif exprNode.kind == nnkCommentStmt:
@@ -47,6 +45,9 @@ macro quoteAst*(ast: untyped): untyped =
   result = newNimNode(nnkStmtListExpr)
   result.add result.newTreeExpr(ast, ident"uq")
 
+  echo "quoteAst:"
+  echo result.repr
+
 macro quoteAst*(unquoteIdent, ast: untyped): untyped =
   unquoteIdent.expectKind nnkIdent
   result = newStmtList()
@@ -83,11 +84,13 @@ macro foobar(arg: untyped): untyped =
   #result = quoteAst:
   #  echo uq(bindSym"foo")(123, "abc")
 
-  result = newTree(NimNodeKind(115), newTree(NimNodeKind(26), ident("echo"), newTree(
-    NimNodeKind(27), expectNimNode(bindSym"foo"), newLit(123), newLit("abc"))))
-
   echo result.treeRepr
 
+  # result = quoteAst:
+  #   var tmp = 1
+  #   for x in 0 ..< 100:
+  #     tmp *= 3
+
 let myVal = "Hallo Welt!"
 foobar(myVal)