summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2016-10-27 15:37:34 +0200
committerGitHub <noreply@github.com>2016-10-27 15:37:34 +0200
commitcacbf8b32c7b910eeb6b8b5d37adf2a7dd2f343c (patch)
treefaddd5fb0ea8009db010f75c8bdff642ab5e4c2e
parent38ad7400fa4ecc475b587456770e4d981dc9d037 (diff)
parent74c6500a30b99fde9af5d17a87723dcf18309964 (diff)
downloadNim-cacbf8b32c7b910eeb6b8b5d37adf2a7dd2f343c.tar.gz
Merge pull request #4963 from jangko/macro_error_improvement
Macro.error improvement fixes #4915
-rw-r--r--compiler/vm.nim12
-rw-r--r--compiler/vmgen.nim2
-rw-r--r--lib/core/macros.nim8
-rw-r--r--tests/clearmsg/tmacroerrorproc.nim13
-rw-r--r--web/news/e029_version_0_16_0.rst2
5 files changed, 28 insertions, 9 deletions
diff --git a/compiler/vm.nim b/compiler/vm.nim
index be522ced0..c4e8df90e 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -76,12 +76,13 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
     msgWriteln(s)
 
 proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
-                msg: TMsgKind, arg = "") =
+                msg: TMsgKind, arg = "", n: PNode = nil) =
   msgWriteln("stack trace: (most recent call last)")
   stackTraceAux(c, tos, pc)
   # XXX test if we want 'globalError' for every mode
-  if c.mode == emRepl: globalError(c.debug[pc], msg, arg)
-  else: localError(c.debug[pc], msg, arg)
+  let lineInfo = if n == nil: c.debug[pc] else: n.info
+  if c.mode == emRepl: globalError(lineInfo, msg, arg)
+  else: localError(lineInfo, msg, arg)
 
 proc bailOut(c: PCtx; tos: PStackFrame) =
   stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
@@ -1245,7 +1246,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
                                      regs[rc].node.strVal, regs[rd].node.strVal,
                                      c.debug[pc])
     of opcNError:
-      stackTrace(c, tos, pc, errUser, regs[ra].node.strVal)
+      decodeB(rkNode)
+      let a = regs[ra].node
+      let b = regs[rb].node
+      stackTrace(c, tos, pc, errUser, a.strVal, if b.kind == nkNilLit: nil else: b)
     of opcNWarning:
       message(c.debug[pc], warnUser, regs[ra].node.strVal)
     of opcNHint:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 6bfc33f00..ed8f3f338 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1068,7 +1068,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     else:
       # setter
       unused(n, dest)
-      genUnaryStmt(c, n, opcNError)
+      genBinaryStmt(c, n, opcNError)
   of mNCallSite:
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABC(n, opcCallSite, dest)
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index d584b1ac5..b0ef54397 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -235,7 +235,7 @@ proc getImpl*(s: NimSym): NimNode {.magic: "GetImpl", noSideEffect.} =
   ## const.
   discard
 
-proc error*(msg: string) {.magic: "NError", benign.}
+proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.}
   ## writes an error message at compile time
 
 proc warning*(msg: string) {.magic: "NWarning", benign.}
@@ -377,19 +377,19 @@ proc expectKind*(n: NimNode, k: NimNodeKind) {.compileTime.} =
   ## checks that `n` is of kind `k`. If this is not the case,
   ## compilation aborts with an error message. This is useful for writing
   ## macros that check the AST that is passed to them.
-  if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind)
+  if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind, n)
 
 proc expectMinLen*(n: NimNode, min: int) {.compileTime.} =
   ## checks that `n` has at least `min` children. If this is not the case,
   ## compilation aborts with an error message. This is useful for writing
   ## macros that check its number of arguments.
-  if n.len < min: error("macro expects a node with " & $min & " children")
+  if n.len < min: error("macro expects a node with " & $min & " children", n)
 
 proc expectLen*(n: NimNode, len: int) {.compileTime.} =
   ## checks that `n` has exactly `len` children. If this is not the case,
   ## compilation aborts with an error message. This is useful for writing
   ## macros that check its number of arguments.
-  if n.len != len: error("macro expects a node with " & $len & " children")
+  if n.len != len: error("macro expects a node with " & $len & " children", n)
 
 proc newTree*(kind: NimNodeKind,
               children: varargs[NimNode]): NimNode {.compileTime.} =
diff --git a/tests/clearmsg/tmacroerrorproc.nim b/tests/clearmsg/tmacroerrorproc.nim
new file mode 100644
index 000000000..9a6ff6a06
--- /dev/null
+++ b/tests/clearmsg/tmacroerrorproc.nim
@@ -0,0 +1,13 @@
+discard """
+  file: "tmacroerrorproc.nim"
+  line: 13
+  errormsg: "Expected a node of kind nnkCharLit, got nnkCommand"
+"""
+# issue #4915
+import macros
+
+macro mixer(n: typed): untyped =
+  expectKind(n, nnkCharLit)
+  
+mixer:
+  echo "owh"
\ No newline at end of file
diff --git a/web/news/e029_version_0_16_0.rst b/web/news/e029_version_0_16_0.rst
index 1d3f3b3df..2f6c72c82 100644
--- a/web/news/e029_version_0_16_0.rst
+++ b/web/news/e029_version_0_16_0.rst
@@ -31,6 +31,8 @@ Changes affecting backwards compatibility
 Library Additions
 -----------------
 
+- Added new parameter to ``error`` proc of ``macro`` module to provide better
+  error message
 
 Tool Additions
 --------------