discard """
nimout: '''
IntLit 5
proc (x: int): string => typeDesc[proc[string, int]]
proc (x: int): void => typeDesc[proc[void, int]]
proc (x: int) => typeDesc[proc[void, int]]
x => seq[int]
a
s
d
f
TTaa
TTaa
TTaa
TTaa
true
true
nil
42
false
true
@[i0, i1, i2, i3, i4]
@[tmp, tmp, tmp, tmp, tmp]
'''
output: '''
range[0 .. 100]
array[0 .. 100, int]
10
test
0o377'i8
0o000000000755'i32
1
2
3
foo1
foo2
foo3
true
false
true
false
1.0
'''
"""
import macros, parseutils
block t7723:
macro foo1(): untyped =
result = newStmtList()
result.add quote do:
proc init(foo: int, bar: typedesc[int]): int =
foo
#expandMacros:
foo1()
doAssert init(1, int) == 1
block t8706:
macro varargsLen(args:varargs[untyped]): untyped =
doAssert args.kind == nnkArglist
doAssert args.len == 0
result = newLit(args.len)
template bar(a0:varargs[untyped]): untyped =
varargsLen(a0)
template foo(x: int, a0:varargs[untyped]): untyped =
bar(a0)
doAssert foo(42) == 0
doAssert bar() == 0
block t9194:
type
Foo1 = range[0 .. 100]
Foo2 = array[0 .. 100, int]
macro get(T: typedesc): untyped =
# Get the X out of typedesc[X]
let tmp = getTypeImpl(T)
result = newStrLitNode(getTypeImpl(tmp[1]).repr)
echo Foo1.get
echo Foo2.get
block t1944:
template t(e: untyped): untyped =
macro m(eNode: untyped): untyped =
echo eNode.treeRepr
m e
t 5
block t926:
proc test(f: var NimNode) {.compileTime.} =
f = newNimNode(nnkStmtList)
f.add newCall(newIdentNode("echo"), newLit(10))
macro blah(prc: untyped): untyped =
result = prc
test(result)
proc test() {.blah.} =
echo 5
block t2211:
macro showType(t:typed): untyped =
let ty = t.getType
echo t.repr, " => ", ty.repr
showType(proc(x:int): string)
showType(proc(x:int): void)
showType(proc(x:int))
var x: seq[int]
showType(x)
block t1140:
proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =
var splitValue: string
var read = value.parseUntil(splitValue, '$', index)
# when false:
if false:
var identifier: string
read = value.parseWhile(identifier, {}, index)
node.add newCall("add", ident("result"), newCall("$", ident(identifier)))
if splitValue.len > 0:
node.insert node.len, newCall("add", ident("result"), newStrLitNode(splitValue))
proc parse_template(node: NimNode, value: string) {.compiletime.} =
var index = 0
while index < value.len and
parse_until_symbol(node, value, index): discard
macro tmpli(body: untyped): typed =
result = newStmtList()
result.add parseExpr("result = \"\"")
result.parse_template body[1].strVal
proc actual: string {.used.} = tmpli html"""
Test!
"""
proc another: string {.used.} = tmpli html"""
what
"""
block tbugs:
type
Foo = object
s: char
iterator test2(f: string): Foo =
for i in f:
yield Foo(s: i)
macro test(): untyped =
for i in test2("asdf"):
echo i.s
test()
# bug 1297
type TType = tuple[s: string]
macro echotest(): untyped =
var t: TType
t.s = ""
t.s.add("test")
result = newCall(newIdentNode("echo"), newStrLitNode(t.s))
echotest()
# bug #1103
type
Td = tuple
a:string
b:int
proc get_data(d: Td) : string {.compileTime.} =
result = d.a # Works if a literal string is used here.
# Bugs if line A or B is active. Works with C
result &= "aa" # A
#result.add("aa") # B
#result = result & "aa" # C
macro m(s:static[Td]) : untyped =
echo get_data(s)
echo get_data(s)
result = newEmptyNode()
const s = ("TT", 3)
m(s)
m(s)
# bug #933
proc nilcheck(): NimNode {.compileTime.} =
echo(result == nil) # true
echo(result.isNil) # true
echo(repr(result)) # nil
macro testnilcheck(): untyped =
result = newNimNode(nnkStmtList)
discard nilcheck()
testnilcheck()
# bug #1323
proc calc(): array[1, int] =
result[0].inc()
result[0].inc()
const c = calc()
doAssert c[0] == 2
# bug #3046
macro sampleMacroInt(i: int): untyped =
echo i.intVal
macro sampleMacroBool(b: bool): untyped =
echo b.boolVal
sampleMacroInt(42)
sampleMacroBool(false)
sampleMacroBool(system.true)
# bug #11131
macro toRendererBug(n): untyped =
result = newLit repr(n)
echo toRendererBug(0o377'i8)
echo toRendererBug(0o755'i32)
# bug #12129
macro foobar() =
var loopVars = newSeq[NimNode](5)
for i, sym in loopVars.mpairs():
sym = ident("i" & $i)
echo loopVars
for sym in loopVars.mitems():
sym = ident("tmp")
echo loopVars
foobar()
# bug #13253
import macros
type
FooBar = object
a: seq[int]
macro genFoobar(a: static FooBar): untyped =
result = newStmtList()
for b in a.a:
result.add(newCall(bindSym"echo", newLit b))
proc foobar(a: static FooBar) =
genFoobar(a) # removing this make it work
for b in a.a:
echo "foo" & $b
proc main() =
const a: seq[int] = @[1, 2,3]
# Error: type mismatch: got but expected 'seq[int]'
const fb = Foobar(a: a)
foobar(fb)
main()
# bug #13484
proc defForward(id, nid: NimNode): NimNode =
result = newProc(id, @[newIdentNode("bool"), newIdentDefs(nid, newIdentNode("int"))], body=newEmptyNode())
proc defEven(evenid, oddid, nid: NimNode): NimNode =
result = quote do:
proc `evenid`(`nid`: int): bool =
if `nid` == 0:
return true
else:
return `oddid`(`nid` - 1)
proc defOdd(evenid, oddid, nid: NimNode): NimNode =
result = quote do:
proc `oddid`(`nid`: int): bool =
if `nid` == 0:
return false
else:
return `evenid`(`nid` - 1)
proc callNode(funid, param: NimNode): NimNode =
result = quote do:
`funid`(`param`)
macro testEvenOdd3(): untyped =
let
evenid = newIdentNode("even3")
oddid = newIdentNode("odd3")
nid = newIdentNode("n")
oddForward = defForward(oddid, nid)
even = defEven(evenid, oddid, nid)
odd = defOdd(evenid, oddid, nid)
callEven = callNode(evenid, newLit(42))
callOdd = callNode(oddid, newLit(42))
result = quote do:
`oddForward`
`even`
`odd`
echo `callEven`
echo `callOdd`
macro testEvenOdd4(): untyped =
let
evenid = newIdentNode("even4")
oddid = newIdentNode("odd4")
nid = newIdentNode("n")
oddForward = defForward(oddid, nid)
even = defEven(evenid, oddid, nid)
odd = defOdd(evenid, oddid, nid)
callEven = callNode(evenid, newLit(42))
callOdd = callNode(oddid, newLit(42))
# rewrite the body of proc node.
oddForward[6] = newStmtList()
result = quote do:
`oddForward`
`even`
`odd`
echo `callEven`
echo `callOdd`
macro testEvenOdd5(): untyped =
let
evenid = genSym(nskProc, "even5")
oddid = genSym(nskProc, "odd5")
nid = newIdentNode("n")
oddForward = defForward(oddid, nid)
even = defEven(evenid, oddid, nid)
odd = defOdd(evenid, oddid, nid)
callEven = callNode(evenid, newLit(42))
callOdd = callNode(oddid, newLit(42))
result = quote do:
`oddForward`
`even`
`odd`
echo `callEven`
echo `callOdd`
macro testEvenOdd6(): untyped =
let
evenid = genSym(nskProc, "even6")
oddid = genSym(nskProc, "odd6")
nid = newIdentNode("n")
oddForward = defForward(oddid, nid)
even = defEven(evenid, oddid, nid)
odd = defOdd(evenid, oddid, nid)
callEven = callNode(evenid, newLit(42))
callOdd = callNode(oddid, newLit(42))
# rewrite the body of proc node.
oddForward[6] = newStmtList()
result = quote do:
`oddForward`
`even`
`odd`
echo `callEven`
echo `callOdd`
# it works
testEvenOdd3()
# it causes an error (redefinition of odd4), which is correct
assert not compiles testEvenOdd4()
# it caused an error (still forwarded: odd5)
testEvenOdd5()
# it works, because the forward decl and definition share the symbol and the compiler is forgiving here
#testEvenOdd6() #Don't test it though, the compiler may become more strict in the future
# bug #15385
var captured_funcs {.compileTime.}: seq[NimNode] = @[]
macro aad*(fns: varargs[typed]): typed =
result = newStmtList()
for fn in fns:
captured_funcs.add fn[0]
result.add fn
func exp*(x: float): float ## get different error if you remove forward declaration
func exp*(x: float): float {.aad.} =
var x1 = min(max(x, -708.4), 709.8)
var result: float ## looks weird because it is taken from template expansion
result = x1 + 1.0
result
template check_accuracy(f: untyped, rng: Slice[float], n: int, verbose = false): auto =
proc check_accuracy: tuple[avg_ulp: float, max_ulp: int] {.gensym.} =
let k = (rng.b - rng.a) / (float) n
var
res, x: float
i, max_ulp = 0
avg_ulp = 0.0
x = rng.a
while (i < n):
res = f(x)
i.inc
x = x + 0.001
(avg_ulp, max_ulp)
check_accuracy()
discard check_accuracy(exp, -730.0..709.4, 4)
# And without forward decl
macro aad2*(fns: varargs[typed]): typed =
result = newStmtList()
for fn in fns:
captured_funcs.add fn[0]
result.add fn
func exp2*(x: float): float {.aad2.} =
var x1 = min(max(x, -708.4), 709.8)
var result: float ## looks weird because it is taken from template expansion
result = x1 + 1.0
result
template check_accuracy2(f: untyped, rng: Slice[float], n: int, verbose = false): auto =
proc check_accuracy2: tuple[avg_ulp: float, max_ulp: int] {.gensym.} =
let k = (rng.b - rng.a) / (float) n
var
res, x: float
i, max_ulp = 0
avg_ulp = 0.0
x = rng.a
while (i < n):
res = f(x)
i.inc
x = x + 0.001
(avg_ulp, max_ulp)
check_accuracy2()
discard check_accuracy2(exp2, -730.0..709.4, 4)
# And minimized:
macro aadMin(fn: typed): typed = fn
func expMin: float
func expMin: float {.aadMin.} = 1
echo expMin()
# issue #15389
block double_sem_for_procs:
macro aad(fns: varargs[typed]): typed =
result = newStmtList()
for fn in fns:
result.add fn
func exp(x: float): float {.aad.} =
var x1 = min(max(x, -708.4), 709.8)
if x1 > 0.0:
return x1 + 1.0
result = 10.0
discard exp(5.0)