Recently I'd been trying to learn how to use `rawProc`. The documentation have
stated that it could be useful, but not how it's used. It seems to return a
`pointer` that points to a procedure, but it's unknown how many parameters that
proc takes, of what calling convention it is. Also it seems to take an
additional environment-pointer (as stated in the manual), but I didn't know if
that should be the first or the last argument. So I decided to figure it out.
>From the generated C code, I can see that a closure is consisted of a proc and
>an additional pointer (which is also stated in the manual). The underlying
>proc is `{.nimcall.}`. The environment is the last parameter, not the first.
When it is called, it's checked if the environment is `nil`, and if it is, the
underlying proc is casted into another type and called _without_ the
environment pointer, otherwise it's called with the environment and other
arguments.
The type which the underlying proc could be casted into is defined with
`N_CLOSURE_PTR`, which, according to `nimbase.h`, is now an alias for
`N_NIMCALL_PTR`.
Therefore the correct usage seems to be
import sugar
proc makeClosure(x: int): ((int) -> int) =
var n = x
result = (
proc(y: int): int =
n += y
return n
)
proc main =
var
c1 = makeClosure(10)
e = c1.rawEnv()
p = c1.rawProc()
if e.isNil():
let c2 = cast[proc(y: int): int {.nimcall.}](p)
echo c2(2)
else:
let c3 = cast[proc(y: int, env: pointer): int {.nimcall.}](p)
echo c3(3, e)
main()
Run