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

Reply via email to