summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorPeter Munch-Ellingsen <peterme@peterme.net>2022-12-22 04:34:36 +0100
committerGitHub <noreply@github.com>2022-12-22 04:34:36 +0100
commit613829f7a4da5506269fadb3acc78d64ee0cbddf (patch)
tree2b903c1ebf0f6f91f61c6faa5acce2d29b8640e9
parentd0721eadf8cd6bf9436b5e5c9113c4c7bcfcc770 (diff)
downloadNim-613829f7a4da5506269fadb3acc78d64ee0cbddf.tar.gz
Implement setLineInfo (#21153)
* Implement setLineInfo

* Add tests
-rw-r--r--compiler/msgs.nim7
-rw-r--r--compiler/vm.nim14
-rw-r--r--compiler/vmdef.nim3
-rw-r--r--compiler/vmgen.nim14
-rw-r--r--lib/core/macros.nim16
-rw-r--r--tests/macros/tmacros_various.nim23
6 files changed, 72 insertions, 5 deletions
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 2c807806e..8b44c8dc6 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -128,6 +128,13 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
   var dummy: bool
   result = fileInfoIdx(conf, filename, dummy)
 
+proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile; isKnownFile: var bool): FileIndex =
+  fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), isKnownFile)
+
+proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex =
+  var dummy: bool
+  fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
+
 proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
   result.fileIndex = fileInfoIdx
   if line < int high(uint16):
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 53a16bcb0..61261c44c 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1934,14 +1934,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       of 1: # getLine
         regs[ra].node = newIntNode(nkIntLit, n.info.line.int)
       of 2: # getColumn
-        regs[ra].node = newIntNode(nkIntLit, n.info.col)
+        regs[ra].node = newIntNode(nkIntLit, n.info.col.int)
       else:
         internalAssert c.config, false
       regs[ra].node.info = n.info
       regs[ra].node.typ = n.typ
-    of opcNSetLineInfo:
+    of opcNCopyLineInfo:
       decodeB(rkNode)
       regs[ra].node.info = regs[rb].node.info
+    of opcNSetLineInfoLine:
+      decodeB(rkNode)
+      regs[ra].node.info.line = regs[rb].intVal.uint16
+    of opcNSetLineInfoColumn:
+      decodeB(rkNode)
+      regs[ra].node.info.col = regs[rb].intVal.int16
+    of opcNSetLineInfoFile:
+      decodeB(rkNode)
+      regs[ra].node.info.fileIndex =
+        fileInfoIdx(c.config, RelativeFile regs[rb].node.strVal)
     of opcEqIdent:
       decodeBC(rkInt)
       # aliases for shorter and easier to understand code below
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 54876f37d..114a49557 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -141,7 +141,8 @@ type
     opcNError,
     opcNWarning,
     opcNHint,
-    opcNGetLineInfo, opcNSetLineInfo,
+    opcNGetLineInfo, opcNCopyLineInfo, opcNSetLineInfoLine,
+    opcNSetLineInfoColumn, opcNSetLineInfoFile
     opcEqIdent,
     opcStrToIdent,
     opcGetImpl,
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 1fdfea7c4..6a2ab1d11 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1335,7 +1335,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     of "copyLineInfo":
       internalAssert c.config, n.len == 3
       unused(c, n, dest)
-      genBinaryStmt(c, n, opcNSetLineInfo)
+      genBinaryStmt(c, n, opcNCopyLineInfo)
+    of "setLine":
+      internalAssert c.config, n.len == 3
+      unused(c, n, dest)
+      genBinaryStmt(c, n, opcNSetLineInfoLine)
+    of "setColumn":
+      internalAssert c.config, n.len == 3
+      unused(c, n, dest)
+      genBinaryStmt(c, n, opcNSetLineInfoColumn)
+    of "setFile":
+      internalAssert c.config, n.len == 3
+      unused(c, n, dest)
+      genBinaryStmt(c, n, opcNSetLineInfoFile)
     else: internalAssert c.config, false
   of mNHint:
     unused(c, n, dest)
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 18a70f20c..138ec47a0 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -533,6 +533,22 @@ proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.}
 proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.}
   ## Copy lineinfo from `info`.
 
+proc setLine(arg: NimNode, line: uint16) {.magic: "NLineInfo", noSideEffect.}
+proc setColumn(arg: NimNode, column: int16) {.magic: "NLineInfo", noSideEffect.}
+proc setFile(arg: NimNode, file: string) {.magic: "NLineInfo", noSideEffect.}
+
+proc setLineInfo*(arg: NimNode, file: string, line: int, column: int) =
+  ## Sets the line info on the NimNode. The file needs to exists, but can be a
+  ## relative path. If you want to attach line info to a block using `quote`
+  ## you'll need to add the line information after the quote block.
+  arg.setFile(file)
+  arg.setLine(line.uint16)
+  arg.setColumn(column.int16)
+
+proc setLineInfo*(arg: NimNode, lineInfo: LineInfo) =
+  ## See `setLineInfo proc<#setLineInfo,NimNode,string,int,int>`_
+  setLineInfo(arg, lineInfo.filename, lineInfo.line, lineInfo.column)
+
 proc lineInfoObj*(n: NimNode): LineInfo =
   ## Returns `LineInfo` of `n`, using absolute path for `filename`.
   result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn)
diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim
index d702db56a..08be4602c 100644
--- a/tests/macros/tmacros_various.nim
+++ b/tests/macros/tmacros_various.nim
@@ -91,7 +91,7 @@ block tlexerex:
 
 
 
-block tlineinfo:
+block tcopylineinfo:
   # issue #5617, feature request
   type Test = object
 
@@ -103,6 +103,27 @@ block tlineinfo:
   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: