This commit is contained in:
Andreas Rumpf
2016-04-03 23:38:29 +02:00
parent 6e53300f83
commit cb3a38afa2
2 changed files with 48 additions and 32 deletions

View File

@@ -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:

View File

@@ -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)