mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
fixes #1152
This commit is contained in:
@@ -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:
|
||||
|
||||
48
tests/macros/typesafeprintf.nim
Normal file
48
tests/macros/typesafeprintf.nim
Normal 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)
|
||||
Reference in New Issue
Block a user