[Parrot-users] how do I pass obj** to a C function from parrot?

Allison Randal allison at parrot.org
Sun Nov 29 13:21:04 UTC 2009


Vadim Konovalov wrote:
> Hi,
> 
> I have following problem.
> 
> One function returns TclObj*
> Another function takes TclObj** as argument, which is actually an
> array of TclObj*, which I should pass to that another function.
> 
> So I have some functions declared like following:
> 
>     func1 = dlfunc libtcl, "Tcl_NewStringObj", "pti"
>     func2 = dlfunc libtcl, "Tcl_EvalObjv", "ipipi"
> 
> func2 returns int, takes some pointer (that is okay), takes integer
> (this is a number of TclObj*), the TclObj** itself, and integer, which
> could be 0
> 
> I tried to create following "structure":
>     # TclObj**, which is array of TclObj*
>     .local pmc tcl_obj_decl, tcl_obj_struct
>     tcl_obj_decl = new 'FixedPMCArray'
>     tcl_obj_decl = 3
>     tcl_obj_decl[0]  = .DATATYPE_PTR
>     tcl_obj_decl[1]  = objc
>     tcl_obj_decl[2]  = 0
>     tcl_obj_struct = new 'ManagedStruct', tcl_obj_decl
> 
> . and then fill it in a loop with values.
> 
> But when I, essentially, do
> 
>   .local pmc obj
>    obj = func1("string",0)
> 
>    tcl_obj_struct[0;i] = obj
> 
> I get an error
> set_pmc_keyed() not implemented in class 'ManagedStruct'
> 
> I think that when parrot assigns to a field structure, it attempts to
> do a conversion, which is not defined for abstract PMC, thus the
> error. But I do not know what the way out of situation.
> 
> I tried to replace .DATATYPE_PTR, with .DATATYPE_PMC with similar results.
> 
> Actaully, my task is not "twisted" - essentially it is just passing an
> array of some pointers. But how to do this?

There are several ways to do it, so it partly depends on how you plan to 
use the array. If you want to be able to use it as an array in PIR, and 
do things like insert (or delete) elements like:

    tcl_obj_array[0;i] = obj

Then, your array needs to be a PMC array type, like FixedPMCArray (if 
you know how many elements you'll have) or ResizablePMCArray (if you 
don't know how many elements you'll have). A ManagedStruct can't act as 
a generic array of PMCs, which is why you're getting the error about 
"set_pmc_keyed() not implemented".


Could we get a little more detail on the Tcl side of the code? It looks 
like you're embedding a Tcl interpreter inside Parrot? In which case, 
the key thing is building a variable that the 'Tcl_EvalObjv' function 
can understand.

Tcl_Obj is a core Tcl type, so has to be created using Tcl's constructor 
functions. Looks like you're using 'Tcl_NewStringObj' for that. But the 
Tcl_Obj** you need to pass to 'Tcl_EvalObjv' also has to be created by 
Tcl. (Parrot can pass around a pointer to the chunk of memory that holds 
the Tcl_Obj**, but it can't know how to structure it internally so Tcl 
can read it.)

It looks like you can do this by calling the functions 'Tcl_NewListObj' 
to create a new Tcl list of Tcl_Obj's, then call 
'Tcl_ListObjAppendElement' to add each Tcl_Obj* to the list, and then 
call 'Tcl_ListObjGetElements' to get back a Tcl_Obj** array of the 
elements of the list. That Tcl_Obj** array should be able to be passed 
directly to 'Tcl_EvalObjv'.

(BTW, from the documentation on Tcl_EvalObjv, it looks like you may also 
need to import the Tcl functions for manual reference counting 
('Tcl_IncrRefCount' and 'Tcl_DecrRefCount'), since Tcl_EvalObjv expects 
the caller to handle incrementing and decrementing the refcounts on the 
objects passed in.)

Allison


More information about the Parrot-users mailing list