Something like this?
import macros
proc clean(a, b: int) : int =
result = 2 * a + b
proc dirty(a,b:int): int =
echo "dirty"
3
macro hasNoSideEffects(p : typed) : untyped =
result = newCall("compiles", newNimNode(nnkProcDef))
let frm = p.symbol.getImpl
var i = 0
# frm has an additional result node at the end, this ugly loop
# is to construct our procDef without altering the original proc.
while i < frm.len-1:
if i == frm.len-1: break
result[1].add(frm[i])
inc i
addPragma(result[1], newIdentNode("noSideEffect"))
echo hasNoSideEffects(clean) # true
echo hasNoSideEffects(dirty) # false
As NimNodes are `ref` types, I don't think you should change the ones returned
from getImpl directly ( I may be wrong though ).
( There are probably better ways to get all childs except the last, but I can't
seem to find them. )
When dealing with macros, it's usually useful to compare the ast you generate
with the ast printed by `dumpTree`, eg:
import macros
dumpTree:
proc clean(a, b: int) : int {.noSideEffect.} =
result = 2 * a + b