So, if I understand correctly we could use the introspective power of
picolisp and write a {meta?}program to produce the "library" for Pil, and
then use this to call R from picolisp?

--
Cesar Rabak

On Thu, Apr 8, 2021 at 4:14 PM Thorsten Jolitz <tjol...@gmail.com> wrote:

> Hi Alex,
> after digging deeper in R Internals I found out that there are actually C
> access functions for the various subtypes of SEXP that can be wrapped with
> native too:
>
> rinc: (setupRinC)
> -> NIL
> rinc: (evalQuietlyInR "V <- c(1.5, 3.4, 4.2)")
> -> NIL
> rinc: (evalInR "V")
> -> 65007640
> rinc: (REAL (evalInR "V"))
> -> (2 3 4)
> rinc: (teardownRinC)
> -> NIL
>
> I think this is already quite nice.
> Setup an R session, do quiet evaluations in R, do evaluations with return
> value, convert that return value (SEXP subtype) to its appropriate Pil data
> type, tear down R session.
>
> So there are only a few challenges left:
> 1. write wrappers for all type conversion functions (for all SEXP subtypes)
> 2. figure out the SEXP subtype from the pointer returned
> 3. dynamically get the length for all SEXP subtypes with a length, to be
> able to dynamically define return types like '(1.0 . 3) in native or struct
> (I think there are C functions for this in R internals too)
>
> Question on topic 2:
> given the C data type described below for an R "node", would it be somehow
> possible to extract just the SEXPTYPE from a SEXP return value, i.e.
> the first field of the sexpinfo_struct, that is the first struct in the
> SEXPREC_HEADER, that is the first field in the SEXPREC struct to which the
> SEXP return value points?
> Without specifying that complicated C structure in native or struct,
> because we have the C access functions for that. Ignoring all the rest of
> the pointer content, just extract that one field SEXPTYPE?
>
> Knowing which SEXPTYPE the return value represents, one could then read
> the returned pointer with the appropriate data type into Pil (like REAL in
> the example above).
> if the return value is atomic, one is done. If its a vector, list, or so
> one would need the length of it too, not only the type (or is it a valid
> strategy to just use some very big value for the specification like '(1.0 .
> 9999999999999999) or so)?
>
> Cheers
> Thorsten
>
>
> *Composition of an R node: *
> the SEXP subtypes are defined like this:
> typedef unsigned int SEXPTYPE;
>   52   #define NILSXP›        0›   /* nil = NULL */
>   53   #define SYMSXP›        1›   /* symbols */
>   54   #define LISTSXP›       2›   /* lists of dotted pairs */
>   55   #define CLOSXP›        3›   /* closures */
>   56   #define ENVSXP›        4›   /* environments */
>   57   #define PROMSXP›       5›   /* promises: [un]evaluated closure
> arguments */
>   58   #define LANGSXP›       6›   /* language constructs (special lists)
> */
>   59   #define SPECIALSXP   7›     /* special forms */
>   60   #define BUILTINSXP   8›     /* builtin non-special forms */
>   61   #define CHARSXP›       9›   /* "scalar" string type (internal
> only)*/
>   64  #define INTSXP›       13›   /* integer vectors */
>   65   #define REALSXP›      14›   /* real variables */
>   66   #define CPLXSXP›      15›   /* complex variables */
>   67   #define STRSXP›       16›   /* string vectors */
>   68   #define DOTSXP›       17›   /* dot-dot-dot object */
>   69   #define ANYSXP›       18›   /* make "any" args work.
>   72   #define VECSXP›       19›   /* generic vectors */
>   73   #define EXPRSXP›      20›   /* expressions vectors */
>   74   #define BCODESXP    21    /* byte code */
>   62   etc
>
> this type is part of the sxpinfo structure:
> struct sxpinfo_struct {
>  142       SEXPTYPE type      :  TYPE_BITS;
>  143                               /* ==> (FUNSXP == 99) %% 2^5 == 3 ==
> CLOSXP
>  144   › ›   ›        ,* -> warning: `type' is narrower than values
>  145   › ›   ›        ,*              of its type
>  146   › ›   ›        ,* when SEXPTYPE was an enum */
>  147       unsigned int scalar:  1;
>  148       unsigned int obj   :  1;
>  149    etc
>
> which then becomes part of an header:
> #define SEXPREC_HEADER \
>  209       struct sxpinfo_struct sxpinfo; \
>  210       struct SEXPREC *attrib; \
>  211       struct SEXPREC *gengc_next_node, *gengc_prev_node
>  212
>
> which finally becomes part of the SEXPREC structure. A SEXP is a pointer
> to a SEXPREC structure.
>  213   /* The standard node structure consists of a header followed by the
>  214      node data. */
>  215   typedef struct SEXPREC {
>  216       SEXPREC_HEADER;
>  217       union {
>  218   › struct primsxp_struct primsxp;
>  219   › struct symsxp_struct symsxp;
>  220   › etc
>
>
>
>
> Am Mi., 7. Apr. 2021 um 15:55 Uhr schrieb Alexander Burger <
> a...@software-lab.de>:
>
>> On Wed, Apr 07, 2021 at 07:46:20AM +0200, Alexander Burger wrote:
>> > OK, so now we have a pointer to a structure filled by evalInR().
>> > ...
>> >    (struct (evalInR "6*4") ...)
>>
>> In fact this depends on what exactly evalInR() returns.
>>
>> If it returns a pointer to a dynamically allocated structure, and the
>> caller is
>> responsible to de-allocate it, you would do
>>
>>    (let P (evalInR "6*4")
>>       (prog1
>>          (struct P ...)
>>          (free P) ) )
>>
>> If, however, the structure is statically allocated, you can also give the
>> structure's structure directly as the return value specification:
>>
>>    (native `*RinC "evalInR" '(...) "Cmd")
>>
>> For example, as a (somewhat conceived) test case
>>
>>    static struct {
>>       char *s;
>>       int i[4];
>>       double d;
>>       char nm[8];
>>    } Data;
>>
>>    void *foo(void) {
>>       Data.s = "Hello";
>>       Data.i[0] = 1;
>>       Data.i[1] = 2;
>>       Data.i[2] = -3;
>>       Data.i[3] = 4;
>>       Data.d = 0.99;
>>       strcpy(Data.nm, "world");
>>       return &Data;
>>    }
>>
>> Then in the REPL
>>
>>    : (native "./test.so" "foo" '(S I (I . 2) (B . 4) 100 (C . 8)))
>>    -> ("Hello" 1 (2 -3) (4 0 0 0) 99 ("w" "o" "r" "l" "d"))
>>
>> ☺/ A!ex
>>
>> --
>> UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
>>
>>

Reply via email to