summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2016-04-03 23:38:29 +0200
committerAndreas Rumpf <rumpf_a@web.de>2016-04-03 23:38:29 +0200
commitcb3a38afa2de4401af55fbb7b6050f499b182bf4 (patch)
tree7cb34d8933480dedcab82281a39f491fbf545368
parent6e53300f83dc7646fbad834c494c34470a393885 (diff)
downloadNim-cb3a38afa2de4401af55fbb7b6050f499b182bf4.tar.gz
fixes #1152
-rw-r--r--doc/manual/typedesc.txt32
-rw-r--r--tests/macros/typesafeprintf.nim48
2 files changed, 48 insertions, 32 deletions
diff --git a/doc/manual/typedesc.txt b/doc/manual/typedesc.txt
index de1d84d7d..6922d77e4 100644
--- a/doc/manual/typedesc.txt
+++ b/doc/manual/typedesc.txt
@@ -77,38 +77,6 @@ Once bound, typedesc params can appear in the rest of the proc signature:
 
   declareVariableWithType int, 42
 
-When used with macros and .compileTime. procs on the other hand, the compiler
-does not need to instantiate the code multiple times, because types then can be
-manipulated using the unified internal symbol representation. In such context
-typedesc acts as any other type. One can create variables, store typedesc
-values inside containers and so on. For example, here is how one can create
-a type-safe wrapper for the unsafe `printf` function from C:
-
-.. code-block:: nim
-  macro safePrintF(formatString: string{lit}, args: varargs[expr]): expr =
-    var i = 0
-    for c in formatChars(formatString):
-      var expectedType = case c
-        of 'c': char
-        of 'd', 'i', 'x', 'X': int
-        of 'f', 'e', 'E', 'g', 'G': float
-        of 's': string
-        of 'p': pointer
-        else: EOutOfRange
-
-      var actualType = args[i].getType
-      inc i
-
-      if expectedType == EOutOfRange:
-        error c & " is not a valid format character"
-      elif expectedType != actualType:
-        error "type mismatch for argument ", i, ". expected type: ",
-              expectedType.name, ", actual type: ", actualType.name
-
-    # keep the original callsite, but use cprintf instead
-    result = callsite()
-    result[0] = newIdentNode(!"cprintf")
-
 
 Overload resolution can be further influenced by constraining the set of
 types that will match the typedesc param:
diff --git a/tests/macros/typesafeprintf.nim b/tests/macros/typesafeprintf.nim
new file mode 100644
index 000000000..2f4622f3e
--- /dev/null
+++ b/tests/macros/typesafeprintf.nim
@@ -0,0 +1,48 @@
+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 true:
+    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 = callsite()
+  result[0] = bindSym"printfImpl"
+
+printf("test %d\n", 10)