I tried asking yesterday on IRC channel, but I wasn't able to express myself accordingly. I suspect that feature I'm asking for exists in Nimrod, but I couldn't find it anywhere.
Essentially I'm trying to do what I would do in Lisp using eval.
Let's say I can write a macro with a hypothetical eval flag:
macro doSomethingComplicated(a: seq[string]{eval}):
var code = ""
for item in a: # a has type seq[string], not PNimrodNode as in normal macro without {eval}
code.add doSomethingElse(item)
parseStmt(code)
And I want to call it like this:
doSomethingCompilicated(@["1", "2", "3"])
Or maybe other example
proc foo(): int =
return 9
macro f(a: int{eval}): stmt =
echo a.repr
parseStmt("discard")
f(5 + foo())
In current Nimrod (without hypothetical eval) a is of type PNimrodNode and example echoes:
5 + foo()
I would like a to be an integer and get:
14
I know that I can implement these examples without the hypothetical eval, but I feel that's too much boilerplate, because VM already has ability to transform AST to objects. (Also, in second example the only solution that comes to my mind is wrapping macro in a template that creates temporary const to force compile-time evaluation)
Unfortunately static[int] is not what I was searching for.
import macros
macro f(i: static[int]): stmt =
echo "is this int: ", i is int
echo "hello ", i.repr, "!"
parseStmt("discard")
proc foobar(): int = 5
f(5 + foobar())
Prints:
is this int: false
hello 5 + foobar()!
I would expect:
is this int: true
hello 10!
And:
import macros
macro f(args: static[seq[int]]): stmt =
for i in args:
echo "got arg ", i
parseStmt("discard")
f(@[1, 2, 3])
Fails with:
Error: unhandled exception: not (regs[rb].kind == nkMetaNode) [EAssertionFailed]
I've also tried other combinations:
import macros
macro f[T: static[int]](): stmt =
echo T.repr
parseStmt("discard 123")
f[5]()
->
g.nim(4, 7) Error: internal error: cannot generate code for: T
or:
import macros
macro f[T](i: static[T]): stmt =
echo i.repr
parseStmt("discard 123")
f[int](5)
->
g.nim(4, 8) Error: type mismatch: got (static[T])
but expected one of:
system.repr(x: T): string
The behavior of compile time code is strange...
import macros, typetraits
macro f(i: static[int]): stmt =
let k = i + 1
echo "k=", k
parseStmt("discard")
proc foobar(): int = 5
f(5 + foobar())
prints
k=140486155853649
I'm not sure if this is a bug or just some default value...In defence of static[T], it currently relies to some extent on the generic instantiation system, which means that and you'll get much better results with procs. For example, all of the attempts here will work for procs. I'll try to get the macro version into a better shape, but some pieces like the last "generic macro" will be particularly problematic.
In the meantime, depending on your goals, you may work-around the problem by introducing a proc, whose body is completely generated by a macro:
proc f(x: static[int]) =
macro generateBody: stmt =
echo x
generateBody()
proc foo: int = 10
f foo() + 2