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 > >