diff options
author | robot-piglet <[email protected]> | 2025-08-28 14:27:58 +0300 |
---|---|---|
committer | robot-piglet <[email protected]> | 2025-08-28 14:57:06 +0300 |
commit | 81d828c32c8d5477cb2f0ce5da06a1a8d9392ca3 (patch) | |
tree | 3081d566f0d5158d76e9093261344f6406fd09f7 /contrib/tools/swig/Source/Modules/r.cxx | |
parent | 77ea11423f959e51795cc3ef36a48d808b4ffb98 (diff) |
Intermediate changes
commit_hash:d5b1af16dbe9030537a04c27eb410c88c2f496cd
Diffstat (limited to 'contrib/tools/swig/Source/Modules/r.cxx')
-rw-r--r-- | contrib/tools/swig/Source/Modules/r.cxx | 2850 |
1 files changed, 2850 insertions, 0 deletions
diff --git a/contrib/tools/swig/Source/Modules/r.cxx b/contrib/tools/swig/Source/Modules/r.cxx new file mode 100644 index 00000000000..1f9da693028 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/r.cxx @@ -0,0 +1,2850 @@ + +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * r.cxx + * + * R language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static String* replaceInitialDash(const String *name) +{ + String *retval; + if (!Strncmp(name, "_", 1)) { + retval = Copy(name); + Insert(retval, 0, "s"); + } else { + retval = Copy(name); + } + return retval; +} + +static String * getRTypeName(SwigType *t, int *outCount = NULL) { + String *b = SwigType_base(t); + List *els = SwigType_split(t); + int count = 0; + int i; + + if(Strncmp(b, "struct ", 7) == 0) + Replace(b, "struct ", "", DOH_REPLACE_FIRST); + + for(i = 0; i < Len(els); i++) { + String *el = Getitem(els, i); + if(Strcmp(el, "p.") == 0 || Strncmp(el, "a(", 2) == 0) { + count++; + Append(b, "Ref"); + } + } + if(outCount) + *outCount = count; + + String *tmp = NewString(""); + char *retName = Char(SwigType_manglestr(t)); + Insert(tmp, 0, retName); + return tmp; + +} + +/* -------------------------------------------------------------- + * Tries to get the resolved name, with options of adding + * or removing a layer of references. Take care not + * to request both + * --------------------------------------------------------------*/ + +static String *getRClassName(String *retType, int deRef=0, int upRef=0) { + SwigType *resolved = SwigType_typedef_resolve_all(retType); + int ispointer = SwigType_ispointer(resolved); + int isreference = SwigType_isreference(resolved); + if (upRef) { + SwigType_add_pointer(resolved); + } + if (deRef) { + if (ispointer) { + SwigType_del_pointer(resolved); + } + if (isreference) { + SwigType_del_reference(resolved); + } + } + String *tmp = NewString(""); + Insert(tmp, 0, Char(SwigType_manglestr(resolved))); + return(tmp); +} + +/* -------------------------------------------------------------- + * Tries to get the name of the R class corresponding to the given type + * e.g. struct A * is ARef, struct A** is ARefRef. + * Now handles arrays, i.e. struct A[2] + * --------------------------------------------------------------*/ + + +static String * getRClassNameCopyStruct(String *retType, int addRef) { + String *tmp = NewString(""); + + List *l = SwigType_split(retType); + int n = Len(l); + if(!l || n == 0) { +#ifdef R_SWIG_VERBOSE + Printf(stdout, "SwigType_split return an empty list for %s\n", retType); +#endif + return(tmp); + } + + + String *el = Getitem(l, n-1); + char *ptr = Char(el); + if(strncmp(ptr, "struct ", 7) == 0) + ptr += 7; + + Printf(tmp, "%s", ptr); + + if(addRef) { + for(int i = 0; i < n; i++) { + if(Strcmp(Getitem(l, i), "p.") == 0 || + Strncmp(Getitem(l, i), "a(", 2) == 0) + Printf(tmp, "Ref"); + } + } + + return tmp; +} + + +/* ------------------------------------------------------------- + * Write the elements of a list to the File*, one element per line. + * If quote is true, surround the element with "element". + * This takes care of inserting a tab in front of each line and also + * a comma after each element, except the last one. + * --------------------------------------------------------------*/ + + +static void writeListByLine(List *l, File *out, bool quote = 0) { + int i, n = Len(l); + for(i = 0; i < n; i++) + Printf(out, "%s%s%s%s%s\n", tab8, + quote ? "\"" :"", + Getitem(l, i), + quote ? "\"" :"", i < n-1 ? "," : ""); +} + + +static const char *usage = "\ +R Options (available with -r)\n\ + -copystruct - Emit R code to copy C structs (on by default)\n\ + -debug - Output debug\n\ + -dll <name> - Name of the DLL (without the .dll or .so suffix).\n\ + Default is the module name.\n\ + -gc - Aggressive garbage collection\n\ + -memoryprof - Add memory profile\n\ + -namespace - Output NAMESPACE file\n\ + -no-init-code - Turn off the generation of the R_init_<pkgname> code\n\ + (registration information still generated)\n\ + -package <name> - Package name for the PACKAGE argument of the R .Call()\n\ + invocations. Default is the module name.\n\ +"; + + + +/* ------------------------------------------------------------- + * Display the help for this module on the screen/console. + * --------------------------------------------------------------*/ + +static void showUsage() { + fputs(usage, stdout); +} + +static bool expandTypedef(SwigType *t) { + if (SwigType_isenum(t)) return false; + String *prefix = SwigType_prefix(t); + if (Strncmp(prefix, "f", 1)) return false; + if (Strncmp(prefix, "p.f", 3)) return false; + return true; +} + + +/* ------------------------------------------------------------- + * Determine whether we should add a .copy argument to the S function + * that wraps/interfaces to the routine that returns the given type. + * --------------------------------------------------------------*/ + +static int addCopyParameter(SwigType *type) { + int ok = 0; + ok = Strncmp(type, "struct ", 7) == 0 || Strncmp(type, "p.struct ", 9) == 0; + if(!ok) { + ok = Strncmp(type, "p.", 2); + } + + return(ok); +} + +static void replaceRClass(String *tm, SwigType *type) { + String *tmp = getRClassName(type, 0, 0); + String *tmp_base = getRClassName(type, 1, 0); + String *tmp_ref = getRClassName(type, 0, 1); + Replaceall(tm, "$R_class", tmp); + Replaceall(tm, "$*R_class", tmp_base); + Replaceall(tm, "$&R_class", tmp_ref); + Delete(tmp); Delete(tmp_base); Delete(tmp_ref); +} + +class R : public Language { +public: + R(); + void registerClass(Node *n); + void main(int argc, char *argv[]); + int top(Node *n); + + void dispatchFunction(Node *n); + int functionWrapper(Node *n); + int constantWrapper(Node *n); + int variableWrapper(Node *n); + + int classDeclaration(Node *n); + int enumDeclaration(Node *n); + String *enumValue(Node *n); + virtual int enumvalueDeclaration(Node *n); + int membervariableHandler(Node *n); + + int typedefHandler(Node *n); + + static List *Swig_overload_rank(Node *n, bool script_lang_wrapping); + + int memberfunctionHandler(Node *n) { + if (debugMode) + Printf(stdout, "<memberfunctionHandler> %s %s\n", + Getattr(n, "name"), + Getattr(n, "type")); + member_name = Getattr(n, "sym:name"); + processing_class_member_function = 1; + int status = Language::memberfunctionHandler(n); + processing_class_member_function = 0; + return status; + } + + /* Grab the name of the current class being processed so that we can + deal with members of that class. */ + int classHandler(Node *n){ + if(!ClassMemberTable) + ClassMemberTable = NewHash(); + + class_name = Getattr(n, "name"); + int status = Language::classHandler(n); + + class_name = NULL; + return status; + } + + String *runtimeCode(); + void replaceSpecialVariables(String *method, String *tm, Parm *parm); + +protected: + int addRegistrationRoutine(String *rname, int nargs); + int outputRegistrationRoutines(File *out); + + int outputCommandLineArguments(File *out); + int generateCopyRoutines(Node *n); + int DumpCode(Node *n); + + int OutputMemberReferenceMethod(String *className, int isSet, List *memberList, List *nameList, List *typeList, File *out); + int defineArrayAccessors(SwigType *type); + + void addNamespaceFunction(String *name) { + if(!namespaceFunctions) + namespaceFunctions = NewList(); + Append(namespaceFunctions, name); + } + + void addNamespaceMethod(String *name) { + if(!namespaceMethods) + namespaceMethods = NewList(); + Append(namespaceMethods, name); + } + + String* processType(SwigType *t, Node *n, int *nargs = NULL); + String *createFunctionPointerHandler(SwigType *t, Node *n, int *nargs); + int addFunctionPointerProxy(String *name, Node *n, SwigType *t, String *s_paramTypes) { + /*XXX Do we need to put the t in there to get the return type later. */ + if(!functionPointerProxyTable) + functionPointerProxyTable = NewHash(); + + Setattr(functionPointerProxyTable, name, n); + + Setattr(SClassDefs, name, name); + Printv(s_classes, "setClass('", + name, + "',\n", tab8, + "prototype = list(parameterTypes = c(", s_paramTypes, "),\n", + tab8, tab8, tab8, + "returnType = '", SwigType_manglestr(t), "'),\n", tab8, + "contains = 'CRoutinePointer')\n\n##\n", NIL); + + return SWIG_OK; + } + + + void addSMethodInfo(String *name, + String *argType, int nargs); + // Simple initialization such as constant strings that can be reused. + void init(); + + + void addAccessor(String *memberName, Wrapper *f, + String *name, String *methodSetGet); + + static int getFunctionPointerNumArgs(Node *n, SwigType *tt); + + // filtering of class member lists by function type. Used in constructing accessors + // are we allowed to use stl style functors to customise this? + List* filterMemberList(List *class_member_function_types, List *class_member_other, String *R_MEMBER, bool equal); + +protected: + bool copyStruct; + bool memoryProfile; + bool aggressiveGc; + + // Strings into which we cumulate the generated code that is to be written + //vto the files. + String *enum_values; + String *enum_def_calls; + String *sfile; + String *f_init; + String *s_classes; + String *f_begin; + String *f_runtime; + String *f_wrapper; + String *s_header; + String *f_wrappers; + String *s_init; + String *s_init_routine; + String *s_namespace; + + // State variables that carry information across calls to functionWrapper() + // from member accessors and class declarations. + String *opaqueClassDeclaration; + int processing_variable; + int processing_member_access_function; + String *member_name; + String *class_name; + + String *R_MEMBER_NORMAL; + String *R_MEMBER_SET; + String *R_MEMBER_GET; + + int processing_class_member_function; + // Spread out the lists so that they are simpler to process + // by storing the type of the method (i.e. set, get or nothing) + // and having separate lists for name, membername and wrapper + List *class_member_function_types; + List *class_member_function_names; + List *class_member_function_membernames; + List *class_member_function_wrappernames; + /* */ + Hash *ClassMemberTable; + Hash *ClassMethodsTable; + Hash *SClassDefs; + Hash *SMethodInfo; + + // Information about routines that are generated and to be registered with + // R for dynamic lookup. + Hash *registrationTable; + Hash *functionPointerProxyTable; + + List *namespaceFunctions; + List *namespaceMethods; + List *namespaceClasses; // Probably can do this from ClassMemberTable. + + + // Store a copy of the command line. + // Need only keep a string that has it formatted. + char **Argv; + int Argc; + bool inCPlusMode; + + // State variables that we remember from the command line settings + // potentially that govern the code we generate. + String *DllName; + String *Rpackage; + bool noInitializationCode; + bool outputNamespaceInfo; + + String *UnProtectWrapupCode; + + // Static members + static bool debugMode; +}; + +R::R() : + copyStruct(false), + memoryProfile(false), + aggressiveGc(false), + enum_values(0), + enum_def_calls(0), + sfile(0), + f_init(0), + s_classes(0), + f_begin(0), + f_runtime(0), + f_wrapper(0), + s_header(0), + f_wrappers(0), + s_init(0), + s_init_routine(0), + s_namespace(0), + opaqueClassDeclaration(0), + processing_variable(0), + processing_member_access_function(0), + member_name(0), + class_name(0), + R_MEMBER_NORMAL(NewString("normal")), + R_MEMBER_SET(NewString("set")), + R_MEMBER_GET(NewString("get")), + processing_class_member_function(0), + class_member_function_types(0), + class_member_function_names(0), + class_member_function_membernames(0), + class_member_function_wrappernames(0), + ClassMemberTable(0), + ClassMethodsTable(0), + SClassDefs(0), + SMethodInfo(0), + registrationTable(0), + functionPointerProxyTable(0), + namespaceFunctions(0), + namespaceMethods(0), + namespaceClasses(0), + Argv(0), + Argc(0), + inCPlusMode(false), + DllName(0), + Rpackage(0), + noInitializationCode(false), + outputNamespaceInfo(false), + UnProtectWrapupCode(0) { +} + +bool R::debugMode = false; + +int R::getFunctionPointerNumArgs(Node *n, SwigType *tt) { + (void) tt; + n = Getattr(n, "type"); + if (debugMode) + Printf(stdout, "type: %s\n", n); + + ParmList *parms = Getattr(n, "parms"); + if (debugMode) + Printf(stdout, "parms = %p\n", parms); + return ParmList_len(parms); +} + + +void R::addSMethodInfo(String *name, String *argType, int nargs) { + (void) argType; + + if(!SMethodInfo) + SMethodInfo = NewHash(); + if (debugMode) + Printf(stdout, "[addMethodInfo] %s\n", name); + + Hash *tb = Getattr(SMethodInfo, name); + + if(!tb) { + tb = NewHash(); + Setattr(SMethodInfo, name, tb); + } + + String *str = Getattr(tb, "max"); + int max = -1; + if(str) + max = atoi(Char(str)); + if(max < nargs) { + if(str) Delete(str); + str = NewStringf("%d", max); + Setattr(tb, "max", str); + } +} + +/* ---------------------------------------- + * Returns the name of the new routine. + * ------------------------------------------ */ + +String * R::createFunctionPointerHandler(SwigType *t, Node *n, int *numArgs) { + String *funName = SwigType_manglestr(t); + + /* See if we have already processed this one. */ + if(functionPointerProxyTable && Getattr(functionPointerProxyTable, funName)) + return funName; + + if (debugMode) + Printf(stdout, "<createFunctionPointerHandler> Defining %s\n", t); + + SwigType *rettype = Copy(Getattr(n, "type")); + SwigType *funcparams = SwigType_functionpointer_decompose(rettype); + String *rtype = SwigType_str(rettype, 0); + + // ParmList *parms = Getattr(n, "parms"); + // memory leak + ParmList *parms = SwigType_function_parms(SwigType_del_pointer(Copy(t)), n); + + + if (debugMode) { + Printf(stdout, "Type: %s\n", t); + Printf(stdout, "Return type: %s\n", SwigType_base(t)); + } + + bool isVoidType = Strcmp(rettype, "void") == 0; + if (debugMode) + Printf(stdout, "%s is void ? %s (%s)\n", funName, isVoidType ? "yes" : "no", rettype); + + Wrapper *f = NewWrapper(); + + /* Go through argument list, attach lnames for arguments */ + int i = 0; + Parm *p = parms; + for (i = 0; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname; + if (!arg && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("arg%d", i+1); + Setattr(p, "name", lname); + } else + lname = arg; + + Setattr(p, "lname", lname); + } + + Swig_typemap_attach_parms("out", parms, f); + Swig_typemap_attach_parms("scoerceout", parms, f); + Swig_typemap_attach_parms("scheck", parms, f); + + Printf(f->def, "%s %s(", rtype, funName); + + emit_parameter_variables(parms, f); + emit_return_variable(n, rettype, f); + // emit_attach_parmmaps(parms,f); + + /* Using weird name and struct to avoid potential conflicts. */ + Wrapper_add_local(f, "r_swig_cb_data", "RCallbackFunctionData *r_swig_cb_data = R_SWIG_getCallbackFunctionData()"); + String *lvar = NewString("r_swig_cb_data"); + + Wrapper_add_local(f, "r_tmp", "SEXP r_tmp"); // for use in converting arguments to R objects for call. + Wrapper_add_local(f, "r_nprotect", "int r_nprotect = 0"); // for use in converting arguments to R objects for call. + Wrapper_add_local(f, "r_vmax", "char * r_vmax= 0"); // for use in converting arguments to R objects for call. + + // Add local for error code in return value. This is not in emit_return_variable because that assumes an out typemap + // whereas the type makes are reverse + Wrapper_add_local(f, "ecode", "int ecode = 0"); + + p = parms; + int nargs = ParmList_len(parms); + if(numArgs) { + *numArgs = nargs; + if (debugMode) + Printf(stdout, "Setting number of parameters to %d\n", *numArgs); + } + String *setExprElements = NewString(""); + + String *s_paramTypes = NewString(""); + for(i = 0; p; i++) { + SwigType *tt = Getattr(p, "type"); + SwigType *name = Getattr(p, "name"); + SwigType *swig_parm_name = NewStringf("swigarg_%s", name); + String *tm = Getattr(p, "tmap:out"); + bool isVoidParm = Strcmp(tt, "void") == 0; + if (isVoidParm) + Printf(f->def, "%s", SwigType_str(tt, 0)); + else + Printf(f->def, "%s %s", SwigType_str(tt, 0), swig_parm_name); + if (tm) { + String *lstr = SwigType_lstr(tt, 0); + if (SwigType_isreference(tt) || SwigType_isrvalue_reference(tt)) { + Printf(f->code, "%s = (%s) &%s;\n", Getattr(p, "lname"), lstr, swig_parm_name); + } else if (!isVoidParm) { + Printf(f->code, "%s = (%s) %s;\n", Getattr(p, "lname"), lstr, swig_parm_name); + } + Replaceall(tm, "$1", name); + Replaceall(tm, "$result", "r_tmp"); + if (debugMode) { + Printf(stdout, "Calling Replace A: %s\n", Getattr(p,"type")); + } + replaceRClass(tm, Getattr(p,"type")); + Replaceall(tm,"$owner", "0"); + Delete(lstr); + } + + Printf(setExprElements, "%s\n", tm); + Printf(setExprElements, "SETCAR(r_swig_cb_data->el, %s);\n", "r_tmp"); + Printf(setExprElements, "r_swig_cb_data->el = CDR(r_swig_cb_data->el);\n\n"); + + Printf(s_paramTypes, "'%s'", SwigType_manglestr(tt)); + + + p = nextSibling(p); + if(p) { + Printf(f->def, ", "); + Printf(s_paramTypes, ", "); + } + } + + Printf(f->def, ") {\n"); + + Printf(f->code, "Rf_protect(%s->expr = Rf_allocVector(LANGSXP, %d));\n", lvar, nargs + 1); + Printf(f->code, "r_nprotect++;\n"); + Printf(f->code, "r_swig_cb_data->el = r_swig_cb_data->expr;\n\n"); + + Printf(f->code, "SETCAR(r_swig_cb_data->el, r_swig_cb_data->fun);\n"); + Printf(f->code, "r_swig_cb_data->el = CDR(r_swig_cb_data->el);\n\n"); + + Printf(f->code, "%s\n\n", setExprElements); + + Printv(f->code, "r_swig_cb_data->retValue = R_tryEval(", + "r_swig_cb_data->expr,", + " R_GlobalEnv,", + " &r_swig_cb_data->errorOccurred", + ");\n", + NIL); + + Printv(f->code, "\n", + "if(r_swig_cb_data->errorOccurred) {\n", + "R_SWIG_popCallbackFunctionData(1);\n", + "Rf_error(\"error in calling R function as a function pointer (", + funName, + ")\");\n", + "}\n", + NIL); + + + + if(!isVoidType) { + /* Need to deal with the return type of the function pointer, not the function pointer itself. + So build a new node that has the relevant pieces. + XXX Have to be a little more clever so that we can deal with struct A * - the * is getting lost. + Is this still true? If so, will a SwigType_push() solve things? + */ + Parm *bbase = NewParmNode(rettype, n); + String *returnTM = Swig_typemap_lookup("in", bbase, Swig_cresult_name(), f); + if(returnTM) { + String *tm = returnTM; + Replaceall(tm,"$input", "r_swig_cb_data->retValue"); + replaceRClass(tm, rettype); + Replaceall(tm,"$owner", "0"); + Replaceall(tm,"$disown","0"); + Printf(f->code, "%s\n", tm); + } + Delete(bbase); + } + + Printv(f->code, "R_SWIG_popCallbackFunctionData(1);\n", NIL); + Printv(f->code, "\n", UnProtectWrapupCode, NIL); + + if (SwigType_isreference(rettype)) { + Printv(f->code, "return *", Swig_cresult_name(), ";\n", NIL); + } else if (SwigType_isrvalue_reference(rettype)) { + Printv(f->code, "return std::move(*", Swig_cresult_name(), ");\n", NIL); + } else if (!isVoidType) { + Printv(f->code, "return ", Swig_cresult_name(), ";\n", NIL); + } + + Printv(f->code, "\n}\n", NIL); + Replaceall(f->code, "SWIG_exception_fail", "SWIG_exception_noreturn"); + + /* To coerce correctly in S, we really want to have an extra/intermediate + function that handles the scoerceout. + We need to check if any of the argument types have an entry in + that map. If none do, the ignore and call the function straight. + Otherwise, generate a marshalling function. + Need to be able to find it in S. Or use an entirely generic one + that evaluates the expressions. + Handle errors in the evaluation of the function by restoring + the stack, if there is one in use for this function (i.e. no + userData). + */ + + Wrapper_print(f, f_wrapper); + + addFunctionPointerProxy(funName, n, t, s_paramTypes); + Delete(s_paramTypes); + Delete(rtype); + Delete(rettype); + Delete(funcparams); + DelWrapper(f); + + return funName; +} + +void R::init() { + UnProtectWrapupCode = + NewStringf("%s", "vmaxset(r_vmax);\nif(r_nprotect) Rf_unprotect(r_nprotect);\n\n"); + + SClassDefs = NewHash(); + + sfile = NewString(""); + f_init = NewString(""); + s_header = NewString(""); + f_begin = NewString(""); + f_runtime = NewString(""); + f_wrapper = NewString(""); + s_classes = NewString(""); + s_init = NewString(""); + s_init_routine = NewString(""); + enum_def_calls = NewString(""); +} + + +/* ------------------------------------------------------------- + * Method from Language that is called to start the entire + * processing off, i.e. the generation of the code. + * It is called after the input has been read and parsed. + * Here we open the output streams and generate the code. + * ------------------------------------------------------------- */ +int R::top(Node *n) { + String *module = Getattr(n, "name"); + + if (debugMode) { + Printf(stdout, "<Top> %s\n", module); + } + + if(!Rpackage) + Rpackage = Copy(module); + if(!DllName) + DllName = Copy(module); + + if(outputNamespaceInfo) { + s_namespace = NewString(""); + Swig_register_filebyname("snamespace", s_namespace); + Printf(s_namespace, "useDynLib(%s)\n", DllName); + } + // Register the naming functions + Swig_name_register("wrapper", "R_swig_%f"); + + /* Associate the different streams with names so that they can be used in %insert directives by the + typemap code. */ + Swig_register_filebyname("sinit", s_init); + Swig_register_filebyname("sinitroutine", s_init_routine); + + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("header", s_header); + Swig_register_filebyname("wrapper", f_wrapper); + Swig_register_filebyname("s", sfile); + Swig_register_filebyname("sclasses", s_classes); + + Swig_banner(f_begin); + + Swig_obligatory_macros(f_runtime, "R"); + + Swig_banner_target_lang(s_init, "#"); + outputCommandLineArguments(s_init); + + Printf(f_wrapper, "#ifdef __cplusplus\n"); + Printf(f_wrapper, "extern \"C\" {\n"); + Printf(f_wrapper, "#endif\n\n"); + + Language::top(n); + + Printf(f_wrapper, "#ifdef __cplusplus\n"); + Printf(f_wrapper, "}\n"); + Printf(f_wrapper, "#endif\n"); + + String *type_table = NewString(""); + SwigType_emit_type_table(f_runtime,f_wrapper); + Delete(type_table); + + if(ClassMemberTable) { + //XXX OutputClassAccessInfo(ClassMemberTable, sfile); + Delete(ClassMemberTable); + ClassMemberTable = NULL; + } + + Printf(f_init,"}\n"); + if(registrationTable) + outputRegistrationRoutines(f_init); + + /* Now arrange to write the 2 files - .S and .c. */ + + DumpCode(n); + + Delete(sfile); + Delete(s_classes); + Delete(s_init); + Delete(f_wrapper); + Delete(f_init); + + Delete(s_header); + Delete(f_runtime); + Delete(f_begin); + + return SWIG_OK; +} + + +/* ------------------------------------------------------------- + * Write the generated code to the .S and the .c files. + * ------------------------------------------------------------- */ +int R::DumpCode(Node *n) { + String *output_filename = NewString(""); + + + /* The name of the file in which we will generate the S code. */ + Printf(output_filename, "%s%s.R", SWIG_output_directory(), Rpackage); + +#ifdef R_SWIG_VERBOSE + Printf(stdout, "Writing S code to %s\n", output_filename); +#endif + + File *scode = NewFile(output_filename, "w", SWIG_output_files()); + if (!scode) { + FileErrorDisplay(output_filename); + Exit(EXIT_FAILURE); + } + Delete(output_filename); + + + Printf(scode, "%s\n\n", s_init); + Printf(scode, "%s\n\n", s_classes); + Printf(scode, "%s\n", sfile); + Printf(scode, "%s\n", enum_def_calls); + + Delete(scode); + String *outfile = Getattr(n,"outfile"); + File *runtime = NewFile(outfile,"w", SWIG_output_files()); + if (!runtime) { + FileErrorDisplay(outfile); + Exit(EXIT_FAILURE); + } + + Printf(runtime, "%s", f_begin); + Printf(runtime, "%s\n", f_runtime); + Printf(runtime, "%s\n", s_header); + Printf(runtime, "%s\n", f_wrapper); + Printf(runtime, "%s\n", f_init); + + Delete(runtime); + + if(outputNamespaceInfo) { + output_filename = NewString(""); + Printf(output_filename, "%sNAMESPACE", SWIG_output_directory()); + File *ns = NewFile(output_filename, "w", SWIG_output_files()); + if (!ns) { + FileErrorDisplay(output_filename); + Exit(EXIT_FAILURE); + } + Delete(output_filename); + + Printf(ns, "%s\n", s_namespace); + + Printf(ns, "\nexport(\n"); + writeListByLine(namespaceFunctions, ns); + Printf(ns, ")\n"); + Printf(ns, "\nexportMethods(\n"); + writeListByLine(namespaceMethods, ns, 1); + Printf(ns, ")\n"); + Delete(ns); + Delete(s_namespace); + } + + return SWIG_OK; +} + + +List *R::filterMemberList(List *class_member_types, + List *class_member_other, + String *R_MEMBER, bool equal) { + // filters class_member_other based on whether corresponding elements of + // class_member_function_types are equal or notequal to R_MEMBER + List *CM = NewList(); + Iterator ftype, other; + + for (ftype = First(class_member_types), other = First(class_member_other); + ftype.item; + ftype=Next(ftype), other=Next(other)) { + // verbose, clean up later if the overall structure works + if (equal) { + if (ftype.item == R_MEMBER) { + Append(CM, other.item); + } + } else { + if (ftype.item != R_MEMBER) { + Append(CM, other.item); + } + } + } + return(CM); +} + +# if 0 +// not called +/* ------------------------------------------------------------- + * We may need to do more.... so this is left as a + * stub for the moment. + * -------------------------------------------------------------*/ +int R::OutputClassAccessInfo(Hash *tb, File *out) { + int n = OutputClassMemberTable(tb, out); + OutputClassMethodsTable(out); + return n; +} + +/* ------------------------------------------------------------- + * Currently this just writes the information collected about the + * different methods of the C++ classes that have been processed + * to the console. + * This will be used later to define S4 generics and methods. + * --------------------------------------------------------------*/ + +int R::OutputClassMethodsTable(File *) { + Hash *tb = ClassMethodsTable; + + if(!tb) + return SWIG_OK; + + List *keys = Keys(tb); + String *key; + int i, n = Len(keys); + if (debugMode) { + for(i = 0; i < n ; i++ ) { + key = Getitem(keys, i); + Printf(stdout, "%d) %s\n", i, key); + List *els = Getattr(tb, key); + int nels = Len(els); + Printf(stdout, "\t"); + for(int j = 0; j < nels; j+=2) { + Printf(stdout, "%s%s", Getitem(els, j), j < nels - 1 ? ", " : ""); + Printf(stdout, "%s\n", Getitem(els, j+1)); + } + Printf(stdout, "\n"); + } + } + + return SWIG_OK; +} + + +/* -------------------------------------------------------------- + * Iterate over the <class name>_set and <>_get + * elements and generate the $ and $<- functions + * that provide constrained access to the member + * fields in these elements. + + * tb - a hash table that is built up in functionWrapper + * as we process each membervalueHandler. + * The entries are indexed by <class name>_set and + * <class_name>_get. Each entry is a List *. + + * out - the stream where the code is to be written. This is the S + * code stream as we generate only S code here. + * --------------------------------------------------------------*/ + +int R::OutputClassMemberTable(Hash *tb, File *out) { + List *keys = Keys(tb), *el; + + String *key; + int i, n = Len(keys); + /* Loop over all the <Class>_set and <Class>_get entries in the table. */ + /* This function checks for names ending in _set - perhaps it should */ + /* use attributes of some other form, as it potentially clashes with */ + /* methods ending in _set */ + + if(n && outputNamespaceInfo) { + Printf(s_namespace, "exportClasses("); + } + for(i = 0; i < n; i++) { + key = Getitem(keys, i); + el = Getattr(tb, key); + + String *className = Getitem(el, 0); + char *ptr = Char(key); + int klen = Len(key); + int isSet = 0; + if (klen > 4) { + ptr = &ptr[klen - 4]; + isSet = strcmp(ptr, "_set") == 0; + } + + if(outputNamespaceInfo) + Printf(s_namespace, "\"%s\"%s", className, i < n-1 ? "," : ""); + } + if(n && outputNamespaceInfo) { + Printf(s_namespace, ")\n"); + } + + return n; +} + +// end not used +#endif +/* -------------------------------------------------------------- + * Write the methods for $ or $<- for accessing a member field in an + * struct or union (or class). + * className - the name of the struct or union (e.g. Bar for struct Bar) + * isSet - a logical value indicating whether the method is for + * modifying ($<-) or accessing ($) the member field. + * el - a list of length 2 * # accessible member elements + 1. + * The first element is the name of the class. + * The other pairs are member name and the name of the R function to access it. + * out - the stream where we write the code. + * --------------------------------------------------------------*/ + +int R::OutputMemberReferenceMethod(String *className, int isSet, + List *memberList, List *nameList, + List *typeList, File *out) { + int numMems = Len(memberList), j; + int varaccessor = 0; + if (numMems == 0) + return SWIG_OK; + + Wrapper *f = NewWrapper(), *attr = NewWrapper(); + + Printf(f->def, "function(x, name%s)", isSet ? ", value" : ""); + Printf(attr->def, "function(x, i, j, ...%s)", isSet ? ", value" : ""); + + Printf(f->code, "{\n"); + Printf(f->code, "%saccessorFuns = list(", tab8); + + Node *itemList = NewHash(); + bool has_prev = false; + for(j = 0; j < numMems; j++) { + String *item = Getitem(memberList, j); + String *dup = Getitem(nameList, j); + String *setgetmethod = Getitem(typeList, j); + + if (setgetmethod == R_MEMBER_GET) + varaccessor++; + + if (Getattr(itemList, item)) + continue; + Setattr(itemList, item, "1"); + + String *pitem; + if (!Strcmp(item, "operator ()")) { + pitem = NewString("call"); + } else if (!Strcmp(item, "operator ->")) { + pitem = NewString("deref"); + } else if (!Strcmp(item, "operator +")) { + pitem = NewString("add"); + } else if (!Strcmp(item, "operator -")) { + pitem = NewString("sub"); + } else { + pitem = Copy(item); + } + if (has_prev) + Printf(f->code, ", "); + Printf(f->code, "'%s' = %s", pitem, dup); + has_prev = true; + Delete(pitem); + } + Delete(itemList); + Printf(f->code, ");\n"); + + if (!isSet && varaccessor > 0) { + Printf(f->code, "%svaccessors = c(", tab8); + bool first = true; + for(j = 0; j < numMems; j++) { + String *item = Getitem(memberList, j); + String *setgetmethod = Getitem(typeList, j); + + // Check the type here instead of the name + if (setgetmethod == R_MEMBER_GET) { + Printf(f->code, "%s'%s'", first ? "" : ", ", item); + first = false; + } + } + Printf(f->code, ");\n"); + } + + Printv(f->code, ";", tab8, + "idx = pmatch(name, names(accessorFuns));\n", + tab8, + "if(is.na(idx)) \n", + tab8, tab4, NIL); + Printf(f->code, "return(callNextMethod(x, name%s));\n", + isSet ? ", value" : ""); + Printv(f->code, tab8, "f = accessorFuns[[idx]];\n", NIL); + if(isSet) { + Printv(f->code, tab8, "f(x, value);\n", NIL); + Printv(f->code, tab8, "x;\n", NIL); // make certain to return the S value. + } else { + if (varaccessor) { + Printv(f->code, tab8, + "if (is.na(match(name, vaccessors))) function(...){f(x, ...)} else f(x);\n", NIL); + } else { + Printv(f->code, tab8, "function(...){f(x, ...)};\n", NIL); + } + } + Printf(f->code, "}\n"); + + String *classname_str = SwigType_namestr(className); + Printf(out, "# Start of accessor method for %s\n", classname_str); + Printf(out, "setMethod('$%s', '_p%s', ", + isSet ? "<-" : "", + getRClassName(className)); + Wrapper_print(f, out); + Printf(out, ");\n"); + + if(isSet) { + Printf(out, "setMethod('[[<-', c('_p%s', 'character'),", + getRClassName(className)); + Insert(f->code, 2, "name = i;\n"); + Printf(attr->code, "%s", f->code); + Wrapper_print(attr, out); + Printf(out, ");\n"); + } + + Printf(out, "# end of accessor method for %s\n", classname_str); + + Delete(classname_str); + DelWrapper(attr); + DelWrapper(f); + + return SWIG_OK; +} + +/* ------------------------------------------------------------- + * Called when a enumeration is to be processed. + * We want to call the R function defineEnumeration(). + * tdname is the typedef of the enumeration, i.e. giving its name. + * --------------------------------------------------------------*/ + +int R::enumDeclaration(Node *n) { + if (!ImportMode) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + String *symname = Getattr(n, "sym:name"); + + // TODO - deal with anonymous enumerations + // Previous enum code for R didn't wrap them + if (!symname || Getattr(n, "unnamedinstance")) + return SWIG_NOWRAP; + + // create mangled name for the enum + // This will have content if the %nspace feature is set on + // the input file + String *nspace = Getattr(n, "sym:nspace"); // NSpace/getNSpace() only works during Language::enumDeclaration call + String *ename; + + String *name = Getattr(n, "name"); + ename = getRClassName(name); + if (debugMode) { + Node *current_class = getCurrentClass(); + String *cl = NewString(""); + if (current_class) { + cl = getEnumClassPrefix(); + } + Printf(stdout, "enumDeclaration: %s, %s, %s, %s, %s\n", name, symname, nspace, ename, cl); + } + Delete(name); + // set up a call to create the R enum structure. The list of + // individual elements will be built in enum_code + enum_values = 0; + // Emit each enum item + Language::enumDeclaration(n); + + Printf(enum_def_calls, "defineEnumeration(\"%s\",\n .values=c(%s))\n\n", ename, enum_values); + Delete(enum_values); + Delete(ename); + } + return SWIG_OK; +} + +/* ------------------------------------------------------------- +* --------------------------------------------------------------*/ + +int R::enumvalueDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) { + Printf(stdout, "evd: Not public\n"); + return SWIG_NOWRAP; + } + + Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + Node *parent = parentNode(n); + String *parent_name = Getattr(parent, "name"); + String *newsymname = 0; + String *tmpValue; + + // Strange hack from parent method + if (value) + tmpValue = NewString(value); + else + tmpValue = NewString(name); + // Note that this is used in enumValue() amongst other places + Setattr(n, "value", tmpValue); + + // Deal with enum values that are not int + int swigtype = SwigType_type(Getattr(n, "type")); + if (swigtype == T_CHAR) { + if (Getattr(n, "enumstringval")) { + String *val = NewStringf("'%(escape)s'", Getattr(n, "enumstringval")); + Setattr(n, "enumvalue", val); + Delete(val); + } + } else { + String *numval = Getattr(n, "enumnumval"); + if (numval) Setattr(n, "enumvalue", numval); + } + + if (GetFlag(parent, "scopedenum")) { + newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); + symname = newsymname; + } + + { + // Wrap C/C++ enums with constant integers or use the typesafe enum pattern + SwigType *typemap_lookup_type = parent_name ? parent_name : NewString("enum "); + if (debugMode) { + Printf(stdout, "Setting type: %s\n", Copy(typemap_lookup_type)); + } + Setattr(n, "type", typemap_lookup_type); + + // Simple integer constants + // Note these are always generated for anonymous enums, no matter what enum_feature is specified + // Code generated is the same for SimpleEnum and TypeunsafeEnum -> the class it is generated into is determined later + + String *value = enumValue(n); + if (enum_values) { + Printf(enum_values, ",\n\"%s\" = %s", name, value); + } else { + enum_values = NewString(""); + Printf(enum_values, "\"%s\" = %s", name, value); + } + + Delete(value); + } + + return SWIG_OK; +} + + +/* ------------------------------------------------------------- + * Create accessor functions for variables. + * Does not create equivalent wrappers for enumerations, + * which are handled differently + * --------------------------------------------------------------*/ + +int R::variableWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + if (debugMode) { + Printf(stdout, "variableWrapper %s\n", n); + } + processing_variable = 1; + Language::variableWrapper(n); // Force the emission of the _set and _get function wrappers. + processing_variable = 0; + + + SwigType *ty = Getattr(n, "type"); + String *nodeType = nodeType(n); + int addCopyParam = addCopyParameter(ty); + + //XXX + processType(ty, n); + + if (nodeType && !Strcmp(nodeType, "enumitem")) { + /* special wrapper for enums - don't want the R _set, _get functions*/ + if (debugMode) { + Printf(stdout, "variableWrapper enum branch\n"); + } + } else if(!SwigType_isconst(ty)) { + Wrapper *f = NewWrapper(); + Printf(f->def, "%s = \nfunction(value%s)\n{\n", + name, addCopyParam ? ", .copy = FALSE" : ""); + Printv(f->code, "if(missing(value)) {\n", + name, "_get(", addCopyParam ? ".copy" : "", ")\n}", NIL); + Printv(f->code, " else {\n", + name, "_set(value)\n}\n}", NIL); + + Wrapper_print(f, sfile); + DelWrapper(f); + } else { + Printf(sfile, "%s = %s_get\n", name, name); + } + + return SWIG_OK; +} + +/* ------------------------------------------------------------- + * Creates accessor functions for class members. + + * ToDo - this version depends on naming conventions and needs + * to be replaced. + * --------------------------------------------------------------*/ + +void R::addAccessor(String *memberName, Wrapper *wrapper, String *name, + String *methodSetGet) { + + if (!class_member_function_names) { + class_member_function_names = NewList(); + class_member_function_membernames = NewList(); + class_member_function_wrappernames = NewList(); + class_member_function_types = NewList(); + } + Append(class_member_function_types, methodSetGet); + Append(class_member_function_names, name); + Append(class_member_function_membernames, memberName); + + String *tmp = NewString(""); + Wrapper_print(wrapper, tmp); + Append(class_member_function_wrappernames, tmp); + // if we could put the wrapper in directly: Append(l, Copy(sfun)); + if (debugMode) + Printf(stdout, "Adding accessor: %s (%s) => %s\n", memberName, name, tmp); +} + +#define MAX_OVERLOAD 256 + +namespace { +struct Overloaded { + Node *n; /* Node */ + int argc; /* Argument count */ + ParmList *parms; /* Parameters used for overload check */ + int error; /* Ambiguity error */ +}; +} + +List * R::Swig_overload_rank(Node *n, + bool script_lang_wrapping) { + Overloaded nodes[MAX_OVERLOAD]; + int nnodes = 0; + Node *o = Getattr(n,"sym:overloaded"); + + + if (!o) return 0; + + Node *c = o; + while (c) { + if (Getattr(c,"error")) { + c = Getattr(c,"sym:nextSibling"); + continue; + } + /* Make a list of all the declarations (methods) that are overloaded with + * this one particular method name */ + + if (Getattr(c,"wrap:name")) { + nodes[nnodes].n = c; + nodes[nnodes].parms = Getattr(c,"wrap:parms"); + nodes[nnodes].argc = emit_num_required(nodes[nnodes].parms); + nodes[nnodes].error = 0; + nnodes++; + } + c = Getattr(c,"sym:nextSibling"); + } + + /* Sort the declarations by required argument count */ + { + int i,j; + for (i = 0; i < nnodes; i++) { + for (j = i+1; j < nnodes; j++) { + if (nodes[i].argc > nodes[j].argc) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + } + } + } + + /* Sort the declarations by argument types */ + { + int i,j; + for (i = 0; i < nnodes-1; i++) { + if (nodes[i].argc == nodes[i+1].argc) { + for (j = i+1; (j < nnodes) && (nodes[j].argc == nodes[i].argc); j++) { + Parm *p1 = nodes[i].parms; + Parm *p2 = nodes[j].parms; + int differ = 0; + int num_checked = 0; + while (p1 && p2 && (num_checked < nodes[i].argc)) { + if (debugMode) { + Printf(stdout,"p1 = '%s', p2 = '%s'\n", Getattr(p1,"type"), Getattr(p2,"type")); + } + if (checkAttribute(p1,"tmap:in:numinputs","0")) { + p1 = Getattr(p1,"tmap:in:next"); + continue; + } + if (checkAttribute(p2,"tmap:in:numinputs","0")) { + p2 = Getattr(p2,"tmap:in:next"); + continue; + } + String *t1 = Getattr(p1,"tmap:typecheck:precedence"); + String *t2 = Getattr(p2,"tmap:typecheck:precedence"); + if (debugMode) { + Printf(stdout,"t1 = '%s', t2 = '%s'\n", t1, t2); + } + if ((!t1) && (!nodes[i].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n), + "Overloaded method %s not supported (incomplete type checking rule - no precedence level in typecheck typemap for '%s').\n", + Swig_name_decl(nodes[i].n), SwigType_str(Getattr(p1, "type"), 0)); + nodes[i].error = 1; + } else if ((!t2) && (!nodes[j].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s not supported (incomplete type checking rule - no precedence level in typecheck typemap for '%s').\n", + Swig_name_decl(nodes[j].n), SwigType_str(Getattr(p2, "type"), 0)); + nodes[j].error = 1; + } + if (t1 && t2) { + int t1v, t2v; + t1v = atoi(Char(t1)); + t2v = atoi(Char(t2)); + differ = t1v-t2v; + } + else if (!t1 && t2) differ = 1; + else if (t1 && !t2) differ = -1; + else if (!t1 && !t2) differ = -1; + num_checked++; + if (differ > 0) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + break; + } else if ((differ == 0) && (Strcmp(t1,"0") == 0)) { + t1 = Getattr(p1,"ltype"); + if (!t1) { + t1 = SwigType_ltype(Getattr(p1,"type")); + if (Getattr(p1,"tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t1); + } + Setattr(p1,"ltype",t1); + } + t2 = Getattr(p2,"ltype"); + if (!t2) { + t2 = SwigType_ltype(Getattr(p2,"type")); + if (Getattr(p2,"tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t2); + } + Setattr(p2,"ltype",t2); + } + + /* Need subtype check here. If t2 is a subtype of t1, then we need to change the + order */ + + if (SwigType_issubtype(t2,t1)) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + + if (Strcmp(t1,t2) != 0) { + differ = 1; + break; + } + } else if (differ) { + break; + } + if (Getattr(p1,"tmap:in:next")) { + p1 = Getattr(p1,"tmap:in:next"); + } else { + p1 = nextSibling(p1); + } + if (Getattr(p2,"tmap:in:next")) { + p2 = Getattr(p2,"tmap:in:next"); + } else { + p2 = nextSibling(p2); + } + } + if (!differ) { + /* See if declarations differ by const only */ + String *d1 = Getattr(nodes[i].n, "decl"); + String *d2 = Getattr(nodes[j].n, "decl"); + if (d1 && d2) { + String *dq1 = Copy(d1); + String *dq2 = Copy(d2); + if (SwigType_isconst(d1)) { + Delete(SwigType_pop(dq1)); + } + if (SwigType_isconst(d2)) { + Delete(SwigType_pop(dq2)); + } + if (Strcmp(dq1, dq2) == 0) { + + if (SwigType_isconst(d1) && !SwigType_isconst(d2)) { + if (script_lang_wrapping) { + // Swap nodes so that the const method gets ignored (shadowed by the non-const method) + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n), + "using non-const method %s instead.\n", Swig_name_decl(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) { + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), + "using %s instead.\n", Swig_name_decl(nodes[i].n)); + } + } + } + nodes[j].error = 1; + } else if (!SwigType_isconst(d1) && SwigType_isconst(d2)) { + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n), + "using non-const method %s instead.\n", Swig_name_decl(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) { + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), + "using %s instead.\n", Swig_name_decl(nodes[i].n)); + } + } + } + nodes[j].error = 1; + } + } + Delete(dq1); + Delete(dq2); + } + } + if (!differ) { + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s effectively ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[i].n), Getline(nodes[i].n), + "as it is shadowed by %s.\n", Swig_name_decl(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) { + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), + "using %s instead.\n", Swig_name_decl(nodes[i].n)); + } + } + nodes[j].error = 1; + } + } + } + } + } + } + List *result = NewList(); + { + int i; + for (i = 0; i < nnodes; i++) { + if (nodes[i].error) + Setattr(nodes[i].n, "overload:ignore", "1"); + Append(result,nodes[i].n); + } + } + return result; +} + +void R::dispatchFunction(Node *n) { + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *nodeType = Getattr(n, "nodeType"); + bool constructor = (!Cmp(nodeType, "constructor")); + + String *sfname = NewString(symname); + + if (constructor) + Replace(sfname, "new_", "", DOH_REPLACE_FIRST); + + Printf(f->def, + "`%s` <- function(...) {", sfname); + if (debugMode) { + Swig_print_node(n); + } + List *dispatch = Swig_overload_rank(n, true); + int nfunc = Len(dispatch); + Printv(f->code, + "argtypes <- mapply(class, list(...));\n", + "argv <- list(...);\n", + "argc <- length(argtypes);\n", + "f <- NULL;\n", NIL); + + Printf(f->code, "# dispatch functions %d\n", nfunc); + int cur_args = -1; + bool first_compare = true; + for (int i=0; i < nfunc; i++) { + Node *ni = Getitem(dispatch,i); + Parm *pi = Getattr(ni,"wrap:parms"); + int num_arguments = emit_num_arguments(pi); + + String *overname = Getattr(ni,"sym:overname"); + if (cur_args != num_arguments) { + if (cur_args != -1) { + Printv(f->code, "} else ", NIL); + } + Printf(f->code, "if (argc == %d) {", num_arguments); + cur_args = num_arguments; + first_compare = true; + } + Parm *p; + int j; + if (num_arguments > 0) { + if (!first_compare) { + Printv(f->code, " else ", NIL); + } else { + first_compare = false; + } + Printv(f->code, "if (", NIL); + for (p = pi, j = 0 ; j < num_arguments ; j++) { + SwigType *pt = Getattr(p, "type"); + if (debugMode) { + Swig_print_node(p); + } + String *tm = Swig_typemap_lookup("rtype", p, "", 0); + if (tm) { + replaceRClass(tm, pt); + } + + /* Check if type have a %typemap(rtypecheck) */ + String *tmcheck = Getattr(p,"tmap:rtypecheck"); + if (tmcheck) { + tmcheck = Copy(tmcheck); + String *tmp_argtype = NewStringf("argtypes[%d]", j+1); + Replaceall(tmcheck, "$argtype", tmp_argtype); + String *tmp_arg = NewStringf("argv[[%d]]", j+1); + Replaceall(tmcheck, "$arg", tmp_arg); + replaceRClass(tmcheck, pt); + if (debugMode) { + Printf(stdout, "<rtypecheck>%s\n", tmcheck); + } + if (num_arguments == 1) { + Printf(f->code, "%s", tmcheck); + } else { + Printf(f->code, "%s(%s)", j == 0 ? "" : " && ", tmcheck); + } + Delete(tmcheck); + Delete(tmp_arg); + Delete(tmp_argtype); + } else { + Swig_warning(WARN_R_TYPEMAP_RTYPECHECK_UNDEF, input_file, line_number, "No rtypecheck typemap defined for %s\n", SwigType_str(pt, 0)); + } + p = Getattr(p, "tmap:in:next"); + } + Printf(f->code, ") { f <- %s%s; }\n", sfname, overname); + } else { + Printf(f->code, "f <- %s%s; ", sfname, overname); + } + } + if (cur_args != -1) { + Printf(f->code, "};\n"); + } + Printf(f->code, "if (is.null(f)) {\n" + "stop(\"cannot find overloaded function for %s with argtypes (\"," + "toString(argtypes),\")\");\n" + "}", sfname); + Printv(f->code, ";\nf(...)", NIL); + Printv(f->code, ";\n}", NIL); + Wrapper_print(f, sfile); + Printv(sfile, "# Dispatch function\n", NIL); + DelWrapper(f); +} + +/*-------------------------------------------------------------- + +* --------------------------------------------------------------*/ + +int R::functionWrapper(Node *n) { + String *fname = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + String *returntype = Getattr(n, "type"); + + if (debugMode) { + Printf(stdout, + "<functionWrapper> %s %s %s\n", fname, iname, returntype); + } + String *overname = 0; + String *nodeType = Getattr(n, "nodeType"); + bool constructor = (!Cmp(nodeType, "constructor")); + bool destructor = (!Cmp(nodeType, "destructor")); + + String *sfname = NewString(iname); + + if (constructor) + Replace(sfname, "new_", "", DOH_REPLACE_FIRST); + + if (Getattr(n,"sym:overloaded")) { + overname = Getattr(n,"sym:overname"); + Append(sfname, overname); + } + + if (debugMode) + Printf(stdout, + "<functionWrapper> processing parameters\n"); + + + ParmList *l = Getattr(n, "parms"); + Parm *p; + String *tm; + + p = l; + while(p) { + SwigType *resultType = Getattr(p, "type"); + if (expandTypedef(resultType) && + SwigType_istypedef(resultType)) { + SwigType *resolved = + SwigType_typedef_resolve_all(resultType); + if (expandTypedef(resolved)) { + if (debugMode) { + Printf(stdout, "Setting type: %s\n", resolved); + } + Setattr(p, "type", Copy(resolved)); + } + } + p = nextSibling(p); + } + + String *unresolved_return_type = Copy(returntype); + if (expandTypedef(returntype) && SwigType_istypedef(returntype)) { + SwigType *resolved = SwigType_typedef_resolve_all(returntype); + if (debugMode) + Printf(stdout, "<functionWrapper> resolved %s\n", Copy(unresolved_return_type)); + if (expandTypedef(resolved)) { + returntype = Copy(resolved); + Setattr(n, "type", returntype); + } + } + if (debugMode) + Printf(stdout, "<functionWrapper> unresolved_return_type %s\n", unresolved_return_type); + if(processing_member_access_function) { + if (debugMode) + Printf(stdout, "<functionWrapper memberAccess> '%s' '%s' '%s' '%s'\n", fname, iname, member_name, class_name); + + if(opaqueClassDeclaration) + return SWIG_OK; + + + /* Add the name of this member to a list for this class_name. + We will dump all these at the end. */ + + bool isSet = GetFlag(n, "memberset") ? true : false; + + String *tmp = NewString(isSet ? Swig_name_set(NSPACE_TODO, class_name) : Swig_name_get(NSPACE_TODO, class_name)); + + List *memList = Getattr(ClassMemberTable, tmp); + if(!memList) { + memList = NewList(); + Append(memList, class_name); + Setattr(ClassMemberTable, tmp, memList); + } + Delete(tmp); + Append(memList, member_name); + Append(memList, iname); + } + + int i; + int nargs; + + String *wname = Swig_name_wrapper(iname); + + if(overname) + Append(wname, overname); + Setattr(n,"wrap:name", wname); + + Wrapper *f = NewWrapper(); + Wrapper *sfun = NewWrapper(); + + int isVoidReturnType = (Strcmp(returntype, "void") == 0); + // Need to use the unresolved returntype since + // typedef resolution removes the const which causes a + // mismatch with the function action + emit_return_variable(n, unresolved_return_type, f); + + SwigType *rtype = Getattr(n, "type"); + int addCopyParam = 0; + + if(!isVoidReturnType) + addCopyParam = addCopyParameter(rtype); + + if (debugMode) + Printf(stdout, "Adding a .copy argument to %s for %s = %s\n", iname, returntype, addCopyParam ? "yes" : "no"); + + Printv(f->def, "SWIGEXPORT SEXP\n", wname, " ( ", NIL); + + Printf(sfun->def, "# Start of %s\n", iname); + Printv(sfun->def, "\n`", sfname, "` = function(", NIL); + + if(outputNamespaceInfo) {//XXX Need to be a little more discriminating + if (constructor) { + String *niname = Copy(iname); + Replace(niname, "new_", "", DOH_REPLACE_FIRST); + addNamespaceFunction(niname); + Delete(niname); + } else { + addNamespaceFunction(iname); + } + } + + Swig_typemap_attach_parms("scoercein", l, f); + Swig_typemap_attach_parms("scoerceout", l, f); + Swig_typemap_attach_parms("scheck", l, f); + Swig_typemap_attach_parms("rtypecheck", l, f); + + emit_parameter_variables(l, f); + emit_attach_parmmaps(l,f); + Setattr(n,"wrap:parms",l); + + nargs = emit_num_arguments(l); + + Wrapper_add_local(f, "r_nprotect", "unsigned int r_nprotect = 0"); + Wrapper_add_localv(f, "r_ans", "SEXP", "r_ans = R_NilValue", NIL); + Wrapper_add_localv(f, "r_vmax", "VMAXTYPE", "r_vmax = vmaxget()", NIL); + + String *sargs = NewString(""); + + + String *s_inputTypes = NewString(""); + String *s_inputMap = NewString(""); + bool inFirstArg = true; + bool inFirstType = true; + Parm *curP; + for (p =l, i = 0 ; i < nargs ; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *tt = Getattr(p, "type"); + int nargs = -1; + String *funcptr_name = processType(tt, p, &nargs); + + String *name = makeParameterName(n, p, i+1, false); + String *lname = Getattr(p, "lname"); + + if (name) { + /* If we have a :: in the parameter name because we are accessing a static member of a class, say, then + we need to remove that prefix. */ + while (Strstr(name, "::")) { + String *oldname = name; + name = NewStringf("%s", Strchr(name, ':') + 2); + if (debugMode) + Printf(stdout, "+++ parameter name with :: in it %s\n", name); + Delete(oldname); + } + } + + name = replaceInitialDash(name); + + if (!Strncmp(name, "arg", 3)) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + if(processing_variable) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + if(!Strcmp(name, fname)) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + Printf(sargs, "%s, ", name); + + String *tm; + if((tm = Getattr(p, "tmap:scoercein"))) { + Replaceall(tm, "$input", name); + replaceRClass(tm, Getattr(p, "type")); + + if(funcptr_name) { + //XXX need to get this to return non-zero + if(nargs == -1) + nargs = getFunctionPointerNumArgs(p, tt); + + String *snargs = NewStringf("%d", nargs); + Printv(sfun->code, "if(is.function(", name, ")) {", "\n", + "assert('...' %in% names(formals(", name, + ")) || length(formals(", name, ")) >= ", snargs, ");\n} ", NIL); + Delete(snargs); + + Printv(sfun->code, "else {\n", + "if(is.character(", name, ")) {\n", + name, " = getNativeSymbolInfo(", name, ");", + "\n};\n", + "if(is(", name, ", \"NativeSymbolInfo\")) {\n", + name, " = ", name, "$address", ";\n};\n", + "if(is(", name, ", \"ExternalReference\")) {\n", + name, " = ", name, "@ref;\n}\n", + "}; \n", + NIL); + } else { + Printf(sfun->code, "%s\n", tm); + } + } + + Printv(sfun->def, inFirstArg ? "" : ", ", name, NIL); + + if ((tm = Getattr(p,"tmap:scheck"))) { + + Replaceall(tm,"$input", name); + replaceRClass(tm, Getattr(p, "type")); + Printf(sfun->code,"%s\n",tm); + } + + + + curP = p; + if ((tm = Getattr(p,"tmap:in"))) { + + Replaceall(tm,"$input", name); + + if (Getattr(p,"wrap:disown") || (Getattr(p,"tmap:in:disown"))) { + Replaceall(tm,"$disown","SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm,"$disown","0"); + } + + if(funcptr_name) { + /* have us a function pointer */ + Printf(f->code, "if(TYPEOF(%s) != CLOSXP) {\n", name); + Replaceall(tm,"$R_class", ""); + } else { + replaceRClass(tm, Getattr(p, "type")); + } + + + Printf(f->code,"%s\n",tm); + if(funcptr_name) + Printf(f->code, "} else {\n%s = %s;\nR_SWIG_pushCallbackFunctionData(%s, NULL);\n}\n", + lname, funcptr_name, name); + Printv(f->def, inFirstArg ? "" : ", ", "SEXP ", name, NIL); + if (Len(name) != 0) + inFirstArg = false; + p = Getattr(p,"tmap:in:next"); + + } else { + p = nextSibling(p); + } + + + tm = Swig_typemap_lookup("rtype", curP, "", 0); + if(tm) { + replaceRClass(tm, Getattr(curP, "type")); + } + Printf(s_inputTypes, "%s'%s'", inFirstType ? "" : ", ", tm); + Printf(s_inputMap, "%s%s='%s'", inFirstType ? "" : ", ", name, tm); + inFirstType = false; + + if(funcptr_name) + Delete(funcptr_name); + } /* end of looping over parameters. */ + + if(addCopyParam) { + Printf(sfun->def, "%s.copy = FALSE", nargs > 0 ? ", " : ""); + Printf(f->def, "%sSEXP s_swig_copy", nargs > 0 ? ", " : ""); + + Printf(sargs, "as.logical(.copy), "); + } + + Printv(f->def, ")\n{\n", NIL); + // SWIG_fail in R leads to a call to Rf_error() which calls longjmp() + // which means the destructors of any live function-local C++ objects won't + // get run. To avoid this happening, we wrap almost everything in the + // function in a block, and end that right before Rf_error() at which + // point those destructors will get called. + if (CPlusPlus) Append(f->def, "{\n"); + + Printv(sfun->def, ")\n{\n", NIL); + + + /* Insert cleanup code */ + String *cleanup = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + if (tm && (Len(tm) != 0)) { + Printv(cleanup, tm, "\n", NIL); + } + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + String *outargs = NewString(""); + int numOutArgs = isVoidReturnType ? -1 : 0; + for(p = l, i = 0; p; i++) { + if((tm = Getattr(p, "tmap:argout"))) { + // String *lname = Getattr(p, "lname"); + numOutArgs++; + String *pos = NewStringf("%d", numOutArgs); + Replaceall(tm,"$result", "r_ans"); + Replaceall(tm,"$n", pos); // The position into which to store the answer. + Replaceall(tm,"$arg", Getattr(p, "emit:input")); + Replaceall(tm,"$input", Getattr(p, "emit:input")); + Replaceall(tm,"$owner", "0"); + + + Printf(outargs, "%s\n", tm); + p = Getattr(p,"tmap:argout:next"); + } else + p = nextSibling(p); + } + + String *actioncode = emit_action(n); + + /* Deal with the explicit return value. */ + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + SwigType *retType = Getattr(n, "type"); + + Replaceall(tm,"$1", Swig_cresult_name()); + Replaceall(tm,"$result", "r_ans"); + if (debugMode){ + Printf(stdout, "Calling replace D: %s, %s, %s\n", retType, n, tm); + } + replaceRClass(tm, retType); + + if (GetFlag(n,"feature:new")) { + Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); + } else { + Replaceall(tm,"$owner", "0"); + } + + Printf(f->code, "%s\n", tm); + + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, + "Unable to use return type %s in function %s.\n", SwigType_str(returntype, 0), fname); + } + + + if(Len(outargs)) { + Wrapper_add_local(f, "R_OutputValues", "SEXP R_OutputValues"); + + String *tmp = NewString(""); + if(!isVoidReturnType) + Printf(tmp, "Rf_protect(r_ans);\n"); + + Printf(tmp, "Rf_protect(R_OutputValues = Rf_allocVector(VECSXP,%d));\nr_nprotect += %d;\n", + numOutArgs + !isVoidReturnType, + isVoidReturnType ? 1 : 2); + + if(!isVoidReturnType) + Printf(tmp, "SET_VECTOR_ELT(R_OutputValues, 0, r_ans);\n"); + Printf(tmp, "r_ans = R_OutputValues;\n"); + + Insert(outargs, 0, tmp); + Delete(tmp); + + + + Printv(f->code, outargs, NIL); + Delete(outargs); + + } + + /* Output cleanup code */ + int need_cleanup = Len(cleanup) != 0; + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + Printv(f->code, UnProtectWrapupCode, NIL); + + /*If the user gave us something to convert the result in */ + if ((tm = Swig_typemap_lookup("scoerceout", n, Swig_cresult_name(), sfun))) { + Replaceall(tm,"$result","ans"); + if (debugMode) { + Printf(stdout, "Calling replace B: %s, %s, %s\n", Getattr(n, "type"), Getattr(n, "sym:name"), getNSpace()); + } + replaceRClass(tm, Getattr(n, "type")); + Chop(tm); + } + + + Printv(sfun->code, ";", (Len(tm) ? "ans = " : ""), ".Call('", wname, + "', ", sargs, "PACKAGE='", Rpackage, "');\n", NIL); + if(Len(tm)) + { + Printf(sfun->code, "%s\n\n", tm); + if (constructor) + { + String *finalizer = NewString(iname); + Replace(finalizer, "new_", "", DOH_REPLACE_FIRST); + Printf(sfun->code, "reg.finalizer(ans@ref, delete_%s);\n", finalizer); + } + Printf(sfun->code, "ans\n"); + } + + if (destructor) + Printv(f->code, "R_ClearExternalPtr(self);\n", NIL); + + Printv(f->code, "return r_ans;\n", NIL); + + /* Error handling code */ + Printv(f->code, "fail: SWIGUNUSED;\n", NIL); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + if (CPlusPlus) Append(f->code, "}\n"); + Printv(f->code, " Rf_error(\"%s %s\", SWIG_ErrorType(SWIG_lasterror_code), SWIG_lasterror_msg);\n", NIL); + Printv(f->code, " return R_NilValue;\n", NIL); + Delete(cleanup); + + Printv(f->code, "}\n", NIL); + Printv(sfun->code, "\n}", NIL); + + bool isvoid = !Cmp(returntype, "void"); + Replaceall(f->code, "$isvoid", isvoid ? "1" : "0"); + + /* Substitute the function name */ + Replaceall(f->code,"$symname",iname); + + Wrapper_print(f, f_wrapper); + Wrapper_print(sfun, sfile); + + Printf(sfun->code, "\n# End of %s\n", iname); + tm = Swig_typemap_lookup("rtype", n, "", 0); + if(tm) { + SwigType *retType = Getattr(n, "type"); + if (debugMode) { + Printf(stdout, "Calling replace C: %s\n", Copy(retType)); + } + replaceRClass(tm, retType); + } + + Printv(sfile, "attr(`", sfname, "`, 'returnType') = '", + isVoidReturnType ? "void" : (tm ? tm : ""), + "'\n", NIL); + + if(nargs > 0) + Printv(sfile, "attr(`", sfname, "`, \"inputTypes\") = c(", + s_inputTypes, ")\n", NIL); + Printv(sfile, "class(`", sfname, "`) = c(\"SWIGFunction\", class('", + sfname, "'))\n\n", NIL); + + if (memoryProfile) { + Printv(sfile, "memory.profile()\n", NIL); + } + if (aggressiveGc) { + Printv(sfile, "gc()\n", NIL); + } + + // Printv(sfile, "setMethod('", name, "', '", name, "', ", iname, ")\n\n\n"); + + + + /* If we are dealing with a method in an C++ class, then + add the name of the R function and its definition. + XXX need to figure out how to store the Wrapper if possible in the hash/list. + Would like to be able to do this so that we can potentially insert + */ + if(processing_member_access_function || processing_class_member_function) { + String *method_type = R_MEMBER_NORMAL; + if (GetFlag(n, "memberset")) { + method_type = R_MEMBER_SET; + } else if (GetFlag(n, "memberget")) { + method_type = R_MEMBER_GET; + } + addAccessor(member_name, sfun, iname, method_type); + } + + if (Getattr(n, "sym:overloaded") && + !Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + + addRegistrationRoutine(wname, addCopyParam ? nargs +1 : nargs); + + DelWrapper(f); + DelWrapper(sfun); + + Delete(sargs); + Delete(sfname); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * R::constantWrapper() + * ---------------------------------------------------------------------- */ + +int R::constantWrapper(Node *n) { + (void) n; + // TODO + return SWIG_OK; +} + +/*-------------------------------------------------------------- + * Add the specified routine name to the collection of + * generated routines that are called from R functions. + * This is used to register the routines with R for + * resolving symbols. + + * rname - the name of the routine + * nargs - the number of arguments it expects. + * --------------------------------------------------------------*/ + +int R::addRegistrationRoutine(String *rname, int nargs) { + if(!registrationTable) + registrationTable = NewHash(); + + String *el = + NewStringf("{\"%s\", (DL_FUNC) &%s, %d}", rname, rname, nargs); + + Setattr(registrationTable, rname, el); + + return SWIG_OK; +} + +/* ------------------------------------------------------------- + * Write the registration information to an array and + * create the initialization routine for registering + * these. + * --------------------------------------------------------------*/ + +int R::outputRegistrationRoutines(File *out) { + int i, n; + if(!registrationTable) + return(0); + if(inCPlusMode) + Printf(out, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"); + + Printf(out, "#include <R_ext/Rdynload.h>\n\n"); + if(inCPlusMode) + Printf(out, "#ifdef __cplusplus\n}\n#endif\n\n"); + + Printf(out, "SWIGINTERN R_CallMethodDef CallEntries[] = {\n"); + + List *keys = Keys(registrationTable); + n = Len(keys); + for(i = 0; i < n; i++) + Printf(out, " %s,\n", Getattr(registrationTable, Getitem(keys, i))); + + Printf(out, " {NULL, NULL, 0}\n};\n\n"); + + if(!noInitializationCode) { + if (inCPlusMode) + Printv(out, "extern \"C\" ", NIL); + { /* R allows pckage names to have '.' in the name, which is not allowed in C++ var names + we simply replace all occurrences of '.' with '_' to construct the var name */ + String * Rpackage_sane = Copy(Rpackage); + Replace(Rpackage_sane, ".", "_", DOH_REPLACE_ANY); + Printf(out, "SWIGEXPORT void R_init_%s(DllInfo *dll) {\n", Rpackage_sane); + Delete(Rpackage_sane); + } + Printf(out, "%sR_registerRoutines(dll, NULL, CallEntries, NULL, NULL);\n", tab4); + if(Len(s_init_routine)) { + Printf(out, "\n%s\n", s_init_routine); + } + Printf(out, "}\n"); + } + + return n; +} + + + +/* ------------------------------------------------------------- + * Process a struct, union or class declaration in the source code, + * or an anonymous typedef struct + * --------------------------------------------------------------*/ + +//XXX What do we need to do here - +// Define an S4 class to refer to this. + +void R::registerClass(Node *n) { + String *name = Getattr(n, "name"); + + if (debugMode) + Swig_print_node(n); + String *sname = NewStringf("_p%s", SwigType_manglestr(name)); + if(!Getattr(SClassDefs, sname)) { + Setattr(SClassDefs, sname, sname); + String *base; + + if (CPlusPlus && (Strcmp(nodeType(n), "class") == 0)) { + base = NewString(""); + List *l = Getattr(n, "bases"); + if(Len(l)) { + Printf(base, "c("); + for(int i = 0; i < Len(l); i++) { + registerClass(Getitem(l, i)); + Printf(base, "'_p%s'%s", + SwigType_manglestr(Getattr(Getitem(l, i), "name")), + i < Len(l)-1 ? ", " : ""); + } + Printf(base, ")"); + } else { + base = NewString("'C++Reference'"); + } + } else + base = NewString("'ExternalReference'"); + + Printf(s_classes, "setClass('%s', contains = %s)\n", sname, base); + Delete(base); + } +} + +int R::classDeclaration(Node *n) { + + String *name = Getattr(n, "name"); + String *kind = Getattr(n, "kind"); + + if (debugMode) + Swig_print_node(n); + registerClass(n); + + + /* If we have a typedef union { ... } U, then we never get to see the typedef + via a regular call to typedefHandler. Instead, */ + if(Getattr(n, "unnamed") && Getattr(n, "storage") && Strcmp(Getattr(n, "storage"), "typedef") == 0 + && Getattr(n, "tdname") && Strcmp(Getattr(n, "tdname"), name) == 0) { + if (debugMode) + Printf(stdout, "Typedef in the class declaration for %s\n", name); + // typedefHandler(n); + } + + bool opaque = GetFlag(n, "feature:opaque") ? true : false; + + if(opaque) + opaqueClassDeclaration = name; + + int status = Language::classDeclaration(n); + + opaqueClassDeclaration = NULL; + + + if (class_member_function_types) { + + // collect the "set" methods + List *class_set_membernames = filterMemberList(class_member_function_types, + class_member_function_membernames, R_MEMBER_SET, true); + List *class_set_functionnames = filterMemberList(class_member_function_types, + class_member_function_names, R_MEMBER_SET, true); + // this one isn't used - collecting to keep code simpler + List *class_set_functiontypes = filterMemberList(class_member_function_types, + class_member_function_types, R_MEMBER_SET, true); + + // collect the others + List *class_other_membernames = filterMemberList(class_member_function_types, + class_member_function_membernames, R_MEMBER_SET, false); + List *class_other_functionnames = filterMemberList(class_member_function_types, + class_member_function_names, R_MEMBER_SET, false); + List *class_other_functiontypes = filterMemberList(class_member_function_types, + class_member_function_types, R_MEMBER_SET, false); + + if (Len(class_other_membernames) > 0) { + OutputMemberReferenceMethod(name, 0, class_other_membernames, class_other_functionnames, class_other_functiontypes, sfile); + } + if (Len(class_set_membernames) > 0) { + OutputMemberReferenceMethod(name, 1, class_set_membernames, class_set_functionnames, class_set_functiontypes, sfile); + } + Delete(class_set_membernames); + Delete(class_set_functionnames); + Delete(class_set_functiontypes); + Delete(class_other_membernames); + Delete(class_other_functionnames); + Delete(class_other_functiontypes); + } + + if (class_member_function_types) { + Delete(class_member_function_types); + class_member_function_types = NULL; + Delete(class_member_function_names); + class_member_function_names = NULL; + Delete(class_member_function_membernames); + class_member_function_membernames = NULL; + Delete(class_member_function_wrappernames); + class_member_function_wrappernames = NULL; + } + if (Getattr(n, "has_destructor")) { + Printf(sfile, "setMethod('delete', '_p%s', function(obj) {delete%s(obj)})\n", getRClassName(name), getRClassName(name)); + + } + if(!opaque && !Strcmp(kind, "struct") && copyStruct) { + + String *def = + NewStringf("setClass(\"%s\",\n%srepresentation(\n", name, tab4); + bool firstItem = true; + + for(Node *c = firstChild(n); c; ) { + String *elName; + String *tp; + + elName = Getattr(c, "name"); + + String *elKind = Getattr(c, "kind"); + if (!Equal(elKind, "variable")) { + c = nextSibling(c); + continue; + } + if (!Len(elName)) { + c = nextSibling(c); + continue; + } + tp = Swig_typemap_lookup("rtype", c, "", 0); + if(!tp) { + c = nextSibling(c); + continue; + } + if (Strstr(tp, "R_class")) { + c = nextSibling(c); + continue; + } + if (Strcmp(tp, "character") && + Strstr(Getattr(c, "decl"), "p.")) { + c = nextSibling(c); + continue; + } + + if (!firstItem) { + Printf(def, ",\n"); + } + // else + //XXX How can we tell if this is already done. + // SwigType_push(elType, elDecl); + + + // returns "" tp = processType(elType, c, NULL); + // Printf(stdout, "<classDeclaration> elType %p\n", elType); + // tp = getRClassNameCopyStruct(Getattr(c, "type"), 1); + + String *elNameT = replaceInitialDash(elName); + Printf(def, "%s%s = \"%s\"", tab8, elNameT, tp); + firstItem = false; + Delete(tp); + Delete(elNameT); + c = nextSibling(c); + } + Printf(def, "),\n%scontains = \"RSWIGStruct\")\n", tab8); + Printf(s_classes, "%s\n\n# End class %s\n\n", def, name); + + generateCopyRoutines(n); + + Delete(def); + } + + return status; +} + + + +/* ------------------------------------------------------------- + * Create the C routines that copy an S object of the class given + * by the given struct definition in Node *n to the C value + * and also the routine that goes from the C routine to an object + * of this S class. + * --------------------------------------------------------------*/ + +/*XXX + Clean up the toCRef - make certain the names are correct for the types, etc. + in all cases. +*/ + +int R::generateCopyRoutines(Node *n) { + Wrapper *copyToR = NewWrapper(); + Wrapper *copyToC = NewWrapper(); + + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + String *kind = Getattr(n, "kind"); + String *type; + + if(Len(tdname)) { + type = Copy(tdname); + } else { + type = NewStringf("%s %s", kind, name); + } + + String *mangledName = SwigType_manglestr(name); + + if (debugMode) + Printf(stdout, "generateCopyRoutines: name = %s, %s\n", name, type); + + Printf(copyToR->def, "CopyToR%s = function(value, obj = new(\"%s\"))\n{\n", + mangledName, name); + Printf(copyToC->def, "CopyToC%s = function(value, obj)\n{\n", + mangledName); + + Node *c = firstChild(n); + + for(; c; c = nextSibling(c)) { + String *elName = Getattr(c, "name"); + if (!Len(elName)) { + continue; + } + String *elKind = Getattr(c, "kind"); + if (!Equal(elKind, "variable")) { + continue; + } + + String *tp = Swig_typemap_lookup("rtype", c, "", 0); + if(!tp) { + continue; + } + if (Strstr(tp, "R_class")) { + continue; + } + if (Strcmp(tp, "character") && + Strstr(Getattr(c, "decl"), "p.")) { + continue; + } + + + /* The S functions to get and set the member value. */ + String *elNameT = replaceInitialDash(elName); + Printf(copyToR->code, "obj@%s = value$%s;\n", elNameT, elNameT); + Printf(copyToC->code, "obj$%s = value@%s;\n", elNameT, elNameT); + Delete(elNameT); + } + Printf(copyToR->code, "obj;\n}\n\n"); + String *rclassName = getRClassNameCopyStruct(type, 0); // without the Ref. + Printf(sfile, "# Start definition of copy functions & methods for %s\n", rclassName); + + Wrapper_print(copyToR, sfile); + Printf(copyToC->code, "obj\n}\n\n"); + Wrapper_print(copyToC, sfile); + + + Printf(sfile, "# Start definition of copy methods for %s\n", rclassName); + Printf(sfile, "setMethod('copyToR', '_p%s', CopyToR%s);\n", mangledName, + mangledName); + Printf(sfile, "setMethod('copyToC', '%s', CopyToC%s);\n\n", rclassName, + mangledName); + + Printf(sfile, "# End definition of copy methods for %s\n", rclassName); + Printf(sfile, "# End definition of copy functions & methods for %s\n", rclassName); + + String *m = NewStringf("%sCopyToR", name); + addNamespaceMethod(m); + char *tt = Char(m); tt[Len(m)-1] = 'C'; + addNamespaceMethod(m); + Delete(m); + Delete(rclassName); + Delete(mangledName); + DelWrapper(copyToR); + DelWrapper(copyToC); + + return SWIG_OK; +} + + + +/* ------------------------------------------------------------- + * Called when there is a typedef to be invoked. + * + * XXX Needs to be enhanced or split to handle the case where we have a + * typedef within a classDeclaration emission because the struct/union/etc. + * is anonymous. + * --------------------------------------------------------------*/ + +int R::typedefHandler(Node *n) { + SwigType *tp = Getattr(n, "type"); + String *type = Getattr(n, "type"); + if (debugMode) + Printf(stdout, "<typedefHandler> %s\n", Getattr(n, "name")); + + processType(tp, n); + + if(Strncmp(type, "struct ", 7) == 0) { + String *name = Getattr(n, "name"); + char *trueName = Char(type); + trueName += 7; + if (debugMode) + Printf(stdout, "<typedefHandler> Defining S class %s\n", trueName); + Printf(s_classes, "setClass('_p%s', contains = 'ExternalReference')\n", + SwigType_manglestr(name)); + } + + return Language::typedefHandler(n); +} + + + +/* -------------------------------------------------------------- + * Called when processing a field in a "class", i.e. struct, union or + * actual class. We set a state variable so that we can correctly + * interpret the resulting functionWrapper() call and understand that + * it is for a field element. + * --------------------------------------------------------------*/ + +int R::membervariableHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + processType(t, n, NULL); + processing_member_access_function = 1; + member_name = Getattr(n,"sym:name"); + if (debugMode) + Printf(stdout, "<membervariableHandler> name = %s, sym:name = %s\n", + Getattr(n, "name"), member_name); + + int status(Language::membervariableHandler(n)); + + if(!opaqueClassDeclaration && debugMode) + Printf(stdout, "<membervariableHandler> %s %s\n", Getattr(n, "name"), Getattr(n, "type")); + + processing_member_access_function = 0; + member_name = NULL; + + return status; +} + + +/* + This doesn't seem to get used so leave it out for the moment. +*/ +String * R::runtimeCode() { + String *s = Swig_include_sys("rrun.swg"); + if (!s) { + Printf(stdout, "*** Unable to open 'rrun.swg'\n"); + s = NewString(""); + } + return s; +} + +/*---------------------------------------------------------------------- + * replaceSpecialVariables() + *--------------------------------------------------------------------*/ + +void R::replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + SwigType *type = Getattr(parm, "type"); + replaceRClass(tm, type); +} + + +/* ----------------------------------------------------------------------- + * Called when SWIG wants to initialize this + * We initialize anythin we want here. + * Most importantly, tell SWIG where to find the files (e.g. r.swg) for this module. + * Use Swig_mark_arg() to tell SWIG that it is understood and not to + * throw an error. + * --------------------------------------------------------------*/ + +void R::main(int argc, char *argv[]) { + init(); + Preprocessor_define("SWIGR 1", 0); + SWIG_library_directory("r"); + SWIG_config_file("r.swg"); + debugMode = false; + copyStruct = true; + memoryProfile = false; + aggressiveGc = false; + inCPlusMode = false; + outputNamespaceInfo = false; + noInitializationCode = false; + + this->Argc = argc; + this->Argv = argv; + + allow_overloading();// can we support this? + + for(int i = 0; i < argc; i++) { + if(strcmp(argv[i], "-package") == 0) { + Swig_mark_arg(i); + i++; + Swig_mark_arg(i); + Rpackage = argv[i]; + } else if(strcmp(argv[i], "-dll") == 0) { + Swig_mark_arg(i); + i++; + Swig_mark_arg(i); + DllName = argv[i]; + } else if(strcmp(argv[i], "-help") == 0) { + showUsage(); + } else if(strcmp(argv[i], "-namespace") == 0) { + outputNamespaceInfo = true; + Swig_mark_arg(i); + } else if(!strcmp(argv[i], "-no-init-code")) { + noInitializationCode = true; + Swig_mark_arg(i); + } else if(!strcmp(argv[i], "-c++")) { + inCPlusMode = true; + Swig_mark_arg(i); + Printf(s_classes, "setClass('C++Reference', contains = 'ExternalReference')\n"); + } else if(!strcmp(argv[i], "-debug")) { + debugMode = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i],"-copystruct")) { + copyStruct = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nocopystruct")) { + copyStruct = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-memoryprof")) { + memoryProfile = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nomemoryprof")) { + memoryProfile = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-aggressivegc")) { + aggressiveGc = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-noaggressivegc")) { + aggressiveGc = false; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); + Swig_mark_arg(i); + Exit(EXIT_FAILURE); + } + + if (debugMode) { + Swig_typemap_search_debug_set(); + Swig_typemap_used_debug_set(); + Swig_typemap_register_debug_set(); + Swig_file_debug_set(); + } + /// copyToR copyToC functions. + + } +} + +/* ----------------------------------------------------------------------- + * Could make this work for String or File and then just store the resulting string + * rather than the collection of arguments and argc. + * ----------------------------------------------------------------------- */ +int R::outputCommandLineArguments(File *out) +{ + if(Argc < 1 || !Argv || !Argv[0]) + return(-1); + + Printf(out, "\n## Generated via the command line invocation:\n##\t"); + for(int i = 0; i < Argc ; i++) { + Printf(out, " %s", Argv[i]); + } + Printf(out, "\n\n\n"); + + return Argc; +} + + + +/* How SWIG instantiates an object from this module. + See swigmain.cxx */ +extern "C" +Language *swig_r(void) { + return new R(); +} + + + + +/* ----------------------------------------------------------------------- + * Needs to be reworked. + *----------------------------------------------------------------------- */ +String * R::processType(SwigType *t, Node *n, int *nargs) { + //XXX Need to handle typedefs, e.g. + // a type which is a typedef to a function pointer. + + SwigType *tmp = Getattr(n, "tdname"); + if (debugMode) + Printf(stdout, "processType %s (tdname = %s)(SwigType = %s)\n", Getattr(n, "name"), tmp, Copy(t)); + + SwigType *td = t; + if (expandTypedef(t) && + SwigType_istypedef(t)) { + SwigType *resolved = + SwigType_typedef_resolve_all(t); + if (expandTypedef(resolved)) { + td = Copy(resolved); + } + } + + if(!td) { + int count = 0; + String *b = getRTypeName(t, &count); + if(count && b && !Getattr(SClassDefs, b)) { + if (debugMode) + Printf(stdout, "<processType> Defining class %s\n", b); + + Printf(s_classes, "setClass('%s', contains = 'ExternalReference')\n", b); + Setattr(SClassDefs, b, b); + } + + } + + + if(td) + t = td; + + if(SwigType_isfunctionpointer(t)) { + if (debugMode) + Printf(stdout, + "<processType> Defining pointer handler %s\n", t); + + String *tmp = createFunctionPointerHandler(t, n, nargs); + return tmp; + } + + return NULL; +} + + +/* ----------------------------------------------------------------------- + * enumValue() + * This method will return a string with an enum value to use in from R when + * setting up an enum variable + * ------------------------------------------------------------------------ */ + +String *R::enumValue(Node *n) { + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + String *newsymname = 0; + + Node *parent = parentNode(n); + symname = Getattr(n, "sym:name"); + + // parent enumtype has namespace mangled in + String *etype = Getattr(parent, "enumtype"); + // we have to directly call the c wrapper function, as the + // R wrapper to the enum is designed to be used after the enum + // structures have been created on the R side. This means + // that we'll need to construct a .Call expression + + // change the type for variableWrapper + if (debugMode) { + Printf(stdout, "<enumValue> type set: %s\n", etype); + } + + Setattr(n, "type", etype); + + if (!getCurrentClass()) { + newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); + // Strange hack to change the name + Setattr(n, "name", Getattr(n, "value")); + Setattr(n, "sym:name", newsymname); + variableWrapper(n); + value = Swig_name_get(NSPACE_TODO, newsymname); + } else { + String *enumClassPrefix = getEnumClassPrefix(); + newsymname = Swig_name_member(0, enumClassPrefix, symname); + Setattr(n, "name", Getattr(n, "value")); + Setattr(n, "sym:name", newsymname); + variableWrapper(n); + value = Swig_name_get(NSPACE_TODO, newsymname); + } + value = Swig_name_wrapper(value); + Replace(value, "_wrap", "R_swig", DOH_REPLACE_FIRST); + + String *valuecall=NewString(""); + Printv(valuecall, ".Call('", value, "',FALSE, PACKAGE='", Rpackage, "')", NIL); + Delete(value); + return valuecall; +} |