
/* -----------------------------------------------------------------------------
 * 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;
}

/* -------------------------------------------------------------
 * The name the enum is registered under in the generated R code.
 * %rename of the enum is honoured by using sym:name for the final
 * name component, keeping any C++ scope (namespace or enclosing class).
 * --------------------------------------------------------------*/

static String *getEnumRClassName(Node *n) {
  String *symname = Getattr(n, "sym:name");
  String *scope = Swig_scopename_prefix(Getattr(n, "name"));
  String *qname = scope ? NewStringf("%s::%s", scope, symname) : Copy(symname);
  String *ename = getRClassName(qname);
  Delete(qname);
  Delete(scope);
  return ename;
}

/* -------------------------------------------------------------
 * 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\
\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);
  // Honour %rename of an enum: the mangled type uses the C++ enum name, but the
  // enum is registered in R under its renamed sym:name, so substitute it in.
  // enumLookup only matches a simple enum type, so reduce any pointer/reference
  // or qualified type to its base enum type first.
  SwigType *base = SwigType_base(type);
  Node *enumnode = Language::enumLookup(base);
  if (enumnode && Getattr(enumnode, "sym:name")) {
    String *orig = getRClassName(Getattr(enumnode, "name"));
    String *renamed = getEnumRClassName(enumnode);
    if (!Equal(orig, renamed)) {
      Replaceall(tmp, orig, renamed);
      Replaceall(tmp_base, orig, renamed);
      Replaceall(tmp_ref, orig, renamed);
    }
    Delete(orig);
    Delete(renamed);
  }
  Delete(base);
  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.
 *
 * TODO: Investigate generating function pointer code inline rather than in
 * a helper function. The generated code should then avoid some unnecessary
 * copying.
 * ------------------------------------------------------------------------ */

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");
  bool r_tmp_needed = false;

  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");
    SwigType *rpt = SwigType_typedef_resolve_all(tt);
    bool isVoidParm = Strcmp(rpt, "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(rpt) || SwigType_isrvalue_reference(rpt)) {
        Printf(f->code, "%s = (%s) &%s;\n", Getattr(p, "lname"), lstr, swig_parm_name);
      } else if (!isVoidParm) {
        if (cparse_cplusplus && SwigType_type(rpt) == T_USER)
          Printf(f->code, "%s = SWIG_STD_MOVE(*(&%s));\n", Getattr(p, "lname"), swig_parm_name);
        else
          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);
    }

    r_tmp_needed = true;
    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, ", ");
    }
    Delete(rpt);
  }

  Printf(f->def, ") {\n");

  if (r_tmp_needed)
    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.

  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;

    // Use sym:name so that %rename of the enum is honoured.
    ename = getEnumRClassName(n);
    if (debugMode) {
      Node *current_class = getCurrentClass();
      String *cl = NewString("");
      if (current_class) {
        cl = getEnumClassPrefix();
      }
      Printf(stdout, "enumDeclaration: %s, %s, %s, %s, %s\n", Getattr(n, "name"), symname, nspace, ename, cl);
    }
    // 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", "*sym: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 *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);
  }

  {
    // 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", symname, value);
    } else {
      enum_values = NewString("");
      Printf(enum_values, "\"%s\" = %s", symname, value);
    }

    Delete(value);
  }

  Swig_restore(n);
  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                    */
};
}  // namespace

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 = NewString(argv[i]);
    } else if (strcmp(argv[i], "-dll") == 0) {
      Swig_mark_arg(i);
      i++;
      Swig_mark_arg(i);
      DllName = NewString(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();
    }
  }
}

/* -----------------------------------------------------------------------
 * 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"));
    // Language::variableWrapper() adds the EnumClassPrefix for a scoped enum
    // outside of a class, so don't prefix sym:name here as well.
    if (!GetFlag(parent, "scopedenum"))
      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;
}
