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