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