Picolisp has "native" calls as an FFI to call C shared libraries from
Picolisp, and build Picolisp wrapper functions on top of C functions
defined in header files.

A lot of programming languages allow that, there are e.g. many Python
wrappers for all kinds of data science libraries. But with Picolisp you
need only very little code to do it. It's still not easy when the C
functions are non-trivial (and you have only limited C knowledge).

There are quite a few Picolisp wrapper libs from AW on GitHub with good
explanations....

Cesar Rabak <cesar.ra...@gmail.com> schrieb am Do., 8. Apr. 2021, 21:54:

> 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