func Eval(expression string) (*Result, error) { var status C.ParseStatus cmd := C.CString(expression) defer C.free(unsafe.Pointer(cmd)) cmdRChar := C.mkChar(cmd) protector := Protect(cmdRChar) defer protector.Unprotect() cmdSexp := C.allocVector(C.STRSXP, 1) protector.Protect(cmdSexp) C.SET_STRING_ELT(cmdSexp, 0, cmdRChar) parsedCmd := C.R_ParseVector(cmdSexp, -1, (*C.ParseStatus)(unsafe.Pointer(&status)), C.R_NilValue) if status != C.PARSE_OK { return nil, fmt.Errorf("Invalid command: %s", C.GoString(cmd)) } protector.Protect(parsedCmd) var result C.SEXP errorOccured := 0 /* Loop is needed here as EXPSEXP will be of length > 1 */ for i := 0; i < int(C.Rf_length(parsedCmd)); i++ { result = C.R_tryEval(C.VECTOR_ELT(parsedCmd, C.R_xlen_t(i)), C.R_GlobalEnv, (*C.int)(unsafe.Pointer(&errorOccured))) //R 3.0 if errorOccured != 0 { return nil, fmt.Errorf("R error occured executing: %s", C.GoString(cmd)) } } return NewResult(result), nil }
func toIface(s C.SEXP) interface{} { // generate a go map or slice or scalar value, then encode it n := int(C.Rf_xlength(s)) if n == 0 { return nil // drops type info. Meh. } switch C.TYPEOF(s) { case C.VECSXP: // an R generic vector; e.g list() VPrintf("encodeRIntoMsgpack sees VECSXP\n") // could be a map or a slice. Check out the names. rnames := C.Rf_getAttrib(s, C.R_NamesSymbol) rnamesLen := int(C.Rf_xlength(rnames)) VPrintf("namesLen = %d\n", rnamesLen) if rnamesLen > 0 { myMap := map[string]interface{}{} for i := 0; i < rnamesLen; i++ { myMap[C.GoString(C.get_string_elt(rnames, C.int(i)))] = toIface(C.VECTOR_ELT(s, C.R_xlen_t(i))) } VPrintf("VECSXP myMap = '%#v'\n", myMap) return myMap } else { // else: no names, so we treat it as an array instead of as a map mySlice := make([]interface{}, n) for i := 0; i < n; i++ { mySlice[i] = toIface(C.VECTOR_ELT(s, C.R_xlen_t(i))) } VPrintf("VECSXP mySlice = '%#v'\n", mySlice) return mySlice } case C.REALSXP: // a vector of float64 (numeric) VPrintf("encodeRIntoMsgpack sees REALSXP\n") mySlice := make([]float64, n) for i := 0; i < n; i++ { mySlice[i] = float64(C.get_real_elt(s, C.int(i))) } VPrintf("VECSXP mySlice = '%#v'\n", mySlice) return mySlice case C.INTSXP: // a vector of int32 VPrintf("encodeRIntoMsgpack sees INTSXP\n") mySlice := make([]int, n) for i := 0; i < n; i++ { mySlice[i] = int(C.get_int_elt(s, C.int(i))) } VPrintf("INTSXP mySlice = '%#v'\n", mySlice) return mySlice case C.RAWSXP: VPrintf("encodeRIntoMsgpack sees RAWSXP\n") mySlice := make([]byte, n) C.memcpy(unsafe.Pointer(&mySlice[0]), unsafe.Pointer(C.RAW(s)), C.size_t(n)) VPrintf("RAWSXP mySlice = '%#v'\n", mySlice) return mySlice case C.STRSXP: // a vector of string (pointers to charsxp that are interned) VPrintf("encodeRIntoMsgpack sees STRSXP\n") mySlice := make([]string, n) for i := 0; i < n; i++ { mySlice[i] = C.GoString(C.get_string_elt(s, C.int(i))) } VPrintf("STRSXP mySlice = '%#v'\n", mySlice) return mySlice case C.NILSXP: // c(); an empty vector VPrintf("encodeRIntoMsgpack sees NILSXP\n") return nil case C.CHARSXP: // a single string, interned in a global pool for reuse by STRSXP. VPrintf("encodeRIntoMsgpack sees CHARSXP\n") case C.SYMSXP: VPrintf("encodeRIntoMsgpack sees SYMSXP\n") case C.LISTSXP: VPrintf("encodeRIntoMsgpack sees LISTSXP\n") case C.CLOSXP: VPrintf("encodeRIntoMsgpack sees CLOSXP\n") case C.ENVSXP: VPrintf("encodeRIntoMsgpack sees ENVSXP\n") case C.PROMSXP: VPrintf("encodeRIntoMsgpack sees PROMSXP\n") case C.LANGSXP: VPrintf("encodeRIntoMsgpack sees LANGSXP\n") case C.SPECIALSXP: VPrintf("encodeRIntoMsgpack sees SPECIALSXP\n") case C.BUILTINSXP: VPrintf("encodeRIntoMsgpack sees BUILTINSXP\n") case C.LGLSXP: VPrintf("encodeRIntoMsgpack sees LGLSXP\n") case C.CPLXSXP: VPrintf("encodeRIntoMsgpack sees CPLXSXP\n") case C.DOTSXP: VPrintf("encodeRIntoMsgpack sees DOTSXP\n") case C.ANYSXP: VPrintf("encodeRIntoMsgpack sees ANYSXP\n") case C.EXPRSXP: VPrintf("encodeRIntoMsgpack sees EXPRSXP\n") case C.BCODESXP: VPrintf("encodeRIntoMsgpack sees BCODESXP\n") case C.EXTPTRSXP: VPrintf("encodeRIntoMsgpack sees EXTPTRSXP\n") case C.WEAKREFSXP: VPrintf("encodeRIntoMsgpack sees WEAKREFSXP\n") case C.S4SXP: VPrintf("encodeRIntoMsgpack sees S4SXP\n") default: VPrintf("encodeRIntoMsgpack sees <unknown>\n") } VPrintf("... warning: encodeRIntoMsgpack() ignoring this input.\n") return nil }