/* -----------------------------------------------------------------------------
 * See the LICENSE file for information on copyright, usage and redistribution
 * of SWIG, and the README file for authors - http://www.swig.org/release.html.
 *
 * go.cxx
 *
 * Go language module for SWIG.
 * ----------------------------------------------------------------------------- */

#include "swigmod.h"
#include "cparse.h"
#include <ctype.h>

class GO:public Language {
  static const char *const usage;

  // Go package name.
  String *package;
  // SWIG module name.
  String *module;
  // Flag for generating gccgo output.
  bool gccgo_flag;
  // Prefix to use with gccgo.
  String *go_prefix;
  // Name of shared library to import.
  String *soname;
  // Size in bits of the C type "long".
  int long_type_size;
  // Size in bits of the Go type "int".  0 if not specified.
  int intgo_type_size;

  /* Output files */
  File *f_c_begin;
  File *f_go_begin;
  File *f_gc_begin;

  /* Output fragments */
  File *f_c_runtime;
  File *f_c_header;
  File *f_c_wrappers;
  File *f_c_init;
  File *f_c_directors;
  File *f_c_directors_h;
  File *f_go_runtime;
  File *f_go_header;
  File *f_go_wrappers;
  File *f_gc_runtime;
  File *f_gc_header;
  File *f_gc_wrappers;

  // True if we imported a module.
  bool saw_import;
  // If not NULL, name of import package being processed.
  String *imported_package;
  // Build interface methods while handling a class.  This is only
  // non-NULL when we are handling methods.
  String *interfaces;
  // The class node while handling a class.  This is only non-NULL
  // when we are handling methods.
  Node *class_node;
  // The class name while handling a class.  This is only non-NULL
  // when we are handling methods.  This is the name of the class as
  // SWIG sees it.
  String *class_name;
  // The receiver name while handling a class.  This is only non-NULL
  // when we are handling methods.  This is the name of the class
  // as run through goCPointerType.
  String *class_receiver;
  // A hash table of method names that we have seen when processing a
  // class.  This lets us detect base class methods that we don't want
  // to use.
  Hash *class_methods;
  // True when we are generating the wrapper functions for a variable.
  bool making_variable_wrappers;
  // True when working with a static member function.
  bool is_static_member_function;
  // A hash table of types that we have seen but which may not have
  // been defined.  The index is a SwigType.
  Hash *undefined_types;
  // A hash table of classes which were defined.  The index is a Go
  // type name.
  Hash *defined_types;

public:
  GO():package(NULL),
     module(NULL),
     gccgo_flag(false),
     go_prefix(NULL),
     soname(NULL),
     long_type_size(32),
     intgo_type_size(0),
     f_c_begin(NULL),
     f_go_begin(NULL),
     f_gc_begin(NULL),
     f_c_runtime(NULL),
     f_c_header(NULL),
     f_c_wrappers(NULL),
     f_c_init(NULL),
     f_c_directors(NULL),
     f_c_directors_h(NULL),
     f_go_runtime(NULL),
     f_go_header(NULL),
     f_go_wrappers(NULL),
     f_gc_runtime(NULL),
     f_gc_header(NULL),
     f_gc_wrappers(NULL),
     saw_import(false),
     imported_package(NULL),
     interfaces(NULL),
     class_node(NULL),
     class_name(NULL),
     class_receiver(NULL),
     class_methods(NULL),
     making_variable_wrappers(false),
     is_static_member_function(false),
     undefined_types(NULL),
     defined_types(NULL) {
    director_multiple_inheritance = 1;
    director_language = 1;
    director_prot_ctor_code = NewString("_swig_gopanic(\"accessing abstract class or protected constructor\");");
  }

private:
  /* ------------------------------------------------------------
   * main()
   * ------------------------------------------------------------ */
  virtual void main(int argc, char *argv[]) {

    SWIG_library_directory("go");
    bool display_help = false;

    // Process command line options.
    for (int i = 1; i < argc; i++) {
      if (argv[i]) {
	if (strcmp(argv[i], "-package") == 0) {
	  if (argv[i + 1]) {
	    package = NewString(argv[i + 1]);
	    Swig_mark_arg(i);
	    Swig_mark_arg(i + 1);
	    i++;
	  } else {
	    Swig_arg_error();
	  }
	} else if (strcmp(argv[i], "-gccgo") == 0) {
	  Swig_mark_arg(i);
	  gccgo_flag = true;
	} else if (strcmp(argv[i], "-go-prefix") == 0) {
	  if (argv[i + 1]) {
	    go_prefix = NewString(argv[i + 1]);
	    Swig_mark_arg(i);
	    Swig_mark_arg(i + 1);
	    i++;
	  } else {
	    Swig_arg_error();
	  }
	} else if (strcmp(argv[i], "-soname") == 0) {
	  if (argv[i + 1]) {
	    soname = NewString(argv[i + 1]);
	    Swig_mark_arg(i);
	    Swig_mark_arg(i + 1);
	    i++;
	  } else {
	    Swig_arg_error();
	  }
	} else if (strcmp(argv[i], "-longsize") == 0) {
	  if (argv[i + 1]) {
	    long_type_size = atoi(argv[i + 1]);
	    if (long_type_size != 32 && long_type_size != 64) {
	      Printf(stderr, "-longsize not 32 or 64\n");
	      Swig_arg_error();
	    }
	    Swig_mark_arg(i);
	    Swig_mark_arg(i + 1);
	    ++i;
	  } else {
	    Swig_arg_error();
	  }
	} else if (strcmp(argv[i], "-intgosize") == 0) {
	  if (argv[i + 1]) {
	    intgo_type_size = atoi(argv[i + 1]);
	    if (intgo_type_size != 32 && intgo_type_size != 64) {
	      Printf(stderr, "-intgosize not 32 or 64\n");
	      Swig_arg_error();
	    }
	    Swig_mark_arg(i);
	    Swig_mark_arg(i + 1);
	    ++i;
	  } else {
	    Swig_arg_error();
	  }
	} else if (strcmp(argv[i], "-help") == 0) {
	  display_help = true;
	  Printf(stdout, "%s\n", usage);
	}
      }
    }

    if (gccgo_flag && !go_prefix) {
      go_prefix = NewString("go");
    }

    // Add preprocessor symbol to parser.
    Preprocessor_define("SWIGGO 1", 0);

    if (gccgo_flag) {
      Preprocessor_define("SWIGGO_GCCGO 1", 0);
    }

    if (long_type_size == 32) {
      Preprocessor_define("SWIGGO_LONG_TYPE_SIZE 32", 0);
    } else {
      Preprocessor_define("SWIGGO_LONG_TYPE_SIZE 64", 0);
    }

    // This test may be removed in the future, when we can assume that
    // everybody has upgraded to Go 1.1.  The code below is prepared
    // for this test to simply be taken out.
    if (intgo_type_size == 0 && !display_help) {
      Printf(stderr, "SWIG -go: -intgosize option required but not specified\n");
      SWIG_exit(EXIT_FAILURE);
    }

    if (intgo_type_size == 32) {
      Preprocessor_define("SWIGGO_INTGO_SIZE 32", 0);
    } else if (intgo_type_size == 64) {
      Preprocessor_define("SWIGGO_INTGO_SIZE 64", 0);
    } else {
      Preprocessor_define("SWIGGO_INTGO_SIZE 0", 0);
    }

    // Add typemap definitions.
    SWIG_typemap_lang("go");
    SWIG_config_file("go.swg");

    allow_overloading();
  }

  /* ---------------------------------------------------------------------
   * top()
   *
   * For 6g/8g, we are going to create the following files:
   *
   * 1) A .c or .cxx file compiled with gcc.  This file will contain
   *    function wrappers.  Each wrapper will take a pointer to a
   *    struct holding the arguments, unpack them, and call the real
   *    function.
   *
   * 2) A .go file which defines the Go form of all types, and which
   *    defines Go function wrappers.  Each wrapper will call the C
   *    function wrapper in the second file.
   *
   * 3) A .c file compiled with 6c/8c.  This file will define
   *    Go-callable C function wrappers.  Each wrapper will use
   *    cgocall to call the function wrappers in the first file.
   *
   * When generating code for gccgo, we don't need the third file, and
   * the function wrappers in the first file have a different form.
   *
   * --------------------------------------------------------------------- */

  virtual int top(Node *n) {
    Node *optionsnode = Getattr(Getattr(n, "module"), "options");
    if (optionsnode) {
      if (Getattr(optionsnode, "directors")) {
	allow_directors();
      }
      if (Getattr(optionsnode, "dirprot")) {
	allow_dirprot();
      }
      allow_allprotected(GetFlag(optionsnode, "allprotected"));
    }

    module = Getattr(n, "name");
    if (!package) {
      package = Copy(module);
    }
    if (!soname) {
      soname = Copy(package);
      Append(soname, ".so");
    }

    // Get filenames.

    String *c_filename = Getattr(n, "outfile");
    String *c_filename_h = Getattr(n, "outfile_h");

    String *go_filename = NewString("");
    Printf(go_filename, "%s%s.go", SWIG_output_directory(), module);

    String *gc_filename = NULL;
    if (!gccgo_flag) {
      gc_filename = NewString("");
      Printf(gc_filename, "%s%s_gc.c", SWIG_output_directory(), module);
    }

    // Open files.

    f_c_begin = NewFile(c_filename, "w", SWIG_output_files());
    if (!f_c_begin) {
      FileErrorDisplay(c_filename);
      SWIG_exit(EXIT_FAILURE);
    }

    if (directorsEnabled()) {
      if (!c_filename_h) {
	Printf(stderr, "Unable to determine outfile_h\n");
	SWIG_exit(EXIT_FAILURE);
      }
      f_c_directors_h = NewFile(c_filename_h, "w", SWIG_output_files());
      if (!f_c_directors_h) {
	FileErrorDisplay(c_filename_h);
	SWIG_exit(EXIT_FAILURE);
      }
    }

    f_go_begin = NewFile(go_filename, "w", SWIG_output_files());
    if (!f_go_begin) {
      FileErrorDisplay(go_filename);
      SWIG_exit(EXIT_FAILURE);
    }

    if (!gccgo_flag) {
      f_gc_begin = NewFile(gc_filename, "w", SWIG_output_files());
      if (!f_gc_begin) {
	FileErrorDisplay(gc_filename);
	SWIG_exit(EXIT_FAILURE);
      }
    }

    f_c_runtime = NewString("");
    f_c_header = NewString("");
    f_c_wrappers = NewString("");
    f_c_init = NewString("");
    f_c_directors = NewString("");
    f_go_runtime = NewString("");
    f_go_header = NewString("");
    f_go_wrappers = NewString("");
    if (!gccgo_flag) {
      f_gc_runtime = NewString("");
      f_gc_header = NewString("");
      f_gc_wrappers = NewString("");
    }

    Swig_register_filebyname("begin", f_c_begin);
    Swig_register_filebyname("runtime", f_c_runtime);
    Swig_register_filebyname("header", f_c_header);
    Swig_register_filebyname("wrapper", f_c_wrappers);
    Swig_register_filebyname("init", f_c_init);
    Swig_register_filebyname("director", f_c_directors);
    Swig_register_filebyname("director_h", f_c_directors_h);
    Swig_register_filebyname("go_begin", f_go_begin);
    Swig_register_filebyname("go_runtime", f_go_runtime);
    Swig_register_filebyname("go_header", f_go_header);
    Swig_register_filebyname("go_wrapper", f_go_wrappers);
    if (!gccgo_flag) {
      Swig_register_filebyname("gc_begin", f_gc_begin);
      Swig_register_filebyname("gc_runtime", f_gc_runtime);
      Swig_register_filebyname("gc_header", f_gc_header);
      Swig_register_filebyname("gc_wrapper", f_gc_wrappers);
    }

    Swig_banner(f_c_begin);

    Printf(f_c_runtime, "#define SWIGMODULE %s\n", module);

    if (directorsEnabled()) {
      Printf(f_c_runtime, "#define SWIG_DIRECTORS\n");

      Swig_banner(f_c_directors_h);
      Printf(f_c_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module);
      Printf(f_c_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module);

      Printf(f_c_directors, "\n// C++ director class methods.\n");
      String *filename = Swig_file_filename(c_filename_h);
      Printf(f_c_directors, "#include \"%s\"\n\n", filename);
      Delete(filename);
    }

    Swig_banner(f_go_begin);

    if (!gccgo_flag) {
      Swig_banner(f_gc_begin);
      Printf(f_gc_begin, "\n/* This file should be compiled with 6c/8c.  */\n");
      Printf(f_gc_begin, "#pragma dynimport _ _ \"%s\"\n", soname);
    }

    // Output module initialization code.

    Printf(f_go_begin, "\npackage %s\n\n", package);

    Printf(f_go_runtime, "//extern %sSwigCgocall\n", module);
    Printf(f_go_runtime, "func SwigCgocall()\n");
    Printf(f_go_runtime, "//extern %sSwigCgocallDone\n", module);
    Printf(f_go_runtime, "func SwigCgocallDone()\n");
    Printf(f_go_runtime, "//extern %sSwigCgocallBack\n", module);
    Printf(f_go_runtime, "func SwigCgocallBack()\n");
    Printf(f_go_runtime, "//extern %sSwigCgocallBackDone\n", module);
    Printf(f_go_runtime, "func SwigCgocallBackDone()\n\n");

    // All the C++ wrappers should be extern "C".

    Printv(f_c_wrappers, "#ifdef __cplusplus\n", "extern \"C\" {\n", "#endif\n\n", NULL);

    // Set up the hash table for types not defined by SWIG.

    undefined_types = NewHash();
    defined_types = NewHash();

    // Emit code.

    Language::top(n);

    // Write out definitions for the types not defined by SWIG.

    Printv(f_go_wrappers, "\n", NULL);
    for (Iterator p = First(undefined_types); p.key; p = Next(p)) {
      String *ty = goType(NULL, p.key);
      if (!Getattr(defined_types, ty)) {
	String *cp = goCPointerType(p.key, false);
	if (!Getattr(defined_types, cp)) {
	  Printv(f_go_wrappers, "type ", cp, " uintptr\n", NULL);
	  Printv(f_go_wrappers, "type ", ty, " interface {\n", NULL);
	  Printv(f_go_wrappers, "\tSwigcptr() uintptr;\n", NULL);
	  Printv(f_go_wrappers, "}\n", NULL);
	  Printv(f_go_wrappers, "func (p ", cp, ") Swigcptr() uintptr {\n", NULL);
	  Printv(f_go_wrappers, "\treturn uintptr(p)\n", NULL);
	  Printv(f_go_wrappers, "}\n\n", NULL);
	}
	Delete(cp);
      }
      Delete(ty);
    }
    Delete(undefined_types);
    Delete(defined_types);

    /* Write and cleanup */

    Dump(f_c_header, f_c_runtime);

    if (directorsEnabled()) {
      Printf(f_c_directors_h, "#endif\n");
      Delete(f_c_directors_h);
      f_c_directors_h = NULL;

      Dump(f_c_directors, f_c_runtime);
      Delete(f_c_directors);
      f_c_directors = NULL;
    }

    // End the extern "C".
    Printv(f_c_wrappers, "#ifdef __cplusplus\n", "}\n", "#endif\n\n", NULL);

    Dump(f_c_runtime, f_c_begin);
    Dump(f_c_wrappers, f_c_begin);
    Dump(f_c_init, f_c_begin);
    Dump(f_go_header, f_go_begin);
    Dump(f_go_runtime, f_go_begin);
    Dump(f_go_wrappers, f_go_begin);
    if (!gccgo_flag) {
      Dump(f_gc_header, f_gc_begin);
      Dump(f_gc_runtime, f_gc_begin);
      Dump(f_gc_wrappers, f_gc_begin);
    }

    Delete(f_c_runtime);
    Delete(f_c_header);
    Delete(f_c_wrappers);
    Delete(f_c_init);
    Delete(f_go_runtime);
    Delete(f_go_header);
    Delete(f_go_wrappers);
    if (!gccgo_flag) {
      Delete(f_gc_runtime);
      Delete(f_gc_header);
      Delete(f_gc_wrappers);
    }

    Delete(f_c_begin);
    Delete(f_go_begin);
    if (!gccgo_flag) {
      Delete(f_gc_begin);
    }

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * importDirective()
   *
   * Handle a SWIG import statement by generating a Go import
   * statement.
   * ------------------------------------------------------------ */

  virtual int importDirective(Node *n) {
    String *hold_import = imported_package;
    String *modname = Getattr(n, "module");
    if (modname) {
      Printv(f_go_begin, "import \"", modname, "\"\n", NULL);
      imported_package = modname;
      saw_import = true;
    }
    int r = Language::importDirective(n);
    imported_package = hold_import;
    return r;
  }

  /* ----------------------------------------------------------------------
   * functionWrapper()
   *
   * Implement a function.
   * ---------------------------------------------------------------------- */

  virtual int functionWrapper(Node *n) {
    if (GetFlag(n, "feature:ignore")) {
      return SWIG_OK;
    }

    // We don't need explicit calls.
    if (GetFlag(n, "explicitcall")) {
      return SWIG_OK;
    }

    String *name = Getattr(n, "sym:name");
    String *nodetype = Getattr(n, "nodeType");
    bool is_static = is_static_member_function || isStatic(n);
    bool is_friend = isFriend(n);
    bool is_ctor_dtor = false;

    SwigType *result = Getattr(n, "type");

    // For some reason SWIG changs the "type" value during the call to
    // functionWrapper.  We need to remember the type for possible
    // overload processing.
    Setattr(n, "go:type", Copy(result));

    String *go_name;

    String *r1 = NULL;
    if (making_variable_wrappers) {
      // Change the name of the variable setter and getter functions
      // to be more Go like.

      bool is_set = Strcmp(Char(name) + Len(name) - 4, "_set") == 0;
      assert(is_set || Strcmp(Char(name) + Len(name) - 4, "_get") == 0);

      // Start with Set or Get.
      go_name = NewString(is_set ? "Set" : "Get");

      // If this is a static variable, put in the class name,
      // capitalized.
      if (is_static && class_name) {
	String *ccn = exportedName(class_name);
	Append(go_name, ccn);
	Delete(ccn);
      }

      // Add the rest of the name, capitalized, dropping the _set or
      // _get.
      String *c1 = removeClassname(name);
      String *c2 = exportedName(c1);
      char *p = Char(c2);
      int len = Len(p);
      for (int i = 0; i < len - 4; ++i) {
	Putc(p[i], go_name);
      }
      Delete(c2);
      Delete(c1);

      if (!checkIgnoredParameters(n, go_name)) {
	Delete(go_name);
	return SWIG_NOWRAP;
      }
    } else if (Cmp(nodetype, "constructor") == 0) {
      is_ctor_dtor = true;

      // Change the name of a constructor to be more Go like.  Change
      // new_ to New, and capitalize the class name.
      assert(Strncmp(name, "new_", 4) == 0);
      String *c1 = NewString(Char(name) + 4);
      String *c2 = exportedName(c1);
      go_name = NewString("New");
      Append(go_name, c2);
      Delete(c2);
      Delete(c1);

      if (Swig_methodclass(n) && Swig_directorclass(n)
	  && Strcmp(Char(Getattr(n, "wrap:action")), director_prot_ctor_code) != 0) {
	// The core SWIG code skips the first parameter when
	// generating the $nondirector_new string.  Recreate the
	// action in this case.  But don't it if we are using the
	// special code for an abstract class.
	String *call = Swig_cppconstructor_call(getClassType(),
						Getattr(n, "parms"));
	SwigType *type = Copy(getClassType());
	SwigType_add_pointer(type);
	String *cres = Swig_cresult(type, Swig_cresult_name(), call);
	Setattr(n, "wrap:action", cres);
      }
    } else if (Cmp(nodetype, "destructor") == 0) {
      // No need to emit protected destructors.
      if (!is_public(n)) {
	return SWIG_OK;
      }

      is_ctor_dtor = true;

      // Change the name of a destructor to be more Go like.  Change
      // delete_ to Delete and capitalize the class name.
      assert(Strncmp(name, "delete_", 7) == 0);
      String *c1 = NewString(Char(name) + 7);
      String *c2 = exportedName(c1);
      go_name = NewString("Delete");
      Append(go_name, c2);
      Delete(c2);
      Delete(c1);

      result = NewString("void");
      r1 = result;
    } else {
      if (!checkFunctionVisibility(n, NULL)) {
	return SWIG_OK;
      }

      go_name = buildGoName(name, is_static, is_friend);

      if (!checkIgnoredParameters(n, go_name)) {
	Delete(go_name);
	return SWIG_NOWRAP;
      }
    }

    String *overname = NULL;
    if (Getattr(n, "sym:overloaded")) {
      overname = Getattr(n, "sym:overname");
    } else {
      String *scope;
      if (!class_name || is_static || is_ctor_dtor) {
	scope = NULL;
      } else {
	scope = NewString("swiggoscope.");
	Append(scope, class_name);
      }
      if (!checkNameConflict(go_name, n, scope)) {
	Delete(go_name);
	return SWIG_NOWRAP;
      }
    }

    String *wname = Swig_name_wrapper(name);
    if (overname) {
      Append(wname, overname);
    }
    Setattr(n, "wrap:name", wname);

    ParmList *parms = Getattr(n, "parms");
    Setattr(n, "wrap:parms", parms);

    int r = makeWrappers(n, name, go_name, overname, wname, NULL, parms, result, is_static);
    if (r != SWIG_OK) {
      return r;
    }

    if (Getattr(n, "sym:overloaded") && !Getattr(n, "sym:nextSibling")) {
      String *scope ;
      if (!class_name || is_static || is_ctor_dtor) {
	scope = NULL;
      } else {
	scope = NewString("swiggoscope.");
	Append(scope, class_name);
      }
      if (!checkNameConflict(go_name, n, scope)) {
	Delete(go_name);
	return SWIG_NOWRAP;
      }

      String *receiver = class_receiver;
      if (is_static || is_ctor_dtor) {
	receiver = NULL;
      }
      r = makeDispatchFunction(n, go_name, receiver, is_static, NULL, false);
      if (r != SWIG_OK) {
	return r;
      }
    }

    Delete(wname);
    Delete(go_name);
    Delete(r1);

    return SWIG_OK;
  }

  /* ----------------------------------------------------------------------
   * staticmemberfunctionHandler()
   *
   * For some reason the language code removes the "storage" attribute
   * for a static function before calling functionWrapper, which means
   * that we have no way of knowing whether a function is static or
   * not.  That makes no sense in the Go context.  Here we note that a
   * function is static.
   * ---------------------------------------------------------------------- */

  int staticmemberfunctionHandler(Node *n) {
    assert(!is_static_member_function);
    is_static_member_function = true;
    int r = Language::staticmemberfunctionHandler(n);
    is_static_member_function = false;
    return r;
  }

  /* ----------------------------------------------------------------------
   * makeWrappers()
   *
   * Write out the various function wrappers.
   * n: The function we are emitting.
   * name: The function name.
   * go_name: The name of the function in Go.
   * overname: The overload string for overloaded function.
   * wname: The SWIG wrapped name--the name of the C function.
   * base: A list of the names of base classes, in the case where this
   *       is is a vritual method not defined in the current class.
   * parms: The parameters.
   * result: The result type.
   * is_static: Whether this is a static method or member.
   * ---------------------------------------------------------------------- */

  int makeWrappers(Node *n, String *name, String *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static) {

    assert(result);

    bool needs_wrapper;
    int r = goFunctionWrapper(n, name, go_name, overname, wname, base, parms, result, is_static, &needs_wrapper);
    if (r != SWIG_OK) {
      return r;
    }

    if (!gccgo_flag) {
      r = gcFunctionWrapper(n, name, go_name, overname, wname, parms, result, is_static, needs_wrapper);
      if (r != SWIG_OK) {
	return r;
      }
      r = gccFunctionWrapper(n, base, wname, parms, result);
      if (r != SWIG_OK) {
	return r;
      }
    } else {
      r = gccgoFunctionWrapper(n, base, wname, parms, result);
      if (r != SWIG_OK) {
	return r;
      }
    }

    if (class_methods) {
      Setattr(class_methods, Getattr(n, "name"), NewString(""));
    }

    return SWIG_OK;
  }

  /* ----------------------------------------------------------------------
   * goFunctionWrapper()
   *
   * Write out a function wrapper in Go.  When not implementing a
   * method, the actual code is all in C; here we just declare the C
   * function.  When implementing a method, we have to call the C
   * function, because it will have a different name.  If base is not
   * NULL, then we are being called to forward a virtual method to a
   * base class.
   * ---------------------------------------------------------------------- */

  int goFunctionWrapper(Node *n, String *name, String *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static, bool *p_needs_wrapper) {
    Wrapper *dummy = NewWrapper();
    emit_attach_parmmaps(parms, dummy);
    Swig_typemap_attach_parms("default", parms, dummy);
    Swig_typemap_attach_parms("gotype", parms, dummy);
    int parm_count = emit_num_arguments(parms);
    int required_count = emit_num_required(parms);

    String *receiver = class_receiver;
    if (receiver && is_static) {
      receiver = NULL;
    }

    String *nodetype = Getattr(n, "nodeType");
    bool is_constructor = Cmp(nodetype, "constructor") == 0;
    bool is_destructor = Cmp(nodetype, "destructor") == 0;
    if (is_constructor || is_destructor) {
      assert(class_receiver);
      assert(!base);
      receiver = NULL;
    }

    bool add_to_interface = (interfaces && !is_constructor && !is_destructor && !is_static && !overname && checkFunctionVisibility(n, NULL));

    bool needs_wrapper = (gccgo_flag || receiver || is_constructor || is_destructor || parm_count > required_count);

    // See whether any of the function parameters are represented by
    // interface values When calling the C++ code, we need to convert
    // back to a uintptr.
    if (!needs_wrapper) {
      Parm *p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	String *ty = Getattr(p, "type");
	if (goTypeIsInterface(p, ty)) {
	  needs_wrapper = true;
	  break;
	}
	p = nextParm(p);
      }
    }
    if (goTypeIsInterface(n, result)) {
      needs_wrapper = true;
    }

    *p_needs_wrapper = needs_wrapper;

    // If this is a method, first declare the C function we will call.
    // If we do not need a wrapper, then we will only be writing a
    // declaration.
    String *wrapper_name = NULL;
    if (needs_wrapper) {
      wrapper_name = buildGoWrapperName(name, overname);

      if (gccgo_flag) {
	Printv(f_go_wrappers, "//extern ", go_prefix, "_", wname, "\n", NULL);
      }

      Printv(f_go_wrappers, "func ", wrapper_name, "(", NULL);
      if (parm_count > required_count) {
	Printv(f_go_wrappers, "int", NULL);
      }
      Parm *p = getParm(parms);
      Swig_cparm_name(p, 0);
      int i = 0;
      if (is_destructor) {
	if (parm_count > required_count) {
	  Printv(f_go_wrappers, ", ", NULL);
	}
	Printv(f_go_wrappers, "uintptr", NULL);
	++i;
	p = nextParm(p);
      } else if (receiver && (base || !is_constructor)) {
	if (parm_count > required_count) {
	  Printv(f_go_wrappers, ", ", NULL);
	}
	Printv(f_go_wrappers, receiver, NULL);
	if (!base) {
	  ++i;
	  p = nextParm(p);
	}
      }
      for (; i < parm_count; ++i) {
	p = getParm(p);
	// Give the parameter a name we will use below.
	Swig_cparm_name(p, i);
	if (i > 0 || (base && receiver) || parm_count > required_count) {
	  Printv(f_go_wrappers, ", ", NULL);
	}
	String *tm = goWrapperType(p, Getattr(p, "type"), false);
	Printv(f_go_wrappers, tm, NULL);
	Delete(tm);
	p = nextParm(p);
      }
      Printv(f_go_wrappers, ")", NULL);
      if (is_constructor) {
	Printv(f_go_wrappers, " ", class_receiver, NULL);
      } else {
	if (SwigType_type(result) != T_VOID) {
	  String *tm = goWrapperType(n, result, true);
	  Printv(f_go_wrappers, " ", tm, NULL);
	  Delete(tm);
	}
      }

      Printv(f_go_wrappers, "\n\n", NULL);
    }

    // Start defining the Go function.

    if (!needs_wrapper && gccgo_flag) {
      Printv(f_go_wrappers, "//extern ", go_prefix, "_", wname, "\n", NULL);
    }

    Printv(f_go_wrappers, "func ", NULL);

    Parm *p = parms;
    int pi = 0;

    // Add the receiver if this is a method.
    if (receiver) {
      Printv(f_go_wrappers, "(", NULL);
      if (base && receiver) {
	Printv(f_go_wrappers, "_swig_base", NULL);
      } else {
	Printv(f_go_wrappers, Getattr(p, "lname"), NULL);
	p = nextParm(p);
	++pi;
      }
      Printv(f_go_wrappers, " ", receiver, ") ", NULL);
    }

    Printv(f_go_wrappers, go_name, NULL);
    if (overname) {
      Printv(f_go_wrappers, overname, NULL);
    }
    Printv(f_go_wrappers, "(", NULL);

    // If we are doing methods, add this function to the interface.
    if (add_to_interface) {
      Printv(interfaces, "\t", go_name, "(", NULL);
    }

    // Write out the parameters to both the function definition and
    // the interface.

    String *parm_print = NewString("");

    for (; pi < parm_count; ++pi) {
      p = getParm(p);
      if (pi == 0 && is_destructor) {
	String *cl = exportedName(class_name);
	Printv(parm_print, Getattr(p, "lname"), " ", cl, NULL);
	Delete(cl);
      } else {
	if (pi > (receiver && !base ? 1 : 0)) {
	  Printv(parm_print, ", ", NULL);
	}
	if (pi >= required_count) {
	  Printv(parm_print, "_swig_args ...interface{}", NULL);
	  break;
	}
	if (needs_wrapper) {
	  Printv(parm_print, Getattr(p, "lname"), " ", NULL);
	}
	String *tm = goType(p, Getattr(p, "type"));
	Printv(parm_print, tm, NULL);
	Delete(tm);
      }
      p = nextParm(p);
    }

    Printv(parm_print, ")", NULL);

    // Write out the result type.
    if (is_constructor) {
      String *cl = exportedName(class_name);
      Printv(parm_print, " ", cl, NULL);
      Delete(cl);
    } else {
      if (SwigType_type(result) != T_VOID) {
	String *tm = goType(n, result);
	Printv(parm_print, " ", tm, NULL);
	Delete(tm);
      }
    }

    Printv(f_go_wrappers, parm_print, NULL);
    if (add_to_interface) {
      Printv(interfaces, parm_print, "\n", NULL);
    }

    // If this is a wrapper, we need to actually call the C function.
    if (needs_wrapper) {
      Printv(f_go_wrappers, " {\n", NULL);

      if (parm_count > required_count) {
	Parm *p = parms;
	int i;
	for (i = 0; i < required_count; ++i) {
	  p = getParm(p);
	  p = nextParm(p);
	}
	for (; i < parm_count; ++i) {
	  p = getParm(p);
	  String *tm = goType(p, Getattr(p, "type"));
	  Printv(f_go_wrappers, "\tvar ", Getattr(p, "lname"), " ", tm, "\n", NULL);
	  Printf(f_go_wrappers, "\tif len(_swig_args) > %d {\n", i - required_count);
	  Printf(f_go_wrappers, "\t\t%s = _swig_args[%d].(%s)\n", Getattr(p, "lname"), i - required_count, tm);
	  Printv(f_go_wrappers, "\t}\n", NULL);
	  Delete(tm);
	  p = nextParm(p);
	}
      }

      if (gccgo_flag) {
	if (!is_constructor) {
	  Printv(f_go_wrappers, "\tdefer SwigCgocallDone()\n", NULL);
	  Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL);
	} else {
	  // For a constructor the wrapper function will return a
	  // uintptr but we will return an interface.  We want to
	  // convert the uintptr to the interface after calling
	  // SwigCgocallDone, so that we don't try to allocate memory
	  // while the Go scheduler can't see us.
	  Printv(f_go_wrappers, "\tvar done bool\n", NULL);
	  Printv(f_go_wrappers, "\tdefer func() {\n", NULL);
	  Printv(f_go_wrappers, "\t\tif !done {\n", NULL);
	  Printv(f_go_wrappers, "\t\t\tSwigCgocallDone()\n", NULL);
	  Printv(f_go_wrappers, "\t\t}\n", NULL);
	  Printv(f_go_wrappers, "\t}()\n", NULL);
	  Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL);
	}
      }

      Printv(f_go_wrappers, "\t", NULL);
      if (SwigType_type(result) != T_VOID) {
	if (gccgo_flag && is_constructor) {
	  Printv(f_go_wrappers, "swig_r := ", NULL);
	} else {
	  Printv(f_go_wrappers, "return ", NULL);
	}
      }

      Printv(f_go_wrappers, wrapper_name, "(", NULL);

      if (parm_count > required_count) {
	Printv(f_go_wrappers, "len(_swig_args)", NULL);
      }

      if (base && receiver) {
	if (parm_count > required_count) {
	  Printv(f_go_wrappers, ", ", NULL);
	}
	Printv(f_go_wrappers, "_swig_base", NULL);
      }

      Parm *p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	if (i > 0 || (base && receiver)
	    || parm_count > required_count) {
	  Printv(f_go_wrappers, ", ", NULL);
	}
	Printv(f_go_wrappers, Getattr(p, "lname"), NULL);

	// If this is a destructor, then the C function expects the
	// C++ value, and we have the interface.  We need to get the
	// C++ value.  The same is true for a type represented as an
	// interface.
	if ((i == 0 && is_destructor) || ((i > 0 || !receiver || base || is_constructor) && goTypeIsInterface(p, Getattr(p, "type")))) {
	  Printv(f_go_wrappers, ".Swigcptr()", NULL);
	}

	p = nextParm(p);
      }
      Printv(f_go_wrappers, ")\n", NULL);

      if (gccgo_flag && is_constructor) {
	Printv(f_go_wrappers, "\tSwigCgocallDone()\n", NULL);
	Printv(f_go_wrappers, "\tdone = true\n", NULL);
	Printv(f_go_wrappers, "\treturn swig_r\n", NULL);
      }

      Printv(f_go_wrappers, "}\n", NULL);
    }

    Printv(f_go_wrappers, "\n", NULL);

    Delete(wrapper_name);
    DelWrapper(dummy);

    return SWIG_OK;
  }

  /* ----------------------------------------------------------------------
   * gcFunctionWrapper()
   *
   * This is used for 6g/8g, not for gccgo.  Write out the function
   * wrapper which will be compiled with 6c/8c.
   * ---------------------------------------------------------------------- */

  int gcFunctionWrapper(Node *n, String *name, String *go_name, String *overname, String *wname, ParmList *parms, SwigType *result, bool is_static, bool needs_wrapper) {
    Wrapper *f = NewWrapper();

    Printv(f->def, "#pragma dynimport ", wname, " ", wname, " \"\"\n", NULL);
    Printv(f->def, "extern void (*", wname, ")(void*);\n", NULL);
    Printv(f->def, "static void (*x", wname, ")(void*) = ", wname, ";\n", NULL);
    Printv(f->def, "\n", NULL);
    Printv(f->def, "void\n", NULL);

    Wrapper *dummy = NewWrapper();
    emit_attach_parmmaps(parms, dummy);
    Swig_typemap_attach_parms("default", parms, dummy);
    Swig_typemap_attach_parms("gosize", parms, dummy);
    int parm_count = emit_num_arguments(parms);
    int required_count = emit_num_required(parms);

    String *parm_size = NewString("");

    if (parm_count > required_count) {
      Append(parm_size, "SWIG_PARM_SIZE");
    }

    if (class_receiver && !is_static) {
      if (Len(parm_size) > 0) {
	Append(parm_size, " + ");
      }
      Append(parm_size, "SWIG_PARM_SIZE");
    }

    Parm *p = parms;
    for (int i = 0; i < parm_count; ++i) {
      p = getParm(p);
      addGcTypeSize(p, Getattr(p, "type"), parm_size);
      p = nextParm(p);
    }

    if (SwigType_type(result) != T_VOID) {
      addGcTypeSize(n, result, parm_size);
    }

    if (Len(parm_size) == 0) {
      Append(parm_size, "1");
    }

    String *fn_name;
    if (!needs_wrapper) {
      fn_name = Copy(go_name);
      if (overname) {
	Append(fn_name, overname);
      }
    } else {
      fn_name = buildGoWrapperName(name, overname);
    }

    // \xc2\xb7 is UTF-8 for U+00B7 which is Unicode 'Middle Dot'
    Printv(f->def, "\xc2\xb7", fn_name, "(struct { uint8 x[", parm_size, "];} p)", NULL);

    Delete(fn_name);
    Delete(parm_size);

    Printv(f->code, "{\n", NULL);
    Printv(f->code, "\truntime\xc2\xb7" "cgocall(x", wname, ", &p);\n", NULL);
    Printv(f->code, "}\n", NULL);
    Printv(f->code, "\n", NULL);

    Wrapper_print(f, f_gc_wrappers);

    DelWrapper(f);
    DelWrapper(dummy);

    return SWIG_OK;
  }

  /* ----------------------------------------------------------------------
   * getGcTypeSize()
   *
   * Return the size to use when passing a type from 6g/8g to 6c/8c.
   * ---------------------------------------------------------------------- */

  String *addGcTypeSize(Node *n, SwigType *type, String *orig) {
    if (Len(orig) > 0) {
      Append(orig, " + ");
    }

    String *go = goType(n, type);
    if (Cmp(go, "string") == 0) {
      // A string has a pointer and a length.
      Append(orig, "(2 * SWIG_PARM_SIZE)");
    } else if (Strncmp(go, "[]", 2) == 0) {
      // A slice has a pointer, a length, and a capacity.
      Append(orig, "(3 * SWIG_PARM_SIZE)");
    } else if (Strcmp(go, "float64") == 0) {
      Append(orig, "8");
    } else if (Strcmp(go, "complex64") == 0) {
      Append(orig, "8");
    } else if (Strcmp(go, "complex128") == 0) {
      Append(orig, "16");
    } else {
      Append(orig, "SWIG_PARM_SIZE");
    }

    return orig;
  }

  /* ----------------------------------------------------------------------
   * gccFunctionWrapper()
   *
   * This is used for 6g/8g, not for gccgo.  Write out the function
   * wrapper which will be compiled with gcc.  If the base parameter
   * is not NULL, this is calls the base class method rather than
   * executing the SWIG wrapper code.
   * ---------------------------------------------------------------------- */

  int gccFunctionWrapper(Node *n, List *base, String *wname, ParmList *parms, SwigType *result) {
    Wrapper *f = NewWrapper();

    Swig_save("gccFunctionWrapper", n, "parms", NULL);

    Parm *base_parm = NULL;
    if (base && !isStatic(n)) {
      SwigType *base_type = Copy(getClassType());
      SwigType_add_pointer(base_type);
      base_parm = NewParm(base_type, NewString("arg1"), n);
      set_nextSibling(base_parm, parms);
      parms = base_parm;
    }

    emit_parameter_variables(parms, f);
    emit_attach_parmmaps(parms, f);
    int parm_count = emit_num_arguments(parms);
    int required_count = emit_num_required(parms);

    emit_return_variable(n, result, f);

    // Start the function definition.

    Printv(f->def, "void\n", wname, "(void *swig_v)\n", "{\n", NULL);

    // The single function parameter is a pointer to the real argument
    // values.  Define the structure that it points to.

    Printv(f->code, "\tstruct swigargs {\n", NULL);

    if (parm_count > required_count) {
      Printv(f->code, "\t\tintgo _swig_optargc;\n", NULL);
    }

    Parm *p = parms;
    for (int i = 0; i < parm_count; ++i) {
      p = getParm(p);
      String *ln = Getattr(p, "lname");
      SwigType *pt = Getattr(p, "type");
      String *ct = gcCTypeForGoValue(p, pt, ln);
      Printv(f->code, "\t\t\t", ct, ";\n", NULL);
      Delete(ct);
      p = nextParm(p);
    }
    if (SwigType_type(result) != T_VOID) {
      Printv(f->code, "\t\tlong : 0;\n", NULL);
      String *ln = NewString(Swig_cresult_name());
      String *ct = gcCTypeForGoValue(n, result, ln);
      Delete(ln);
      Printv(f->code, "\t\t", ct, ";\n", NULL);
      Delete(ct);
    }
    Printv(f->code, "\t} *swig_a = (struct swigargs *) swig_v;\n", NULL);

    Printv(f->code, "\n", NULL);

    // Copy the input arguments out of the structure into the
    // parameter variables.

    p = parms;
    for (int i = 0; i < parm_count; ++i) {
      p = getParm(p);

      String *tm = Getattr(p, "tmap:in");
      if (!tm) {
	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument\n", SwigType_str(Getattr(p, "type"), 0));
      } else {
	String *ln = Getattr(p, "lname");
	String *input = NewString("");
	Printv(input, "swig_a->", ln, NULL);
	Replaceall(tm, "$input", input);
	Setattr(p, "emit:input", input);
	if (i < required_count) {
	  Printv(f->code, "\t", tm, "\n", NULL);
	} else {
	  Printf(f->code, "\tif (swig_a->_swig_optargc > %d) {\n", i - required_count);
	  Printv(f->code, "\t\t", tm, "\n", NULL);
	  Printv(f->code, "\t}\n", NULL);
	}
      }
      p = nextParm(p);
    }

    Printv(f->code, "\n", NULL);

    // Do the real work of the function.

    checkConstraints(parms, f);

    emitGoAction(n, base, parms, result, f);

    argout(parms, f);

    cleanupFunction(n, f, parms);

    Printv(f->code, "}\n", NULL);

    Wrapper_print(f, f_c_wrappers);

    Swig_restore(n);

    DelWrapper(f);
    Delete(base_parm);

    return SWIG_OK;
  }

  /* ----------------------------------------------------------------------
   * gccgoFunctionWrapper()
   *
   * This is used for gccgo, not 6g/8g.  Write out the function
   * wrapper which will be compiled with gcc.  If the base parameter
   * is not NULL, this is calls the base class method rather than
   * executing the SWIG wrapper code.
   * ---------------------------------------------------------------------- */

  int gccgoFunctionWrapper(Node *n, List *base, String *wname, ParmList *parms, SwigType *result) {
    Wrapper *f = NewWrapper();

    Swig_save("gccgoFunctionWrapper", n, "parms", NULL);

    Parm *base_parm = NULL;
    if (base && !isStatic(n)) {
      SwigType *base_type = Copy(getClassType());
      SwigType_add_pointer(base_type);
      base_parm = NewParm(base_type, NewString("arg1"), n);
      set_nextSibling(base_parm, parms);
      parms = base_parm;
    }

    emit_parameter_variables(parms, f);
    emit_attach_parmmaps(parms, f);
    int parm_count = emit_num_arguments(parms);
    int required_count = emit_num_required(parms);

    emit_return_variable(n, result, f);

    // Start the function definition.

    String *fnname = NewString("");
    Printv(fnname, go_prefix, "_", wname, "(", NULL);

    if (parm_count > required_count) {
      Printv(fnname, "intgo _swig_optargc", NULL);
    }

    Parm *p = parms;
    for (int i = 0; i < parm_count; ++i) {
      p = getParm(p);
      SwigType *pt = Copy(Getattr(p, "type"));
      if (SwigType_isarray(pt)) {
	SwigType_del_array(pt);
	SwigType_add_pointer(pt);
      }
      String *pn = NewString("g");
      Append(pn, Getattr(p, "lname"));
      String *ct = gccgoCTypeForGoValue(p, pt, pn);
      if (i > 0 || parm_count > required_count) {
	Printv(fnname, ", ", NULL);
      }
      Printv(fnname, ct, NULL);
      Delete(ct);
      Delete(pn);
      Delete(pt);
      p = nextParm(p);
    }

    Printv(fnname, ")", NULL);

    if (SwigType_type(result) == T_VOID) {
      Printv(f->def, "void ", fnname, NULL);
    } else {
      String *ct = gccgoCTypeForGoValue(n, result, fnname);
      Printv(f->def, ct, NULL);
      Delete(ct);
    }

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

    Delete(fnname);

    if (SwigType_type(result) != T_VOID) {
      String *ln = NewString("go_result");
      String *ct = gccgoCTypeForGoValue(n, result, ln);
      Wrapper_add_local(f, "go_result", ct);
      Delete(ct);
      Delete(ln);
    }

    // Copy the parameters into the variables which hold their values,
    // applying appropriate transformations.

    p = parms;
    for (int i = 0; i < parm_count; ++i) {
      p = getParm(p);

      String *tm = Getattr(p, "tmap:in");
      if (!tm) {
	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number,
		     "Unable to use type %s as a function argument\n", SwigType_str(Getattr(p, "type"), 0));
      } else {
	String *ln = Getattr(p, "lname");
	String *pn = NewString("g");
	Append(pn, ln);
	Replaceall(tm, "$input", pn);
	Setattr(p, "emit:input", pn);
	if (i < required_count) {
	  Printv(f->code, "  ", tm, "\n", NULL);
	} else {
	  Printf(f->code, "  if (_swig_optargc > %d) {\n", i - required_count);
	  Printv(f->code, "    ", tm, "\n", NULL);
	  Printv(f->code, "  }\n", NULL);
	}
      }

      p = nextParm(p);
    }

    Printv(f->code, "\n", NULL);

    // Do the real work of the function.

    checkConstraints(parms, f);

    emitGoAction(n, base, parms, result, f);

    argout(parms, f);

    cleanupFunction(n, f, parms);

    if (SwigType_type(result) != T_VOID) {
      Printv(f->code, "  return go_result;\n", NULL);
    }

    Printv(f->code, "}\n", NULL);

    Wrapper_print(f, f_c_wrappers);

    Swig_restore(n);

    DelWrapper(f);
    Delete(base_parm);

    return SWIG_OK;
  }

  /* -----------------------------------------------------------------------
   * checkConstraints()
   *
   * Check parameter constraints if any.  This is used for the C/C++
   * function.  This assumes that each parameter has an "emit:input"
   * property with the name to use to refer to that parameter.
   * ----------------------------------------------------------------------- */

  void checkConstraints(ParmList *parms, Wrapper *f) {
    Parm *p = parms;
    while (p) {
      String *tm = Getattr(p, "tmap:check");
      if (!tm) {
	p = nextSibling(p);
      } else {
	Replaceall(tm, "$input", Getattr(p, "emit:input"));
	Printv(f->code, tm, "\n\n", NULL);
	p = Getattr(p, "tmap:check:next");
      }
    }
  }

  /* -----------------------------------------------------------------------
   * getGoAction()
   *
   * Get the action of the function.  This is used for C/C++ function.
   * ----------------------------------------------------------------------- */

  void emitGoAction(Node *n, List *base, ParmList *parms, SwigType *result, Wrapper *f) {
    String *actioncode;
    if (!base || isStatic(n)) {
      Swig_director_emit_dynamic_cast(n, f);
      actioncode = emit_action(n);
    } else {
      // Call the base class method.
      actioncode = NewString("");

      String *current = NewString("");
      if (!gccgo_flag) {
	Printv(current, "swig_a->", NULL);
      }
      Printv(current, Getattr(parms, "lname"), NULL);

      int vc = 0;
      for (Iterator bi = First(base); bi.item; bi = Next(bi)) {
	Printf(actioncode, "  %s *swig_b%d = (%s *)%s;\n", bi.item, vc, bi.item, current);
	Delete(current);
	current = NewString("");
	Printf(current, "swig_b%d", vc);
	++vc;
      }

      String *code = Copy(Getattr(n, "wrap:action"));
      Replaceall(code, Getattr(parms, "lname"), current);
      Printv(actioncode, code, "\n", NULL);
    }

    Swig_save("emitGoAction", n, "type", "tmap:out", NULL);

    Setattr(n, "type", result);

    String *tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode);
    if (!tm) {
      Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s\n", SwigType_str(result, 0));
    } else {
      if (!gccgo_flag) {
	static const String *swig_a_result = NewStringf("swig_a->%s", Swig_cresult_name());
	Replaceall(tm, "$result", swig_a_result);
      } else {
	Replaceall(tm, "$result", "go_result");
      }
      if (GetFlag(n, "feature:new")) {
	Replaceall(tm, "$owner", "1");
      } else {
	Replaceall(tm, "$owner", "0");
      }
      Printv(f->code, tm, "\n", NULL);
      Delete(tm);
    }

    Swig_restore(n);
  }

  /* -----------------------------------------------------------------------
   * argout()
   *
   * Handle argument output code if any.  This is used for the C/C++
   * function.  This assumes that each parameter has an "emit:input"
   * property with the name to use to refer to that parameter.
   * ----------------------------------------------------------------------- */

  void argout(ParmList *parms, Wrapper *f) {
    Parm *p = parms;
    while (p) {
      String *tm = Getattr(p, "tmap:argout");
      if (!tm) {
	p = nextSibling(p);
      } else {
	Replaceall(tm, "$result", Swig_cresult_name());
	Replaceall(tm, "$input", Getattr(p, "emit:input"));
	Printv(f->code, tm, "\n", NULL);
	p = Getattr(p, "tmap:argout:next");
      }
    }
  }

  /* -----------------------------------------------------------------------
   * freearg()
   *
   * Handle argument cleanup code if any.  This is used for the C/C++
   * function.  This assumes that each parameter has an "emit:input"
   * property with the name to use to refer to that parameter.
   * ----------------------------------------------------------------------- */

  String *freearg(ParmList *parms) {
    String *ret = NewString("");
    Parm *p = parms;
    while (p) {
      String *tm = Getattr(p, "tmap:freearg");
      if (!tm) {
	p = nextSibling(p);
      } else {
	Replaceall(tm, "$input", Getattr(p, "emit:input"));
	Printv(ret, tm, "\n", NULL);
	p = Getattr(p, "tmap:freearg:next");
      }
    }
    return ret;
  }

  /* -----------------------------------------------------------------------
   * cleanupFunction()
   *
   * Final function cleanup code.
   * ----------------------------------------------------------------------- */

  void cleanupFunction(Node *n, Wrapper *f, ParmList *parms) {
    String *cleanup = freearg(parms);
    Printv(f->code, cleanup, NULL);

    if (GetFlag(n, "feature:new")) {
      String *tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0);
      if (tm) {
	Replaceall(tm, "$source", Swig_cresult_name());
	Printv(f->code, tm, "\n", NULL);
	Delete(tm);
      }
    }

    Replaceall(f->code, "$cleanup", cleanup);
    Delete(cleanup);

    Replaceall(f->code, "$symname", Getattr(n, "sym:name"));
  }

  /* -----------------------------------------------------------------------
   * variableHandler()
   *
   * This exists just to set the making_variable_wrappers flag.
   * ----------------------------------------------------------------------- */

  virtual int variableHandler(Node *n) {
    assert(!making_variable_wrappers);
    making_variable_wrappers = true;
    int r = Language::variableHandler(n);
    making_variable_wrappers = false;
    return r;
  }

  /* -----------------------------------------------------------------------
   * constantWrapper()
   *
   * Product a const declaration.
   * ------------------------------------------------------------------------ */

  virtual int constantWrapper(Node *n) {
    SwigType *type = Getattr(n, "type");

    if (!SwigType_issimple(type) && SwigType_type(type) != T_STRING) {
      return goComplexConstant(n, type);
    }

    if (Getattr(n, "storage") && Strcmp(Getattr(n, "storage"), "static") == 0) {
      return goComplexConstant(n, type);
    }

    String *go_name = buildGoName(Getattr(n, "sym:name"), false, false);

    String *tm = goType(n, type);
    String *value = Getattr(n, "value");

    String *copy = NULL;
    if (SwigType_type(type) == T_BOOL) {
      if (Cmp(value, "true") != 0 && Cmp(value, "false") != 0) {
	return goComplexConstant(n, type);
      }
    } else if (SwigType_type(type) == T_STRING || SwigType_type(type) == T_CHAR) {
      // Backslash sequences are somewhat different in Go and C/C++.
      if (Strchr(value, '\\') != 0) {
	return goComplexConstant(n, type);
      }
    } else {
      // Accept a 0x prefix, and strip combinations of u and l
      // suffixes.  Otherwise accept digits, decimal point, and
      // exponentiation.  Treat anything else as too complicated to
      // handle as a Go constant.
      char *p = Char(value);
      int len = strlen(p);
      bool need_copy = false;
      while (len > 0) {
	char c = p[len - 1];
	if (c != 'l' && c != 'L' && c != 'u' && c != 'U') {
	  break;
	}
	--len;
	need_copy = true;
      }
      bool is_hex = false;
      int i = 0;
      if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
	i = 2;
	is_hex = true;
      }
      for (; i < len; ++i) {
	switch (p[i]) {
	case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
	  break;
	case 'a': case 'b': case 'c': case 'd': case 'f': case 'A': case 'B': case 'C': case 'D': case 'F':
	  if (!is_hex) {
	    return goComplexConstant(n, type);
	  }
	  break;
	case '.': case 'e': case 'E': case '+': case '-':
	  break;
	default:
	  return goComplexConstant(n, type);
	}
      }
      if (need_copy) {
	copy = Copy(value);
	Replaceall(copy, p + len, "");
	value = copy;
      }
    }

    if (!checkNameConflict(go_name, n, NULL)) {
      Delete(tm);
      Delete(go_name);
      Delete(copy);
      return SWIG_NOWRAP;
    }

    Printv(f_go_wrappers, "const ", go_name, " ", tm, " = ", NULL);
    if (SwigType_type(type) == T_STRING) {
      Printv(f_go_wrappers, "\"", value, "\"", NULL);
    } else if (SwigType_type(type) == T_CHAR) {
      Printv(f_go_wrappers, "'", value, "'", NULL);
    } else {
      Printv(f_go_wrappers, value, NULL);
    }

    Printv(f_go_wrappers, "\n", NULL);

    Delete(tm);
    Delete(go_name);
    Delete(copy);

    return SWIG_OK;
  }

  /* ----------------------------------------------------------------------
   * enumDeclaration()
   *
   * A C++ enum type turns into a Named go int type.
   * ---------------------------------------------------------------------- */

  virtual int enumDeclaration(Node *n) {
    String *name = goEnumName(n);
    if (Strcmp(name, "int") != 0) {
      if (!ImportMode || !imported_package) {
	if (!checkNameConflict(name, n, NULL)) {
	  Delete(name);
	  return SWIG_NOWRAP;
	}
	Printv(f_go_wrappers, "type ", name, " int\n", NULL);
      } else {
	String *nw = NewString("");
	Printv(nw, imported_package, ".", name, NULL);
	Setattr(n, "go:enumname", nw);
      }
    }
    Delete(name);

    return Language::enumDeclaration(n);
  }

  /* -----------------------------------------------------------------------
   * enumvalueDeclaration()
   *
   * Declare a single value of an enum type.  We fetch the value by
   * calling a C/C++ function.
   * ------------------------------------------------------------------------ */

  virtual int enumvalueDeclaration(Node *n) {
    if (!is_public(n)) {
      return SWIG_OK;
    }
    if (Getattr(parentNode(n), "unnamed")) {
      Setattr(n, "type", NewString("int"));
    } else {
      Setattr(n, "type", Getattr(parentNode(n), "enumtype"));
    }
    return goComplexConstant(n, Getattr(n, "type"));
  }

  /* -----------------------------------------------------------------------
   * goComplexConstant()
   *
   * Handle a const declaration for something which is not a Go constant.
   * ------------------------------------------------------------------------ */

  int goComplexConstant(Node *n, SwigType *type) {
    String *symname = Getattr(n, "sym:name");
    if (!symname) {
      symname = Getattr(n, "name");
    }

    String *varname = buildGoName(symname, true, false);

    if (!checkNameConflict(varname, n, NULL)) {
      Delete(varname);
      return SWIG_NOWRAP;
    }

    String *get = NewString("");
    Printv(get, Swig_cresult_name(), " = ", NULL);

    char quote;
    if (Getattr(n, "wrappedasconstant")) {
      quote = '\0';
    } else if (SwigType_type(type) == T_CHAR) {
      quote = '\'';
    } else if (SwigType_type(type) == T_STRING) {
      quote = '"';
    } else {
      quote = '\0';
    }

    if (quote != '\0') {
      Printf(get, "%c", quote);
    }

    Printv(get, Getattr(n, "value"), NULL);

    if (quote != '\0') {
      Printf(get, "%c", quote);
    }

    Printv(get, ";\n", NULL);
    Setattr(n, "wrap:action", get);

    String *sname = Copy(symname);
    if (class_name) {
      Append(sname, "_");
      Append(sname, class_name);
    }

    String *go_name = NewString("_swig_get");
    if (class_name) {
      Append(go_name, class_name);
      Append(go_name, "_");
    }
    Append(go_name, sname);

    String *wname = Swig_name_wrapper(sname);
    Setattr(n, "wrap:name", wname);

    int r = makeWrappers(n, sname, go_name, NULL, wname, NULL, NULL, type, true);

    if (r != SWIG_OK) {
      return r;
    }

    String *t = goType(n, type);
    Printv(f_go_wrappers, "var ", varname, " ", t, " = ", go_name, "()\n", NULL);

    Delete(varname);
    Delete(t);
    Delete(go_name);
    Delete(sname);

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * classHandler()
   *
   * For a C++ class, in Go we generate both a struct and an
   * interface.  The interface will declare all the class public
   * methods.  We will define all the methods on the struct, so that
   * the struct meets the interface.  We then expect users of the
   * class to use the interface.
   * ------------------------------------------------------------ */

  virtual int classHandler(Node *n) {
    class_node = n;

    List *baselist = Getattr(n, "bases");
    bool has_base_classes = baselist && Len(baselist) > 0;

    String *name = Getattr(n, "sym:name");

    String *go_name = exportedName(name);

    if (!checkNameConflict(go_name, n, NULL)) {
      Delete(go_name);
      SetFlag(n, "go:conflict");
      return SWIG_NOWRAP;
    }

    String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true);

    class_name = name;
    class_receiver = go_type_name;
    class_methods = NewHash();

    int isdir = GetFlag(n, "feature:director");
    int isnodir = GetFlag(n, "feature:nodirector");
    bool is_director = isdir && !isnodir;

    Printv(f_go_wrappers, "type ", go_type_name, " uintptr\n\n", NULL);

    // A method to return the pointer to the C++ class.  This is used
    // by generated code to convert between the interface and the C++
    // value.
    Printv(f_go_wrappers, "func (p ", go_type_name, ") Swigcptr() uintptr {\n", NULL);
    Printv(f_go_wrappers, "\treturn (uintptr)(p)\n", NULL);
    Printv(f_go_wrappers, "}\n\n", NULL);

    // A method used as a marker for the class, to avoid invalid
    // interface conversions when using multiple inheritance.
    Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigIs", go_name, "() {\n", NULL);
    Printv(f_go_wrappers, "}\n\n", NULL);

    if (is_director) {
      // Return the interface passed to the NewDirector function.
      Printv(f_go_wrappers, "func (p ", go_type_name, ") DirectorInterface() interface{} {\n", NULL);
      Printv(f_go_wrappers, "\treturn nil\n", NULL);
      Printv(f_go_wrappers, "}\n\n", NULL);
    }

    // We have seen a definition for this type.
    Setattr(defined_types, go_name, go_name);
    Setattr(defined_types, go_type_name, go_type_name);

    interfaces = NewString("");

    int r = Language::classHandler(n);
    if (r != SWIG_OK) {
      return r;
    }

    if (has_base_classes) {
      // For each method defined in a base class but not defined in
      // this class, we need to define the method in this class.  We
      // can't use anonymous field inheritance because it works
      // differently in Go and in C++.

      Hash *local = NewHash();
      for (Node *ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) {

	if (!is_public(ni)) {
	  continue;
	}

	String *type = Getattr(ni, "nodeType");
	if (Cmp(type, "constructor") == 0 || Cmp(type, "destructor") == 0) {
	  continue;
	}

	String *cname = Getattr(ni, "sym:name");
	if (!cname) {
	  cname = Getattr(ni, "name");
	}
	if (cname) {
	  Setattr(local, cname, NewString(""));
	}
      }

      for (Iterator b = First(baselist); b.item; b = Next(b)) {
	List *bases = NewList();
	Append(bases, Getattr(b.item, "classtype"));
	int r = addBase(n, b.item, bases, local);
	if (r != SWIG_OK) {
	  return r;
	}
	Delete(bases);
      }

      Delete(local);

      Hash *parents = NewHash();
      addFirstBaseInterface(n, parents, baselist);
      int r = addExtraBaseInterfaces(n, parents, baselist);
      Delete(parents);
      if (r != SWIG_OK) {
	return r;
      }
    }

    Printv(f_go_wrappers, "type ", go_name, " interface {\n", NULL);
    Printv(f_go_wrappers, "\tSwigcptr() uintptr\n", NULL);
    Printv(f_go_wrappers, "\tSwigIs", go_name, "()\n", NULL);

    if (is_director) {
      Printv(f_go_wrappers, "\tDirectorInterface() interface{}\n", NULL);
    }

    Append(f_go_wrappers, interfaces);
    Printf(f_go_wrappers, "}\n\n", NULL);
    Delete(interfaces);

    interfaces = NULL;
    class_name = NULL;
    class_receiver = NULL;
    class_node = NULL;
    Delete(class_methods);
    class_methods = NULL;

    Delete(go_type_name);

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * addBase()
   *
   * Implement methods and members defined in a parent class for a
   * child class.
   * ------------------------------------------------------------ */

  int addBase(Node *n, Node *base, List *bases, Hash *local) {
    if (GetFlag(base, "feature:ignore")) {
      return SWIG_OK;
    }

    for (Node *ni = Getattr(base, "firstChild"); ni; ni = nextSibling(ni)) {

      if (GetFlag(ni, "feature:ignore")) {
	continue;
      }

      if (!is_public(ni)) {
	continue;
      }

      String *type = Getattr(ni, "nodeType");
      if (Strcmp(type, "constructor") == 0 || Strcmp(type, "destructor") == 0 || Strcmp(type, "enum") == 0 || Strcmp(type, "using") == 0 || Strcmp(type, "classforward") == 0 || Strcmp(type, "template") == 0) {
	continue;
      }
      String *storage = Getattr(ni, "storage");
      if (storage && (Strcmp(storage, "typedef") == 0 || Strcmp(storage, "friend") == 0)) {
	continue;
      }

      String *mname = Getattr(ni, "sym:name");
      if (!mname) {
	continue;
      }

      String *lname = Getattr(ni, "name");
      if (Getattr(class_methods, lname)) {
	continue;
      }
      if (Getattr(local, lname)) {
	continue;
      }
      Setattr(local, lname, NewString(""));

      String *ty = NewString(Getattr(ni, "type"));
      SwigType_push(ty, Getattr(ni, "decl"));
      String *fullty = SwigType_typedef_resolve_all(ty);
      bool is_function = SwigType_isfunction(fullty) ? true : false;
      Delete(ty);
      Delete(fullty);

      if (is_function) {
	int r = goBaseMethod(n, bases, ni);
	if (r != SWIG_OK) {
	  return r;
	}

	if (Getattr(ni, "sym:overloaded")) {
	  for (Node *on = Getattr(ni, "sym:nextSibling"); on; on = Getattr(on, "sym:nextSibling")) {
	    r = goBaseMethod(n, bases, on);
	    if (r != SWIG_OK) {
	      return r;
	    }
	  }

	  String *receiver = class_receiver;
	  bool is_static = isStatic(ni);
	  if (is_static) {
	    receiver = NULL;
	  }
	  String *go_name = buildGoName(Getattr(ni, "sym:name"), is_static, false);
	  r = makeDispatchFunction(ni, go_name, receiver, is_static, NULL, false);
	  Delete(go_name);
	  if (r != SWIG_OK) {
	    return r;
	  }
	}
      } else {
	int r = goBaseVariable(n, bases, ni);
	if (r != SWIG_OK) {
	  return r;
	}
      }
    }

    List *baselist = Getattr(base, "bases");
    if (baselist && Len(baselist) > 0) {
      for (Iterator b = First(baselist); b.item; b = Next(b)) {
	List *nb = Copy(bases);
	Append(nb, Getattr(b.item, "classtype"));
	int r = addBase(n, b.item, nb, local);
	Delete(nb);
	if (r != SWIG_OK) {
	  return r;
	}
      }
    }

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * goBaseMethod()
   *
   * Implement a method defined in a parent class for a child class.
   * ------------------------------------------------------------ */

  int goBaseMethod(Node *method_class, List *bases, Node *method) {
    String *symname = Getattr(method, "sym:name");
    if (!validIdentifier(symname)) {
      return SWIG_OK;
    }

    String *name = NewString("");
    Printv(name, Getattr(method_class, "sym:name"), "_", symname, NULL);

    bool is_static = isStatic(method);

    String *go_name = buildGoName(name, is_static, false);

    String *overname = NULL;
    if (Getattr(method, "sym:overloaded")) {
      overname = Getattr(method, "sym:overname");
    }
    String *wname = Swig_name_wrapper(name);
    if (overname) {
      Append(wname, overname);
    }

    String *result = NewString(Getattr(method, "type"));
    SwigType_push(result, Getattr(method, "decl"));
    if (SwigType_isqualifier(result)) {
      Delete(SwigType_pop(result));
    }
    Delete(SwigType_pop_function(result));

    // If the base method is imported, wrap:action may not be set.
    Swig_save("goBaseMethod", method, "wrap:name", "wrap:action", "parms", NULL);
    Setattr(method, "wrap:name", wname);
    if (!Getattr(method, "wrap:action")) {
      if (!is_static) {
	Swig_MethodToFunction(method, getNSpace(), getClassType(), (Getattr(method, "template") ? SmartPointer : Extend | SmartPointer), NULL, false);
	// Remove any self parameter that was just added.
	ParmList *parms = Getattr(method, "parms");
	if (parms && Getattr(parms, "self")) {
	  parms = CopyParmList(nextSibling(parms));
	  Setattr(method, "parms", parms);
	}
      } else {
	String *call = Swig_cfunction_call(Getattr(method, "name"), Getattr(method, "parms"));
	Setattr(method, "wrap:action", Swig_cresult(Getattr(method, "type"), Swig_cresult_name(), call));
      }
    }

    int r = makeWrappers(method, name, go_name, overname, wname, bases, Getattr(method, "parms"), result, is_static);

    Swig_restore(method);

    Delete(result);
    Delete(go_name);
    Delete(name);

    return r;
  }

  /* ------------------------------------------------------------
   * goBaseVariable()
   *
   * Add accessors for a member variable defined in a parent class for
   * a child class.
   * ------------------------------------------------------------ */

  int goBaseVariable(Node *var_class, List *bases, Node *var) {
    if (isStatic(var)) {
      return SWIG_OK;
    }

    String *var_name = buildGoName(Getattr(var, "sym:name"), false, false);

    Swig_save("goBaseVariable", var, "type", "wrap:action", NULL);

    // For a pointer type we apparently have to wrap in the decl.
    SwigType *var_type = NewString(Getattr(var, "type"));
    SwigType_push(var_type, Getattr(var, "decl"));
    Setattr(var, "type", var_type);

    SwigType *vt = Copy(var_type);
    if (SwigType_isclass(vt)) {
      SwigType_add_pointer(vt);
    }

    int flags = Extend | SmartPointer | use_naturalvar_mode(var);
    if (isNonVirtualProtectedAccess(var)) {
      flags |= CWRAP_ALL_PROTECTED_ACCESS;
    }

    String *mname = Swig_name_member(getNSpace(), Getattr(var_class, "sym:name"), var_name);

    if (is_assignable(var)) {
      for (Iterator ki = First(var); ki.key; ki = Next(ki)) {
	if (Strncmp(ki.key, "tmap:", 5) == 0) {
	  Delattr(var, ki.key);
	}
      }
      Swig_save("goBaseVariableSet", var, "name", "sym:name", "type", NULL);

      String *mname_set = NewString("Set");
      Append(mname_set, mname);

      String *go_name = NewString("Set");
      Append(go_name, var_name);

      Swig_MembersetToFunction(var, class_name, flags);

      String *wname = Swig_name_wrapper(mname_set);
      ParmList *parms = NewParm(vt, var_name, var);
      String *result = NewString("void");
      int r = makeWrappers(var, mname_set, go_name, NULL, wname, bases, parms, result, false);
      if (r != SWIG_OK) {
	return r;
      }
      Delete(wname);
      Delete(parms);
      Delete(result);
      Delete(go_name);
      Delete(mname_set);

      Swig_restore(var);
      for (Iterator ki = First(var); ki.key; ki = Next(ki)) {
	if (Strncmp(ki.key, "tmap:", 5) == 0) {
	  Delattr(var, ki.key);
	}
      }
    }

    Swig_MembergetToFunction(var, class_name, flags);

    String *mname_get = NewString("Get");
    Append(mname_get, mname);

    String *go_name = NewString("Get");
    Append(go_name, var_name);

    String *wname = Swig_name_wrapper(mname_get);

    int r = makeWrappers(var, mname_get, go_name, NULL, wname, bases, NULL, vt, false);
    if (r != SWIG_OK) {
      return r;
    }

    Delete(wname);
    Delete(mname_get);
    Delete(go_name);
    Delete(mname);
    Delete(var_name);
    Delete(var_type);
    Delete(vt);

    Swig_restore(var);

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * addFirstBaseInterface()
   *
   * When a C++ class uses multiple inheritance, we can use the C++
   * pointer for the first base class but not for any subsequent base
   * classes.  However, the Go interface will match the interface for
   * all the base classes.  To avoid accidentally treating a class as
   * a pointer to a base class other than the first one, we use an
   * isClassname method.  This function adds those methods as
   * required.
   *
   * For convenience when using multiple inheritance, we also add
   * functions to retrieve the base class pointers.
   * ------------------------------------------------------------ */

  void addFirstBaseInterface(Node *n, Hash *parents, List *bases) {
    if (!bases || Len(bases) == 0) {
      return;
    }
    Iterator b = First(bases);
    if (!GetFlag(b.item, "feature:ignore")) {
      String *go_name = buildGoName(Getattr(n, "sym:name"), false, false);
      String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true);
      String *go_base_name = exportedName(Getattr(b.item, "sym:name"));
      String *go_base_type = goType(n, Getattr(b.item, "classtypeobj"));
      String *go_base_type_name = goCPointerType(Getattr(b.item, "classtypeobj"), true);

      Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigIs", go_base_name, "() {\n", NULL);
      Printv(f_go_wrappers, "}\n\n", NULL);

      Printv(interfaces, "\tSwigIs", go_base_name, "()\n", NULL);

      Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigGet", go_base_name, "() ", go_base_type, " {\n", NULL);
      Printv(f_go_wrappers, "\treturn ", go_base_type_name, "(p.Swigcptr())\n", NULL);
      Printv(f_go_wrappers, "}\n\n", NULL);

      Printv(interfaces, "\tSwigGet", go_base_name, "() ", go_base_type, "\n", NULL);

      Setattr(parents, go_base_name, NewString(""));

      Delete(go_name);
      Delete(go_type_name);
      Delete(go_base_type);
      Delete(go_base_type_name);
    }

    addFirstBaseInterface(n, parents, Getattr(b.item, "bases"));
  }

  /* ------------------------------------------------------------
   * addExtraBaseInterfaces()
   *
   * Add functions to retrieve the base class pointers for all base
   * classes other than the first.
   * ------------------------------------------------------------ */

  int addExtraBaseInterfaces(Node *n, Hash *parents, List *bases) {
    Iterator b = First(bases);

    Node *fb = b.item;

    for (b = Next(b); b.item; b = Next(b)) {
      if (GetFlag(b.item, "feature:ignore")) {
	continue;
      }

      String *go_base_name = exportedName(Getattr(b.item, "sym:name"));

      Swig_save("addExtraBaseInterface", n, "wrap:action", "wrap:name", "wrap:parms", NULL);

      SwigType *type = Copy(Getattr(n, "classtypeobj"));
      SwigType_add_pointer(type);
      Parm *parm = NewParm(type, "self", n);
      Setattr(n, "wrap:parms", parm);

      String *pn = Swig_cparm_name(parm, 0);
      String *action = NewString("");
      Printv(action, Swig_cresult_name(), " = (", Getattr(b.item, "classtype"), "*)", pn, ";", NULL);
      Delete(pn);

      Setattr(n, "wrap:action", action);

      String *name = Copy(class_name);
      Append(name, "_SwigGet");
      Append(name, go_base_name);

      String *go_name = NewString("SwigGet");
      String *c1 = exportedName(go_base_name);
      Append(go_name, c1);
      Delete(c1);

      String *wname = Swig_name_wrapper(name);
      Setattr(n, "wrap:name", wname);

      SwigType *result = Copy(Getattr(b.item, "classtypeobj"));
      SwigType_add_pointer(result);

      int r = makeWrappers(n, name, go_name, NULL, wname, NULL, parm, result,
			   false);
      if (r != SWIG_OK) {
	return r;
      }

      Swig_restore(n);

      Setattr(parents, go_base_name, NewString(""));

      Delete(go_name);
      Delete(type);
      Delete(parm);
      Delete(action);
      Delete(result);

      String *ns = NewString("");
      addParentExtraBaseInterfaces(n, parents, b.item, false, ns);
      Delete(ns);
    }

    if (!GetFlag(fb, "feature:ignore")) {
      String *ns = NewString("");
      addParentExtraBaseInterfaces(n, parents, fb, true, ns);
      Delete(ns);
    }

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * addParentExtraBaseInterfaces()
   *
   * Add functions to retrieve the base class pointers for all base
   * classes of parents other than the first base class at each level.
   * ------------------------------------------------------------ */

  void addParentExtraBaseInterfaces(Node *n, Hash *parents, Node *base, bool is_base_first, String *sofar) {
    List *baselist = Getattr(base, "bases");
    if (!baselist || Len(baselist) == 0) {
      return;
    }

    String *go_this_base_name = exportedName(Getattr(base, "sym:name"));

    String *sf = NewString("");
    Printv(sf, sofar, ".SwigGet", go_this_base_name, "()", NULL);

    Iterator b = First(baselist);

    if (is_base_first) {
      if (!b.item) {
	return;
      }
      if (!GetFlag(b.item, "feature:ignore")) {
	addParentExtraBaseInterfaces(n, parents, b.item, true, sf);
      }

      b = Next(b);
    }

    String *go_name = buildGoName(Getattr(n, "sym:name"), false, false);
    String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true);

    for (; b.item; b = Next(b)) {
      if (GetFlag(b.item, "feature:ignore")) {
	continue;
      }

      String *go_base_name = exportedName(Getattr(b.item, "sym:name"));

      if (!Getattr(parents, go_base_name)) {
	Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigGet", go_base_name, "() ", go_base_name, " {\n", NULL);
	Printv(f_go_wrappers, "\treturn p", sf, ".SwigGet", go_base_name, "()\n", NULL);
	Printv(f_go_wrappers, "}\n\n", NULL);

	Printv(interfaces, "\tSwigGet", go_base_name, "() ", go_base_name, "\n", NULL);

	addParentExtraBaseInterfaces(n, parents, b.item, false, sf);

	Setattr(parents, go_base_name, NewString(""));
      }
    }

    Delete(go_name);
    Delete(go_type_name);
    Delete(go_this_base_name);
    Delete(sf);
  }

  /* ------------------------------------------------------------
   * classDirectorInit
   *
   * Add support for a director class.
   *
   * Virtual inheritance is different in Go and C++.  We implement
   * director classes by defining a new function in Go,
   * NewDirectorClassname, which takes a empty interface value and
   * creates an instance of a new child class.  The new child class
   * refers all methods back to Go.  The Go code checks whether the
   * value passed to NewDirectorClassname implements that method; if
   * it does, it calls it, otherwise it calls back into C++.
   * ------------------------------------------------------------ */

  int classDirectorInit(Node *n) {
    // Because we use a different function to handle inheritance in
    // Go, ordinary creations of the object should not create a
    // director object.
    Delete(director_ctor_code);
    director_ctor_code = NewString("$nondirector_new");

    class_node = n;

    String *name = Getattr(n, "sym:name");

    assert(!class_name);
    class_name = name;

    String *go_name = exportedName(name);

    String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true);

    assert(!class_receiver);
    class_receiver = go_type_name;

    String *director_struct_name = NewString("_swig_Director");
    Append(director_struct_name, go_name);

    String *cxx_director_name = NewString("SwigDirector_");
    Append(cxx_director_name, name);

    // The Go type of the director class.
    Printv(f_go_wrappers, "type ", director_struct_name, " struct {\n", NULL);
    Printv(f_go_wrappers, "\t", go_type_name, "\n", NULL);
    Printv(f_go_wrappers, "\tv interface{}\n", NULL);
    Printv(f_go_wrappers, "}\n\n", NULL);

    Printv(f_go_wrappers, "func (p *", director_struct_name, ") Swigcptr() uintptr {\n", NULL);
    Printv(f_go_wrappers, "\treturn p.", go_type_name, ".Swigcptr()\n", NULL);
    Printv(f_go_wrappers, "}\n\n", NULL);

    Printv(f_go_wrappers, "func (p *", director_struct_name, ") SwigIs", go_name, "() {\n", NULL);
    Printv(f_go_wrappers, "}\n\n", NULL);

    Printv(f_go_wrappers, "func (p *", director_struct_name, ") DirectorInterface() interface{} {\n", NULL);
    Printv(f_go_wrappers, "\treturn p.v\n", NULL);
    Printv(f_go_wrappers, "}\n\n", NULL);

    // Start defining the director class.
    Printv(f_c_directors_h, "class ", cxx_director_name, " : public ", Getattr(n, "classtype"), "\n", NULL);
    Printv(f_c_directors_h, "{\n", NULL);
    Printv(f_c_directors_h, " public:\n", NULL);

    Delete(director_struct_name);
    Delete(cxx_director_name);

    class_methods = NewHash();

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * classDirectorConstructor
   *
   * Emit a constructor for a director class.
   * ------------------------------------------------------------ */

  int classDirectorConstructor(Node *n) {
    bool is_ignored = GetFlag(n, "feature:ignore") ? true : false;

    String *name = Getattr(n, "sym:name");
    if (!name) {
      assert(is_ignored);
      name = Getattr(n, "name");
    }

    String *overname = NULL;
    if (Getattr(n, "sym:overloaded")) {
      overname = Getattr(n, "sym:overname");
    }

    String *go_name = exportedName(name);

    ParmList *parms = Getattr(n, "parms");
    Setattr(n, "wrap:parms", parms);

    String *cn = exportedName(Getattr(parentNode(n), "sym:name"));

    String *go_type_name = goCPointerType(Getattr(parentNode(n), "classtypeobj"), true);

    String *director_struct_name = NewString("_swig_Director");
    Append(director_struct_name, cn);

    String *fn_name = NewString("_swig_NewDirector");
    Append(fn_name, cn);
    Append(fn_name, go_name);

    if (!overname && !is_ignored) {
      if (!checkNameConflict(fn_name, n, NULL)) {
	return SWIG_NOWRAP;
      }
    }

    String *wname = Swig_name_wrapper(fn_name);

    if (overname) {
      Append(wname, overname);
    }
    Setattr(n, "wrap:name", wname);

    bool is_static = isStatic(n);

    Wrapper *dummy = NewWrapper();
    emit_attach_parmmaps(parms, dummy);
    DelWrapper(dummy);

    Swig_typemap_attach_parms("gotype", parms, NULL);
    int parm_count = emit_num_arguments(parms);

    String *func_name = NewString("NewDirector");
    Append(func_name, go_name);

    String *func_with_over_name = Copy(func_name);
    if (overname) {
      Append(func_with_over_name, overname);
    }

    SwigType *first_type = NewString("void");
    SwigType_add_pointer(first_type);
    Parm *first_parm = NewParm(first_type, "swig_p", n);
    set_nextSibling(first_parm, parms);
    Setattr(first_parm, "lname", "p");

    Parm *p = parms;
    for (int i = 0; i < parm_count; ++i) {
      p = getParm(p);
      Swig_cparm_name(p, i);
      p = nextParm(p);
    }

    if (!is_ignored) {
      // Declare the C++ wrapper.

      if (gccgo_flag) {
	Printv(f_go_wrappers, "//extern ", go_prefix, "_", wname, "\n", NULL);
      }

      Printv(f_go_wrappers, "func ", fn_name, NULL);
      if (overname) {
	Printv(f_go_wrappers, overname, NULL);
      }
      Printv(f_go_wrappers, "(*", director_struct_name, NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	String *tm = goType(p, Getattr(p, "type"));
	Printv(f_go_wrappers, ", ", tm, NULL);
	Delete(tm);
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ") ", go_type_name, "\n\n", NULL);

      Printv(f_go_wrappers, "func ", func_with_over_name, "(v interface{}", NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	// Set the lname parameter.
	Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", NULL);
	String *tm = goType(p, Getattr(p, "type"));
	Printv(f_go_wrappers, tm, NULL);
	Delete(tm);
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ") ", cn, " {\n", NULL);

      Printv(f_go_wrappers, "\tp := &", director_struct_name, "{0, v}\n", NULL);

      if (gccgo_flag) {
	Printv(f_go_wrappers, "\tdefer SwigCgocallDone()\n", NULL);
	Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL);
      }

      Printv(f_go_wrappers, "\tp.", class_receiver, " = ", fn_name, NULL);
      if (overname) {
	Printv(f_go_wrappers, overname, NULL);
      }
      Printv(f_go_wrappers, "(p", NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	Printv(f_go_wrappers, ", ", Getattr(p, "lname"), NULL);
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ")\n", NULL);
      Printv(f_go_wrappers, "\treturn p\n", NULL);
      Printv(f_go_wrappers, "}\n\n", NULL);

      SwigType *result = Copy(Getattr(parentNode(n), "classtypeobj"));
      SwigType_add_pointer(result);

      Swig_save("classDirectorConstructor", n, "wrap:name", "wrap:action", NULL);

      Setattr(n, "wrap:name", Swig_name_wrapper(name));

      String *action = NewString("");
      Printv(action, Swig_cresult_name(), " = new SwigDirector_", class_name, "(", NULL);
      String *pname = Swig_cparm_name(NULL, 0);
      Printv(action, pname, NULL);
      Delete(pname);
      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	String *pname = Swig_cparm_name(NULL, i + 1);
	Printv(action, ", ", NULL);
	if (SwigType_isreference(Getattr(p, "type"))) {
	  Printv(action, "*", NULL);
	}
	Printv(action, pname, NULL);
	Delete(pname);
	p = nextParm(p);
      }
      Printv(action, ");", NULL);
      Setattr(n, "wrap:action", action);

      if (!gccgo_flag) {
	int r = gcFunctionWrapper(n, fn_name, fn_name, overname, wname,
				  first_parm, result, is_static, false);
	if (r != SWIG_OK) {
	  return r;
	}
	r = gccFunctionWrapper(n, NULL, wname, first_parm, result);
	if (r != SWIG_OK) {
	  return r;
	}
      } else {
	int r = gccgoFunctionWrapper(n, NULL, wname, first_parm, result);
	if (r != SWIG_OK) {
	  return r;
	}
      }

      Swig_restore(n);

      Delete(result);
    }

    String *cxx_director_name = NewString("SwigDirector_");
    Append(cxx_director_name, class_name);

    String *decl = Swig_method_decl(NULL, Getattr(n, "decl"),
				    cxx_director_name, first_parm, 0, 0);
    Printv(f_c_directors_h, "  ", decl, ";\n", NULL);
    Delete(decl);

    decl = Swig_method_decl(NULL, Getattr(n, "decl"), cxx_director_name, first_parm, 0, 0);
    Printv(f_c_directors, cxx_director_name, "::", decl, "\n", NULL);
    Delete(decl);

    Printv(f_c_directors, "    : ", Getattr(parentNode(n), "classtype"), "(", NULL);

    p = parms;
    for (int i = 0; i < parm_count; ++i) {
      p = getParm(p);
      if (i > 0) {
	Printv(f_c_directors, ", ", NULL);
      }
      String *pn = Getattr(p, "name");
      assert(pn);
      Printv(f_c_directors, pn, NULL);
      p = nextParm(p);
    }
    Printv(f_c_directors, "),\n", NULL);
    Printv(f_c_directors, "      go_val(swig_p)\n", NULL);
    Printv(f_c_directors, "{ }\n\n", NULL);

    if (Getattr(n, "sym:overloaded") && !Getattr(n, "sym:nextSibling")) {
      int r = makeDispatchFunction(n, func_name, cn, is_static, Getattr(parentNode(n), "classtypeobj"), false);
      if (r != SWIG_OK) {
	return r;
      }
    }

    Delete(cxx_director_name);
    Delete(go_name);
    Delete(cn);
    Delete(go_type_name);
    Delete(director_struct_name);
    Delete(fn_name);
    Delete(func_name);
    Delete(func_with_over_name);
    Delete(wname);
    Delete(first_type);
    Delete(first_parm);

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * classDirectorDestructor
   *
   * Emit a destructor for a director class.
   * ------------------------------------------------------------ */

  int classDirectorDestructor(Node *n) {
    if (!is_public(n)) {
      return SWIG_OK;
    }

    bool is_ignored = GetFlag(n, "feature:ignore") ? true : false;

    if (!is_ignored) {
      String *fnname = NewString("DeleteDirector");
      String *c1 = exportedName(class_name);
      Append(fnname, c1);
      Delete(c1);

      String *wname = Swig_name_wrapper(fnname);

      Setattr(n, "wrap:name", fnname);

      Swig_DestructorToFunction(n, getNSpace(), getClassType(), CPlusPlus, Extend);

      ParmList *parms = Getattr(n, "parms");
      Setattr(n, "wrap:parms", parms);

      String *result = NewString("void");
      int r = makeWrappers(n, fnname, fnname, NULL, wname, NULL, parms, result, isStatic(n));
      if (r != SWIG_OK) {
	return r;
      }

      Delete(result);
      Delete(fnname);
      Delete(wname);
    }

    // Generate the destructor for the C++ director class.  Since the
    // Go code is keeping a pointer to the C++ object, we need to call
    // back to the Go code to let it know that the C++ object is gone.

    String *wname = NewString("_swiggo_wrap_DeleteDirector_");
    Append(wname, class_name);

    String *go_name = NewString("Swiggo_DeleteDirector_");
    Append(go_name, class_name);

    String *cn = exportedName(class_name);

    String *director_struct_name = NewString("_swig_Director");
    Append(director_struct_name, cn);

    Printv(f_c_directors_h, "  virtual ~SwigDirector_", class_name, "()", NULL);

    String *throws = buildThrow(n);
    if (throws) {
      Printv(f_c_directors_h, " ", throws, NULL);
    }

    Printv(f_c_directors_h, ";\n", NULL);

    if (!is_ignored) {
      if (!gccgo_flag) {
	Printv(f_c_directors, "extern \"C\" void ", wname, "(void*, int);\n", NULL);
      } else {
	Printv(f_c_directors, "extern \"C\" void ", wname, "(void*) __asm__(\"", go_prefix, ".", package, ".", go_name, "\");\n", NULL);
      }
    }

    Printv(f_c_directors, "SwigDirector_", class_name, "::~SwigDirector_", class_name, "()", NULL);

    if (throws) {
      Printv(f_c_directors, " ", throws, NULL);
      Delete(throws);
    }

    Printv(f_c_directors, "\n", NULL);
    Printv(f_c_directors, "{\n", NULL);

    if (!is_ignored) {
      if (!gccgo_flag) {
	Printv(f_c_directors, "  struct { void *p; } a;\n", NULL);
	Printv(f_c_directors, "  a.p = go_val;\n", NULL);
	Printv(f_c_directors, "  crosscall2(", wname, ", &a, (int) sizeof a);\n", NULL);

	Printv(f_gc_wrappers, "#pragma dynexport ", wname, " ", wname, "\n", NULL);
	Printv(f_gc_wrappers, "extern void \xc2\xb7", go_name, "();\n", NULL);
	Printv(f_gc_wrappers, "void\n", NULL);
	Printv(f_gc_wrappers, wname, "(void *a, int32 n)\n", NULL);
	Printv(f_gc_wrappers, "{\n", NULL);
	Printv(f_gc_wrappers, "\truntime\xc2\xb7" "cgocallback(\xc2\xb7", go_name, ", a, n);\n", NULL);
	Printv(f_gc_wrappers, "}\n\n", NULL);
      } else {
	Printv(f_c_directors, "  ", wname, "(go_val);\n", NULL);
      }
    }

    Printv(f_c_directors, "}\n\n", NULL);

    if (!is_ignored) {
      Printv(f_go_wrappers, "func ", go_name, "(p *", director_struct_name, ") {\n", NULL);
      Printv(f_go_wrappers, "\tp.", class_receiver, " = 0\n", NULL);
      Printv(f_go_wrappers, "}\n\n", NULL);
    }

    Delete(wname);
    Delete(go_name);
    Delete(cn);
    Delete(director_struct_name);

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * classDirectorMethod
   *
   * Emit a method for a director class, plus its overloads.
   * ------------------------------------------------------------ */

  int classDirectorMethod(Node *n, Node *parent, String *super) {
    bool is_ignored = GetFlag(n, "feature:ignore") ? true : false;

    // We don't need explicit calls.
    if (GetFlag(n, "explicitcall")) {
      return SWIG_OK;
    }

    String *name = Getattr(n, "sym:name");
    if (!name) {
      assert(is_ignored);
      name = Getattr(n, "name");
    }

    bool overloaded = Getattr(n, "sym:overloaded") && !Getattr(n, "explicitcallnode");
    if (!overloaded) {
      int r = oneClassDirectorMethod(n, parent, super);
      if (r != SWIG_OK) {
	return r;
      }
    } else {
      // Handle overloaded methods here, because otherwise we will
      // reject them in the class_methods hash table.  We need to use
      // class_methods so that we correctly handle cases where a
      // function in one class hides a function of the same name in a
      // parent class.
      if (!Getattr(class_methods, name)) {
	for (Node *on = Getattr(n, "sym:overloaded"); on; on = Getattr(on, "sym:nextSibling")) {
	  // Swig_overload_rank expects wrap:name and wrap:parms to be
	  // set.
	  String *wn = Swig_name_wrapper(Getattr(on, "sym:name"));
	  Append(wn, Getattr(on, "sym:overname"));
	  Setattr(on, "wrap:name", wn);
	  Delete(wn);
	  Setattr(on, "wrap:parms", Getattr(on, "parms"));
	}
      }

      int r = oneClassDirectorMethod(n, parent, super);
      if (r != SWIG_OK) {
	return r;
      }

      if (!Getattr(n, "sym:nextSibling"))
      {
	// Last overloaded function
	Node *on = Getattr(n, "sym:overloaded");
	bool is_static = isStatic(on);

	String *cn = exportedName(Getattr(parent, "sym:name"));
	String *go_name = buildGoName(name, is_static, false);

	String *director_struct_name = NewString("_swig_Director");
	Append(director_struct_name, cn);

	int r = makeDispatchFunction(on, go_name, director_struct_name, is_static, director_struct_name, false);
	if (r != SWIG_OK) {
	  return r;
	}

	String *go_upcall = NewString("Director");
	Append(go_upcall, cn);
	Append(go_upcall, go_name);
	r = makeDispatchFunction(on, go_upcall, director_struct_name, is_static, director_struct_name, true);
	if (r != SWIG_OK) {
	  return r;
	}
	Delete(cn);
	Delete(go_name);
	Delete(director_struct_name);
	Delete(go_upcall);
      }
    }
    Setattr(class_methods, name, NewString(""));

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * oneClassDirectorMethod
   *
   * Emit a method for a director class.
   * ------------------------------------------------------------ */

  int oneClassDirectorMethod(Node *n, Node *parent, String *super) {
    String *symname = Getattr(n, "sym:name");
    if (!checkFunctionVisibility(n, parent)) {
      return SWIG_OK;
    }

    bool is_ignored = GetFlag(n, "feature:ignore") ? true : false;
    bool is_pure_virtual = (Cmp(Getattr(n, "storage"), "virtual") == 0 && Cmp(Getattr(n, "value"), "0") == 0);

    String *name = Getattr(n, "sym:name");
    if (!name) {
      assert(is_ignored);
      name = Getattr(n, "name");
    }

    String *overname = NULL;
    if (Getattr(n, "sym:overloaded")) {
      overname = Getattr(n, "sym:overname");
    }

    String *cn = exportedName(Getattr(parent, "sym:name"));

    String *go_type_name = goCPointerType(Getattr(parent, "classtypeobj"), true);

    String *director_struct_name = NewString("_swig_Director");
    Append(director_struct_name, cn);

    bool is_static = isStatic(n);

    String *go_name = buildGoName(name, is_static, false);

    ParmList *parms = Getattr(n, "parms");
    Setattr(n, "wrap:parms", parms);

    Wrapper *dummy = NewWrapper();
    emit_attach_parmmaps(parms, dummy);
    DelWrapper(dummy);

    Swig_typemap_attach_parms("gotype", parms, NULL);
    int parm_count = emit_num_arguments(parms);

    SwigType *result = Getattr(n, "type");

    // Save the type for overload processing.
    Setattr(n, "go:type", result);

    String *interface_name = NewString("_swig_DirectorInterface");
    Append(interface_name, cn);
    Append(interface_name, go_name);
    if (overname) {
      Append(interface_name, overname);
    }

    String *callback_name = Copy(director_struct_name);
    Append(callback_name, "_callback_");
    Append(callback_name, name);
    Replace(callback_name, "_swig", "Swig", DOH_REPLACE_FIRST);
    if (overname) {
      Append(callback_name, overname);
    }

    String *callback_wname = Swig_name_wrapper(callback_name);

    String *upcall_name = Copy(director_struct_name);
    Append(upcall_name, "_upcall_");
    Append(upcall_name, go_name);

    String *upcall_wname = Swig_name_wrapper(upcall_name);

    String *go_with_over_name = Copy(go_name);
    if (overname) {
      Append(go_with_over_name, overname);
    }

    Parm *p = 0;
    Wrapper *w = NewWrapper();

    Swig_director_parms_fixup(parms);

    Swig_typemap_attach_parms("directorin", parms, w);
    Swig_typemap_attach_parms("directorargout", parms, w);

    if (!is_ignored) {
      // We use an interface to see if this method is defined in Go.
      Printv(f_go_wrappers, "type ", interface_name, " interface {\n", NULL);
      Printv(f_go_wrappers, "\t", go_with_over_name, "(", NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	if (i > 0) {
	  Printv(f_go_wrappers, ", ", NULL);
	}
	String *tm = goType(p, Getattr(p, "type"));
	Printv(f_go_wrappers, tm, NULL);
	Delete(tm);
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ")", NULL);

      if (SwigType_type(result) != T_VOID) {
	String *tm = goType(n, result);
	Printv(f_go_wrappers, " ", tm, NULL);
	Delete(tm);
      }

      Printv(f_go_wrappers, "\n", NULL);
      Printv(f_go_wrappers, "}\n\n", NULL);

      // Declare the upcall function, which calls the method on the
      // parent class.

      if (overname) {
	Append(upcall_wname, overname);
      }

      String *upcall_gc_name = buildGoWrapperName(upcall_name, overname);

      if (gccgo_flag) {
	Printv(f_go_wrappers, "//extern ", go_prefix, "_", upcall_wname, "\n", NULL);
      }

      Printv(f_go_wrappers, "func ", upcall_gc_name, "(", go_type_name, NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	String *tm = goWrapperType(p, Getattr(p, "type"), false);
	Printv(f_go_wrappers, ", ", tm, NULL);
	Delete(tm);
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ")", NULL);

      if (SwigType_type(result) != T_VOID) {
	String *tm = goWrapperType(n, result, true);
	Printv(f_go_wrappers, " ", tm, NULL);
	Delete(tm);
      }

      Printv(f_go_wrappers, "\n", NULL);

      // Define the method on the director class in Go.

      Printv(f_go_wrappers, "func (swig_p *", director_struct_name, ") ", go_with_over_name, "(", NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	if (i > 0) {
	  Printv(f_go_wrappers, ", ", NULL);
	}
	Printv(f_go_wrappers, Getattr(p, "lname"), " ", NULL);
	String *tm = goType(p, Getattr(p, "type"));
	Printv(f_go_wrappers, tm, NULL);
	Delete(tm);
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ")", NULL);

      if (SwigType_type(result) != T_VOID) {
	String *tm = goType(n, result);
	Printv(f_go_wrappers, " ", tm, NULL);
	Delete(tm);
      }

      Printv(f_go_wrappers, " {\n", NULL);

      Printv(f_go_wrappers, "\tif swig_g, swig_ok := swig_p.v.(", interface_name, "); swig_ok {\n", NULL);
      Printv(f_go_wrappers, "\t\t", NULL);
      if (SwigType_type(result) != T_VOID) {
	Printv(f_go_wrappers, "return ", NULL);
      }
      Printv(f_go_wrappers, "swig_g.", go_with_over_name, "(", NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	if (i > 0) {
	  Printv(f_go_wrappers, ", ", NULL);
	}
	Printv(f_go_wrappers, Getattr(p, "lname"), NULL);
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ")\n", NULL);
      if (SwigType_type(result) == T_VOID) {
	Printv(f_go_wrappers, "\t\treturn\n", NULL);
      }
      Printv(f_go_wrappers, "\t}\n", NULL);

      if (gccgo_flag) {
	Printv(f_go_wrappers, "\tdefer SwigCgocallDone()\n", NULL);
	Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL);
      }

      Printv(f_go_wrappers, "\t", NULL);
      if (SwigType_type(result) != T_VOID) {
	Printv(f_go_wrappers, "return ", NULL);
      }
      Printv(f_go_wrappers, upcall_gc_name, "(swig_p.", go_type_name, NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	SwigType *pt = Getattr(p, "type");
	Printv(f_go_wrappers, ", ", Getattr(p, "lname"), NULL);
	if (goTypeIsInterface(p, pt)) {
	  Printv(f_go_wrappers, ".Swigcptr()", NULL);
	}
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ")\n", NULL);
      Printv(f_go_wrappers, "}\n\n", NULL);

      // Define a method in the C++ director class that the C++ upcall
      // function can call.  This permits an upcall to a protected
      // method.

      String *upcall_method_name = NewString("_swig_upcall_");
      Append(upcall_method_name, name);
      if (overname) {
	Append(upcall_method_name, overname);
      }
      SwigType *rtype = Getattr(n, "classDirectorMethods:type");
      String *upcall_decl = Swig_method_decl(rtype, Getattr(n, "decl"), upcall_method_name, parms, 0, 0);
      Printv(f_c_directors_h, "  ", upcall_decl, " {\n", NULL);
      Delete(upcall_decl);

      Printv(f_c_directors_h, "    ", NULL);
      if (SwigType_type(result) != T_VOID) {
	Printv(f_c_directors_h, "return ", NULL);
      }

      String *super_call = Swig_method_call(super, parms);
      Printv(f_c_directors_h, super_call, ";\n", NULL);
      Delete(super_call);

      Printv(f_c_directors_h, "  }\n", NULL);

      // Define the C++ function that the Go function calls.

      SwigType *first_type = NULL;
      Parm *first_parm = parms;
      if (!is_static) {
	first_type = NewString("SwigDirector_");
	Append(first_type, class_name);
	SwigType_add_pointer(first_type);
	first_parm = NewParm(first_type, "p", n);
	set_nextSibling(first_parm, parms);
      }

      Swig_save("classDirectorMethod", n, "wrap:name", "wrap:action", NULL);

      Setattr(n, "wrap:name", upcall_wname);

      String *action = NewString("");
      if (SwigType_type(result) != T_VOID) {
	Printv(action, Swig_cresult_name(), " = (", SwigType_lstr(result, 0), ")", NULL);
	if (SwigType_isreference(result)) {
	  Printv(action, "&", NULL);
	}
      }
      Printv(action, Swig_cparm_name(NULL, 0), "->", upcall_method_name, "(", NULL);

      p = parms;
      int i = 0;
      while (p != NULL) {
	if (SwigType_type(Getattr(p, "type")) != T_VOID) {
	  String *pname = Swig_cparm_name(NULL, i + 1);
	  if (i > 0) {
	    Printv(action, ", ", NULL);
	  }

	  // A parameter whose type is a reference is converted into a
	  // pointer type by gcCTypeForGoValue.  We are calling a
	  // function which expects a reference so we need to convert
	  // back.
	  if (SwigType_isreference(Getattr(p, "type"))) {
	    Printv(action, "*", NULL);
	  }

	  Printv(action, pname, NULL);
	  Delete(pname);
	  i++;
	}
	p = nextSibling(p);
      }
      Printv(action, ");", NULL);
      Setattr(n, "wrap:action", action);

      if (!gccgo_flag) {
	// Write the upcall wrapper function.  This is compiled by gc
	// and calls the C++ function.
	int r = gcFunctionWrapper(n, upcall_name, upcall_name, overname, upcall_wname, first_parm, result, is_static, true);
	if (r != SWIG_OK) {
	  return r;
	}
	r = gccFunctionWrapper(n, NULL, upcall_wname, first_parm, result);
	if (r != SWIG_OK) {
	  return r;
	}
      } else {
	int r = gccgoFunctionWrapper(n, NULL, upcall_wname, first_parm, result);
	if (r != SWIG_OK) {
	  return r;
	}
      }

      Delete(first_type);
      if (first_parm != parms) {
	Delete(first_parm);
      }

      Swig_restore(n);

      // Define a function which uses the Go director type that other
      // methods in the Go type can call to get parent methods.

      Printv(f_go_wrappers, "func Director", cn, go_with_over_name, "(p ", cn, NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", NULL);
	String *tm = goType(p, Getattr(p, "type"));
	Printv(f_go_wrappers, tm, NULL);
	Delete(tm);
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ")", NULL);

      if (SwigType_type(result) != T_VOID) {
	String *tm = goType(n, result);
	Printv(f_go_wrappers, " ", tm, NULL);
	Delete(tm);
      }

      Printv(f_go_wrappers, " {\n", NULL);

      if (gccgo_flag) {
	Printv(f_go_wrappers, "\tdefer SwigCgocallDone()\n", NULL);
	Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL);
      }

      Printv(f_go_wrappers, "\t", NULL);
      if (SwigType_type(result) != T_VOID) {
	Printv(f_go_wrappers, "return ", NULL);
      }
      Printv(f_go_wrappers, upcall_gc_name, "(p.(*", director_struct_name, ").", go_type_name, NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	SwigType *pt = Getattr(p, "type");
	Printv(f_go_wrappers, ", ", Getattr(p, "lname"), NULL);
	if (goTypeIsInterface(p, pt)) {
	  Printv(f_go_wrappers, ".Swigcptr()", NULL);
	}
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ")\n", NULL);
      Printv(f_go_wrappers, "}\n\n", NULL);

      // The Go function which invokes the method.  This is called
      // from by the C++ method on the director class.

      Printv(f_go_wrappers, "func ", callback_name, "(p *", director_struct_name, NULL);

      p = parms;
      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	String *tm = goWrapperType(p, Getattr(p, "type"), false);
	Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", tm, NULL);
	Delete(tm);
	p = nextParm(p);
      }

      Printv(f_go_wrappers, ") ", NULL);
      String *result_wrapper = NULL;
      if (SwigType_type(result) != T_VOID) {
	result_wrapper = goWrapperType(n, result, true);
	Printv(f_go_wrappers, "(swig_result ", result_wrapper, ") ", NULL);
      }
      Printv(f_go_wrappers, "{\n", NULL);

      if (gccgo_flag) {
	Printv(f_go_wrappers, "\tSwigCgocallBack()\n", NULL);
	Printv(f_go_wrappers, "\tdefer SwigCgocallBackDone()\n", NULL);
      }

      Printv(f_go_wrappers, "\t", NULL);

      if (is_ignored) {
	Printv(f_go_wrappers, "return\n", NULL);
      } else {
	bool result_is_interface = false;
	if (SwigType_type(result) != T_VOID) {
	  Printv(f_go_wrappers, "return ", NULL);
	  result_is_interface = goTypeIsInterface(NULL, result);
	  if (result_is_interface) {
	    Printv(f_go_wrappers, result_wrapper, "(", NULL);
	  }
	}
	Printv(f_go_wrappers, "p.", go_with_over_name, "(", NULL);

	p = parms;
	for (int i = 0; i < parm_count; ++i) {
	  p = getParm(p);
	  if (i > 0) {
	    Printv(f_go_wrappers, ", ", NULL);
	  }
	  SwigType *pt = Getattr(p, "type");

	  // If the Go representation is an interface type class, then
	  // we are receiving a uintptr, and must convert to the
	  // interface.
	  bool is_interface = goTypeIsInterface(p, pt);
	  if (is_interface) {
	    // Passing is_result as true to goWrapperType gives us the
	    // name of the Go type we need to convert to an interface.
	    String *wt = goWrapperType(p, pt, true);
	    Printv(f_go_wrappers, wt, "(", NULL);
	    Delete(wt);
	  }

	  Printv(f_go_wrappers, Getattr(p, "lname"), NULL);

	  if (is_interface) {
	    Printv(f_go_wrappers, ")", NULL);
	  }

	  p = nextParm(p);
	}

	Printv(f_go_wrappers, ")", NULL);

	if (result_is_interface) {
	  Printv(f_go_wrappers, ".Swigcptr())", NULL);
	}

	Printv(f_go_wrappers, "\n", NULL);

	Delete(upcall_gc_name);
      }

      Printv(f_go_wrappers, "}\n\n", NULL);

      Delete(result_wrapper);

      // Build the C++ functions.

      Delete(upcall_wname);

      if (!gccgo_flag) {
	Printv(f_c_directors, "extern \"C\" void ", callback_wname, "(void*, int);\n", NULL);
      } else {
	Printv(f_c_directors, "extern \"C\" ", NULL);

	String *fnname = NewString("");
	Printv(fnname, callback_wname, "(void*", NULL);

	p = parms;
	while (p) {
	  while (checkAttribute(p, "tmap:directorin:numinputs", "0")) {
	    p = Getattr(p, "tmap:directorin:next");
	  }
	  String *cg = gccgoCTypeForGoValue(p, Getattr(p, "type"),
					    Getattr(p, "lname"));
	  Printv(fnname, ", ", cg, NULL);
	  Delete(cg);
	  p = Getattr(p, "tmap:directorin:next");
	}

	Printv(fnname, ")", NULL);

	if (SwigType_type(result) == T_VOID) {
	  Printv(f_c_directors, "void ", fnname, NULL);
	} else {
	  String *tm = gccgoCTypeForGoValue(n, result, fnname);
	  Printv(f_c_directors, tm, NULL);
	  Delete(tm);
	}

	Delete(fnname);

	Printv(f_c_directors, " __asm__(\"", go_prefix, ".", package, ".", callback_name, "\");\n", NULL);
      }

      Delete(upcall_method_name);
      Delete(go_with_over_name);
    }

    if (!is_ignored || is_pure_virtual) {
      // Declare the method for the director class.

      SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type");
      String *decl = Swig_method_decl(rtype, Getattr(n, "decl"), Getattr(n, "name"), parms, 0, 0);
      Printv(f_c_directors_h, "  virtual ", decl, NULL);
      Delete(decl);

      String *qname = NewString("");
      Printv(qname, "SwigDirector_", class_name, "::", Getattr(n, "name"), NULL);
      decl = Swig_method_decl(rtype, Getattr(n, "decl"), qname, parms, 0, 0);
      Printv(w->def, decl, NULL);
      Delete(decl);
      Delete(qname);

      String *throws = buildThrow(n);
      if (throws) {
	Printv(f_c_directors_h, " ", throws, NULL);
	Printv(w->def, " ", throws, NULL);
	Delete(throws);
      }

      Printv(f_c_directors_h, ";\n", NULL);

      Printv(w->def, " {\n", NULL);

      if (SwigType_type(result) != T_VOID) {
	Wrapper_add_local(w, "c_result", SwigType_lstr(result, "c_result"));
      }

      if (!is_ignored) {
	if (!gccgo_flag) {
	  Printv(w->code, "  struct {\n", NULL);
	  Printv(w->code, "    void *go_val;\n", NULL);

	  p = parms;
	  while (p) {
	    while (checkAttribute(p, "tmap:directorin:numinputs", "0")) {
	      p = Getattr(p, "tmap:directorin:next");
	    }
	    String *ln = Getattr(p, "lname");
	    String *cg = gcCTypeForGoValue(p, Getattr(p, "type"), ln);
	    Printv(w->code, "      ", cg, ";\n", NULL);
	    Delete(cg);
	    p = Getattr(p, "tmap:directorin:next");
	  }
	  if (SwigType_type(result) != T_VOID) {
	    Printv(w->code, "    long : 0;\n", NULL);
	    String *rname = NewString(Swig_cresult_name());
	    String *cg = gcCTypeForGoValue(n, result, rname);
	    Printv(w->code, "    ", cg, ";\n", NULL);
	    Delete(cg);
	    Delete(rname);
	  }

	  Printv(w->code, "  } swig_a;\n", NULL);
	  Printv(w->code, "  swig_a.go_val = go_val;\n", NULL);

	  p = parms;
	  while (p) {
	    while (checkAttribute(p, "tmap:directorin:numinputs", "0")) {
	      p = Getattr(p, "tmap:directorin:next");
	    }
	    String *tm = Getattr(p, "tmap:directorin");
	    if (!tm) {
	      Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file,
			   line_number, "Unable to use type %s as director method argument\n", SwigType_str(Getattr(p, "type"), 0));
	    } else {
	      String *ln = Getattr(p, "lname");
	      String *input = NewString("");
	      Printv(input, "swig_a.", ln, NULL);
	      Setattr(p, "emit:directorinput", input);
	      Replaceall(tm, "$input", input);
	      Replaceall(tm, "$owner", "0");
	      Delete(input);
	      Printv(w->code, "\t", tm, "\n", NULL);
	    }
	    p = Getattr(p, "tmap:directorin:next");
	  }

	  Printv(w->code, "  crosscall2(", callback_wname, ", &swig_a, (int) sizeof swig_a);\n", NULL);

	  if (SwigType_type(result) != T_VOID) {
	    String *result_str = NewString("c_result");
	    String *tm = Swig_typemap_lookup("directorout", n, result_str, NULL);
	    if (!tm) {
	      Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number,
			   "Unable to use type %s as director method result\n", SwigType_str(result, 0));
	    } else {
	      static const String *swig_a_result = NewStringf("swig_a.%s", Swig_cresult_name());
	      Replaceall(tm, "$input", swig_a_result);
	      Replaceall(tm, "$result", "c_result");
	      Printv(w->code, "  ", tm, "\n", NULL);
	      String *retstr = SwigType_rcaststr(result, "c_result");
	      Printv(w->code, "  return ", retstr, ";\n", NULL);
	      Delete(retstr);
	      Delete(tm);
	    }
	    Delete(result_str);
	  }

	  // The C wrapper code which calls the Go function.
	  Printv(f_gc_wrappers, "#pragma dynexport ", callback_wname, " ", callback_wname, "\n", NULL);
	  Printv(f_gc_wrappers, "extern void \xc2\xb7", callback_name, "();\n", NULL);
	  Printv(f_gc_wrappers, "void\n", NULL);
	  Printv(f_gc_wrappers, callback_wname, "(void *a, int32 n)\n", NULL);
	  Printv(f_gc_wrappers, "{\n", NULL);
	  Printv(f_gc_wrappers, "\truntime\xc2\xb7" "cgocallback(\xc2\xb7", callback_name, ", a, n);\n", NULL);
	  Printv(f_gc_wrappers, "}\n\n", NULL);
	} else {
	  if (SwigType_type(result) != T_VOID) {
	    String *r = NewString(Swig_cresult_name());
	    String *tm = gccgoCTypeForGoValue(n, result, r);
	    Wrapper_add_local(w, r, tm);
	    Delete(tm);
	    Delete(r);
	  }

	  String *args = NewString("");

	  p = parms;
	  while (p) {
	    while (checkAttribute(p, "tmap:directorin:numinputs", "0")) {
	      p = Getattr(p, "tmap:directorin:next");
	    }

	    String *pn = NewString("g");
	    Append(pn, Getattr(p, "lname"));
	    Setattr(p, "emit:input", pn);

	    String *tm = gccgoCTypeForGoValue(n, Getattr(p, "type"), pn);
	    Wrapper_add_local(w, pn, tm);
	    Delete(tm);

	    tm = Getattr(p, "tmap:directorin");
	    if (!tm) {
	      Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file,
			   line_number, "Unable to use type %s as director method argument\n", SwigType_str(Getattr(p, "type"), 0));
	    } else {
	      Replaceall(tm, "$input", pn);
	      Replaceall(tm, "$owner", 0);
	      Printv(w->code, "  ", tm, "\n", NULL);

	      Printv(args, ", ", pn, NULL);
	    }

	    p = Getattr(p, "tmap:directorin:next");
	  }

	  Printv(w->code, "  ", NULL);
	  if (SwigType_type(result) != T_VOID) {
	    Printv(w->code, Swig_cresult_name(), " = ", NULL);
	  }
	  Printv(w->code, callback_wname, "(go_val", args, ");\n", NULL);

	  if (SwigType_type(result) != T_VOID) {
	    String *result_str = NewString("c_result");
	    String *tm = Swig_typemap_lookup("directorout", n, result_str, NULL);
	    if (!tm) {
	      Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number,
			   "Unable to use type %s as director method result\n", SwigType_str(result, 0));
	    } else {
	      Replaceall(tm, "$input", Swig_cresult_name());
	      Replaceall(tm, "$result", "c_result");
	      Printv(w->code, "  ", tm, "\n", NULL);
	      String *retstr = SwigType_rcaststr(result, "c_result");
	      Printv(w->code, "  return ", retstr, ";\n", NULL);
	      Delete(retstr);
	      Delete(tm);
	    }
	    Delete(result_str);
	  }
	}

	/* Marshal outputs */
	for (p = parms; p;) {
	  String *tm;
	  if ((tm = Getattr(p, "tmap:directorargout"))) {
	    Replaceall(tm, "$result", "jresult");
	    Replaceall(tm, "$input", Getattr(p, "emit:directorinput"));
	    Printv(w->code, tm, "\n", NIL);
	    p = Getattr(p, "tmap:directorargout:next");
	  } else {
	    p = nextSibling(p);
	  }
	}
      } else {
	assert(is_pure_virtual);
	Printv(w->code, "  _swig_gopanic(\"call to pure virtual function ", Getattr(parent, "sym:name"), name, "\");\n", NULL);
	if (SwigType_type(result) != T_VOID) {
	  String *retstr = SwigType_rcaststr(result, "c_result");
	  Printv(w->code, "  return ", retstr, ";\n", NULL);
	  Delete(retstr);
	}
      }

      Printv(w->code, "}", NULL);

      Replaceall(w->code, "$symname", symname);
      Wrapper_print(w, f_c_directors);
    }

    Delete(cn);
    Delete(go_type_name);
    Delete(director_struct_name);
    Delete(interface_name);
    Delete(upcall_name);
    Delete(callback_wname);
    Delete(go_name);
    DelWrapper(w);

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * classDirectorEnd
   *
   * Complete support for a director class.
   * ------------------------------------------------------------ */

  int classDirectorEnd(Node *n) {
    (void) n;

    Printv(f_c_directors_h, " private:\n", NULL);
    Printv(f_c_directors_h, "  void *go_val;\n", NULL);
    Printv(f_c_directors_h, "};\n\n", NULL);

    class_name = NULL;
    class_node = NULL;

    Delete(class_receiver);
    class_receiver = NULL;

    Delete(class_methods);
    class_methods = NULL;

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * classDirectorDisown
   *
   * I think Go does not require a disown method.
   * ------------------------------------------------------------ */

  int classDirectorDisown(Node *n) {
    (void) n;
    return SWIG_OK;
  }

  /*----------------------------------------------------------------------
   * buildThrow()
   *
   * Build and return a throw clause if needed.
   *--------------------------------------------------------------------*/

  String *buildThrow(Node *n) {
    ParmList *throw_parm_list = Getattr(n, "throws");
    if (!throw_parm_list && !Getattr(n, "throw"))
      return NULL;
    String *ret = NewString("throw(");
    if (throw_parm_list) {
      Swig_typemap_attach_parms("throws", throw_parm_list, NULL);
    }
    bool first = true;
    for (Parm *p = throw_parm_list; p; p = nextSibling(p)) {
      if (Getattr(p, "tmap:throws")) {
	if (first) {
	  first = false;
	} else {
	  Printv(ret, ", ", NULL);
	}
	String *s = SwigType_str(Getattr(p, "type"), 0);
	Printv(ret, s, NULL);
	Delete(s);
      }
    }
    Printv(ret, ")", NULL);
    return ret;
  }

  /*----------------------------------------------------------------------
   * extraDirectorProtectedCPPMethodsRequired()
   *
   * We don't need to check upcall when calling methods.
   *--------------------------------------------------------------------*/

  bool extraDirectorProtectedCPPMethodsRequired() const {
    return false;
  }

  /*----------------------------------------------------------------------
   * makeDispatchFunction
   *
   * Make a dispatch function for an overloaded C++ function.  The
   * receiver parameter is the receiver for a method, unless is_upcall
   * is true.  If is_upcall is true, then the receiver parameter is
   * the type of the first argument to the function.
   *--------------------------------------------------------------------*/

  int makeDispatchFunction(Node *n, String *go_name, String *receiver, bool is_static, SwigType *director_struct, bool is_upcall) {
    bool is_director = director_struct ? true : false;

    String *nodetype = Getattr(n, "nodeType");
    bool is_constructor = Cmp(nodetype, "constructor") == 0;
    bool is_destructor = Cmp(nodetype, "destructor") == 0;

    bool can_use_receiver = (!is_constructor && !is_destructor && !is_upcall);

    bool use_receiver = (!is_static && can_use_receiver);

    bool add_to_interface = (interfaces && !is_constructor && !is_destructor && !is_static && !is_upcall);

    List *dispatch = Swig_overload_rank(n, false);
    int nfunc = Len(dispatch);

    SwigType *all_result;
    bool mismatch;
    if (is_constructor) {
      assert(!is_upcall);
      if (!is_director) {
	all_result = Copy(Getattr(class_node, "classtypeobj"));
      } else {
	all_result = Copy(director_struct);
      }
      mismatch = false;
    } else {
      all_result = NULL;
      mismatch = false;
      bool any_void = false;
      for (int i = 0; i < nfunc; ++i) {
	Node *nn = Getitem(dispatch, i);
	Node *ni = Getattr(nn, "directorNode") ? Getattr(nn, "directorNode") : nn;
	SwigType *result = Getattr(ni, "go:type");
	assert(result);

	if (SwigType_type(result) == T_VOID) {
	  if (all_result) {
	    mismatch = true;
	  }
	  any_void = true;
	} else {
	  if (any_void) {
	    mismatch = true;
	  } else if (!all_result) {
	    all_result = Copy(result);
	  } else if (Cmp(result, all_result) != 0) {
	    mismatch = true;
	  }
	}
      }
      if (mismatch) {
	Delete(all_result);
	all_result = NULL;
      } else if (all_result) {
	;
      } else {
	all_result = NewString("void");
      }
    }

    Printv(f_go_wrappers, "func ", NULL);

    if (receiver && use_receiver) {
      Printv(f_go_wrappers, "(p ", receiver, ") ", NULL);
    }

    Printv(f_go_wrappers, go_name, "(", NULL);
    if (is_director && is_constructor) {
      Printv(f_go_wrappers, "abi interface{}, ", NULL);
      assert(!add_to_interface);
    }
    if (is_upcall) {
      Printv(f_go_wrappers, "p *", receiver, ", ", NULL);
      assert(!add_to_interface);
    }
    Printv(f_go_wrappers, "a ...interface{})", NULL);

    if (add_to_interface) {
      Printv(interfaces, "\t", go_name, "(a ...interface{})", NULL);
    }

    if (mismatch) {
      Printv(f_go_wrappers, " interface{}", NULL);
      if (add_to_interface) {
	Printv(interfaces, " interface{}", NULL);
      }
    } else if (all_result && SwigType_type(all_result) != T_VOID) {
      if (is_director && is_constructor) {
	Printv(f_go_wrappers, " ", receiver, NULL);
	if (add_to_interface) {
	  Printv(interfaces, " ", receiver, NULL);
	}
      } else {
	String *tm = goType(n, all_result);
	Printv(f_go_wrappers, " ", tm, NULL);
	if (add_to_interface) {
	  Printv(interfaces, " ", tm, NULL);
	}
	Delete(tm);
      }
    }
    Printv(f_go_wrappers, " {\n", NULL);
    if (add_to_interface) {
      Printv(interfaces, "\n", NULL);
    }

    Printv(f_go_wrappers, "\targc := len(a)\n", NULL);

    for (int i = 0; i < nfunc; ++i) {
      int fn = 0;
      Node *nn = Getitem(dispatch, i);
      Node *ni = Getattr(nn, "directorNode") ? Getattr(nn, "directorNode") : nn;
      Parm *pi = Getattr(ni, "wrap:parms");

      // If we are using a receiver, we want to ignore a leading self
      // parameter.  Because of the way this is called, there may or
      // may not be a self parameter at this point.
      if (use_receiver && pi && Getattr(pi, "self")) {
	pi = getParm(pi);
	if (pi) {
	  pi = nextParm(pi);
	}
      }

      int num_required = emit_num_required(pi);
      int num_arguments = emit_num_arguments(pi);
      bool varargs = emit_isvarargs(pi) ? true : false;

      if (varargs) {
	Printf(f_go_wrappers, "\tif argc >= %d {\n", num_required);
      } else {
	if (num_required == num_arguments) {
	  Printf(f_go_wrappers, "\tif argc == %d {\n", num_required);
	} else {
	  Printf(f_go_wrappers, "\tif argc >= %d && argc <= %d {\n", num_required, num_arguments);
	}
      }

      // Build list of collisions with the same number of arguments.
      List *coll = NewList();
      for (int k = i + 1; k < nfunc; ++k) {
	Node *nnk = Getitem(dispatch, k);
	Node *nk = Getattr(nnk, "directorNode") ? Getattr(nnk, "directorNode") : nnk;
	Parm *pk = Getattr(nk, "wrap:parms");
	if (use_receiver && pk && Getattr(pk, "self")) {
	  pk = getParm(pk);
	  if (pk) {
	    pk = nextParm(pk);
	  }
	}
	int nrk = emit_num_required(pk);
	int nak = emit_num_arguments(pk);
	if ((nrk >= num_required && nrk <= num_arguments)
	    || (nak >= num_required && nak <= num_arguments)
	    || (nrk <= num_required && nak >= num_arguments)
	    || (varargs && nrk >= num_required)) {
	  Append(coll, nk);
	}
      }

      int num_braces = 0;
      if (Len(coll) > 0 && num_arguments > 0) {
	int j = 0;
	Parm *pj = pi;
	while (pj) {
	  pj = getParm(pj);
	  if (!pj) {
	    break;
	  }

	  // If all the wrappers have the same type in this position,
	  // we can omit the check.
	  SwigType *tm = goWrapperType(pj, Getattr(pj, "type"), true);
	  bool emitcheck = false;
	  for (int k = 0; k < Len(coll) && !emitcheck; ++k) {
	    Node *nk = Getitem(coll, k);
	    Parm *pk = Getattr(nk, "wrap:parms");
	    if (use_receiver && pk && Getattr(pk, "self")) {
	      pk = getParm(pk);
	      if (pk) {
		pk = nextParm(pk);
	      }
	    }
	    int nak = emit_num_arguments(pk);
	    if (nak <= j)
	      continue;
	    int l = 0;
	    Parm *pl = pk;
	    while (pl && l <= j) {
	      pl = getParm(pl);
	      if (!pl) {
		break;
	      }
	      if (l == j) {
		SwigType *tml = goWrapperType(pl, Getattr(pl, "type"), true);
		if (Cmp(tm, tml) != 0) {
		  emitcheck = true;
		}
		Delete(tml);
	      }
	      pl = nextParm(pl);
	      ++l;
	    }
	  }

	  if (emitcheck) {
	    if (j >= num_required) {
	      Printf(f_go_wrappers, "\t\tif argc > %d {\n", j);
	      ++num_braces;
	    }

	    fn = i + 1;
	    Printf(f_go_wrappers, "\t\tif _, ok := a[%d].(%s); !ok {\n", j, tm);
	    Printf(f_go_wrappers, "\t\t\tgoto check_%d\n", fn);
	    Printv(f_go_wrappers, "\t\t}\n", NULL);
	  }

	  Delete(tm);

	  pj = nextParm(pj);

	  ++j;
	}
      }

      for (; num_braces > 0; --num_braces) {
	Printv(f_go_wrappers, "\t\t}\n", NULL);
      }

      // We may need to generate multiple calls if there are variable
      // argument lists involved.  Build the start of the call.

      String *start = NewString("");

      SwigType *result = Getattr(ni, "go:type");

      if (is_constructor) {
	result = all_result;
      } else if (is_destructor) {
	result = NULL;
      }

      if (result && SwigType_type(result) != T_VOID && (!all_result || SwigType_type(all_result) != T_VOID)) {
	Printv(start, "return ", NULL);
      }

      bool advance_parm = false;

      if (receiver && use_receiver) {
	Printv(start, "p.", go_name, NULL);
      } else if (can_use_receiver && !isStatic(ni) && pi && Getattr(pi, "self")) {
	// This is an overload of a static function and a non-static
	// function.
	assert(num_required > 0);
	SwigType *tm = goWrapperType(pi, Getattr(pi, "type"), true);
	String *nm = buildGoName(Getattr(ni, "sym:name"), false, isFriend(ni));
	Printv(start, "a[0].(", tm, ").", nm, NULL);
	Delete(nm);
	Delete(tm);
	advance_parm = true;
      } else {
	Printv(start, go_name, NULL);
      }

      Printv(start, Getattr(ni, "sym:overname"), "(", NULL);

      bool need_comma = false;

      if (is_director && is_constructor) {
	Printv(start, "abi", NULL);
	need_comma = true;
      }
      if (is_upcall) {
	Printv(start, "p", NULL);
	need_comma = true;
      }
      Parm *p = pi;
      int pn = 0;
      if (advance_parm) {
	p = getParm(p);
	if (p) {
	  p = nextParm(p);
	}
	++pn;
      }
      while (pn < num_required) {
	p = getParm(p);

	if (need_comma) {
	  Printv(start, ", ", NULL);
	}

	SwigType *tm = goType(p, Getattr(p, "type"));
	Printf(start, "a[%d].(%s)", pn, tm);
	Delete(tm);

	need_comma = true;
	++pn;
	p = nextParm(p);
      }

      String *end = NULL;
      if (!result || SwigType_type(result) == T_VOID || (all_result && SwigType_type(all_result) == T_VOID)) {
	end = NewString("");
	Printv(end, "return", NULL);
	if (!all_result || SwigType_type(all_result) != T_VOID) {
	  Printv(end, " 0", NULL);
	}
      }

      if (num_required == num_arguments) {
	Printv(f_go_wrappers, "\t\t", start, ")\n", NULL);
	if (end) {
	  Printv(f_go_wrappers, "\t\t", end, "\n", NULL);
	}
      } else {
	Printv(f_go_wrappers, "\t\tswitch argc {\n", NULL);
	for (int j = num_required; j <= num_arguments; ++j) {
	  Printf(f_go_wrappers, "\t\tcase %d:\n", j);
	  Printv(f_go_wrappers, "\t\t\t", start, NULL);
	  bool nc = need_comma;
	  for (int k = num_required; k < j; ++k) {
	    if (nc) {
	      Printv(f_go_wrappers, ", ", NULL);
	    }
	    Printf(f_go_wrappers, "a[%d]", k);
	    nc = true;
	  }
	  Printv(f_go_wrappers, ")\n", NULL);
	  if (end) {
	    Printv(f_go_wrappers, "\t\t\t", end, "\n", NULL);
	  }
	}
	Printv(f_go_wrappers, "\t\t}\n", NULL);
      }

      Printv(f_go_wrappers, "\t}\n", NULL);

      if (fn != 0) {
	Printf(f_go_wrappers, "check_%d:\n", fn);
      }

      Delete(coll);
    }

    Printv(f_go_wrappers, "\tpanic(\"No match for overloaded function call\")\n", NULL);
    Printv(f_go_wrappers, "}\n\n", NULL);

    Delete(all_result);
    Delete(dispatch);

    return SWIG_OK;
  }

  /* ----------------------------------------------------------------------
   * checkFunctionVisibility()
   *
   * Return true if we should write out a function based on its
   * visibility, false otherwise.
   * ---------------------------------------------------------------------- */

  bool checkFunctionVisibility(Node *n, Node *parent) {
    // Write out a public function.
    if (is_public(n))
      return true;
    // Don't write out a private function.
    if (is_private(n))
      return false;
    // Write a protected function for a director class in
    // dirprot_mode.
    if (parent == NULL) {
      return false;
    }
    if (dirprot_mode() && Swig_directorclass(parent))
      return true;
    // Otherwise don't write out a protected function.
    return false;
  }


  /* ----------------------------------------------------------------------
   * exportedName()
   *
   * Given a C/C++ name, return a name in Go which will be exported.
   * If the first character is an upper case letter, this returns a
   * copy of its argment.  If the first character is a lower case
   * letter, this forces it to upper case.  Otherwise, this prepends
   * 'X'.
   * ---------------------------------------------------------------------- */

  String *exportedName(String *name) {
    String *copy = Copy(name);
    char c = *Char(copy);
    if (islower(c)) {
      char l[2];
      char u[2];
      l[0] = c;
      l[1] = '\0';
      u[0] = toupper(c);
      u[1] = '\0';
      Replace(copy, l, u, DOH_REPLACE_FIRST);
    } else if (!isalpha(c)) {
      char l[2];
      char u[3];
      l[0] = c;
      l[1] = '\0';
      u[0] = 'X';
      u[1] = c;
      u[2] = '\0';
      Replace(copy, l, u, DOH_REPLACE_FIRST);
    }
    String *ret = Swig_name_mangle(copy);
    Delete(copy);
    return ret;
  }

  /* ----------------------------------------------------------------------
   * removeClassname()
   *
   * If the name starts with the current class name, followed by an
   * underscore, remove it.  If there is no current class name, this
   * simply returns a copy of the name.  This undoes Swig's way of
   * recording the class name in a member name.
   * ---------------------------------------------------------------------- */

  String *removeClassname(String *name) {
    String *copy = Copy(name);
    if (class_name) {
      char *p = Char(name);
      if (Strncmp(name, class_name, Len(class_name)) == 0 && p[Len(class_name)] == '_') {
	Replace(copy, class_name, "", DOH_REPLACE_FIRST);
	Replace(copy, "_", "", DOH_REPLACE_FIRST);
      }
    }
    return copy;
  }

  /* ----------------------------------------------------------------------
   * buildGoName()
   *
   * Build the name to use for an ordinary function, variable, or
   * whatever in Go.  The name argument is something like the sym:name
   * attribute of the node.  If is_static is false, this could be a
   * method, and the returned name will be the name of the
   * method--i.e., it will not include the class name.
   * ---------------------------------------------------------------------- */

  String *buildGoName(String *name, bool is_static, bool is_friend) {
    String *nw = NewString("");
    if (is_static && !is_friend && class_name) {
      String *c1 = exportedName(class_name);
      Append(nw, c1);
      Delete(c1);
    }
    String *c2 = removeClassname(name);
    String *c3 = exportedName(c2);
    Append(nw, c3);
    Delete(c2);
    Delete(c3);
    String *ret = Swig_name_mangle(nw);
    Delete(nw);
    return ret;
  }

  /* ----------------------------------------------------------------------
   * buildGoWrapperName()
   *
   * Build the name to use for a Go wrapper function.  This is a
   * function called by the real Go function in order to convert C++
   * classes from interfaces to pointers, and other such conversions
   * between the Go type and the C++ type.
   * ---------------------------------------------------------------------- */

  String *buildGoWrapperName(String *name, String *overname) {
    String *s1 = NewString("_swig_wrap_");
    Append(s1, name);
    String *s2 = Swig_name_mangle(s1);
    Delete(s1);
    if (overname) {
      Append(s2, overname);
    }
    return s2;
  }

  /* ----------------------------------------------------------------------
   * checkNameConflict()
   *
   * Check for a name conflict on the name we are going to use in Go.
   * These conflicts are likely because of the enforced
   * capitalization.  When we find one, issue a warning and return
   * false.  If the name is OK, return true.
   * ---------------------------------------------------------------------- */

  bool checkNameConflict(String* name, Node* n, const_String_or_char_ptr scope) {
    Node *lk = symbolLookup(name, scope);
    if (lk) {
      String *n1 = Getattr(n, "sym:name");
      if (!n1) {
	n1 = Getattr(n, "name");
      }
      String *n2 = Getattr(lk, "sym:name");
      if (!n2) {
	n2 = Getattr(lk, "name");
      }
      Swig_warning(WARN_GO_NAME_CONFLICT, input_file, line_number,
		   "Ignoring '%s' due to Go name ('%s') conflict with '%s'\n",
		   n1, name, n2);
      return false;
    }
    bool r = addSymbol(name, n, scope) ? true : false;
    assert(r);
    return true;
  }

  /* ----------------------------------------------------------------------
   * checkIgnoredParameters()
   *
   * If any of the parameters of this function, or the return type,
   * are ignored due to a name conflict, give a warning and return
   * false.
   * ---------------------------------------------------------------------- */

  bool checkIgnoredParameters(Node *n, String *go_name) {
    ParmList *parms = Getattr(n, "parms");
    if (parms) {
      Wrapper *dummy = NewWrapper();
      emit_attach_parmmaps(parms, dummy);
      int parm_count = emit_num_arguments(parms);
      Parm *p = parms;

      for (int i = 0; i < parm_count; ++i) {
	p = getParm(p);
	if (!checkIgnoredType(n, go_name, Getattr(p, "type"))) {
	  DelWrapper(dummy);
	  return false;
	}
	p = nextParm(p);
      }

      DelWrapper(dummy);
    }

    if (!checkIgnoredType(n, go_name, Getattr(n, "type"))) {
      return false;
    }

    return true;
  }

  /* ----------------------------------------------------------------------
   * checkIgnoredType()
   *
   * If this type is being ignored due to a name conflict, give a
   * warning and return false.
   * ---------------------------------------------------------------------- */

  bool checkIgnoredType(Node *n, String *go_name, SwigType *type) {
    if (hasGoTypemap(n, type)) {
      return true;
    }

    SwigType *t = SwigType_typedef_resolve_all(type);

    bool ret = true;
    bool is_conflict = false;
    Node *e = Language::enumLookup(t);
    if (e) {
      if (GetFlag(e, "go:conflict")) {
	is_conflict = true;
      }
    } else if (SwigType_issimple(t)) {
      Node *cn = classLookup(t);
      if (cn) {
	if (GetFlag(cn, "go:conflict")) {
	  is_conflict = true;
	}
      }
    } else if (SwigType_ispointer(t) || SwigType_isarray(t) || SwigType_isqualifier(t) || SwigType_isreference(t)) {
      SwigType *r = Copy(t);
      if (SwigType_ispointer(r)) {
	SwigType_del_pointer(r);
      } else if (SwigType_isarray(r)) {
	SwigType_del_array(r);
      } else if (SwigType_isqualifier(r)) {
	SwigType_del_qualifier(r);
      } else {
	SwigType_del_reference(r);
      }

      if (!checkIgnoredType(n, go_name, r)) {
	ret = false;
      }

      Delete(r);
    }

    if (is_conflict) {
      String *s = SwigType_str(t, NULL);
      Swig_warning(WARN_GO_NAME_CONFLICT, input_file, line_number,
		   "Ignoring '%s' (Go name '%s') due to Go name conflict for parameter or result type '%s'\n",
		   Getattr(n, "name"), go_name, s);
      Delete(s);
      ret = false;
    }

    Delete(t);

    return ret;
  }

  /* ----------------------------------------------------------------------
   * goType()
   *
   * Given a SWIG type, return a string for the type in Go.
   * ---------------------------------------------------------------------- */

  String *goType(Node *n, SwigType *type) {
    return goTypeWithInfo(n, type, NULL);
  }

  /* ----------------------------------------------------------------------
   * goTypeWithInfo()
   *
   * Like goType, but return some more information.
   *
   * If the p_is_interface parameter is not NULL, this sets
   * *p_is_interface to indicate whether this type is going to be
   * represented by a Go interface type.  These are cases where the Go
   * code needs to make some adjustments when passing values back and
   * forth with C/C++.
   * ---------------------------------------------------------------------- */

  String *goTypeWithInfo(Node *n, SwigType *type, bool *p_is_interface) {
    if (p_is_interface) {
      *p_is_interface = false;
    }

    String *ret;
    if (n && Cmp(type, Getattr(n, "type")) == 0) {
      ret = NULL;
      if (Strcmp(Getattr(n, "nodeType"), "parm") == 0) {
	ret = Getattr(n, "tmap:gotype");
      }
      if (!ret) {
	ret = Swig_typemap_lookup("gotype", n, "", NULL);
      }
    } else {
      Parm *p = NewParm(type, "goType", n);
      ret = Swig_typemap_lookup("gotype", p, "", NULL);
      Delete(p);
    }

    if (ret && Strstr(ret, "$gotypename") != 0) {
      ret = NULL;
    }

    if (ret) {
      return Copy(ret);
    }

    SwigType *t = SwigType_typedef_resolve_all(type);

    Node *e = Language::enumLookup(t);
    if (e) {
      ret = goEnumName(e);
    } else if (Strcmp(t, "enum ") == 0) {
      ret = NewString("int");
    } else if (SwigType_isfunctionpointer(type) || SwigType_isfunction(type)) {
      ret = NewString("_swig_fnptr");
    } else if (SwigType_ismemberpointer(type)) {
      ret = NewString("_swig_memberptr");
    } else if (SwigType_issimple(t)) {
      Node *cn = classLookup(t);
      if (cn) {
	ret = Getattr(cn, "sym:name");
	if (!ret) {
	  ret = Getattr(cn, "name");
	}
	ret = exportedName(ret);

	Node *cnmod = Getattr(cn, "module");
	if (!cnmod || Strcmp(Getattr(cnmod, "name"), module) == 0) {
	  Setattr(undefined_types, t, t);
	} else {
	  String *nw = NewString("");
	  Printv(nw, Getattr(cnmod, "name"), ".", ret, NULL);
	  Delete(ret);
	  ret = nw;
	}
      } else {
	// SWIG does not know about this type.
	ret = exportedName(t);
	Setattr(undefined_types, t, t);
      }
      if (p_is_interface) {
	*p_is_interface = true;
      }
    } else if (SwigType_ispointer(t) || SwigType_isarray(t)) {
      SwigType *r = Copy(t);
      if (SwigType_ispointer(r)) {
	SwigType_del_pointer(r);
      } else {
	SwigType_del_array(r);
      }

      if (SwigType_type(r) == T_VOID) {
	ret = NewString("uintptr");
      } else {
	bool is_interface;
	String *base = goTypeWithInfo(n, r, &is_interface);

	// At the Go level, an unknown or class type is handled as an
	// interface wrapping a pointer.  This means that if a
	// function returns the C type X, we will be wrapping the C
	// type X*.  In Go we will call that type X.  That means that
	// if a C function expects X*, we can pass the Go type X.  And
	// that means that when we see the C type X*, we should use
	// the Go type X.

	// The is_interface variable tells us this.  However, it will
	// be true both for the case of X and for the case of X*.  If
	// r is a pointer here, then we are looking at X**.  There is
	// really no good way for us to handle that.
	bool is_pointer_to_pointer = false;
	if (is_interface) {
	  SwigType *c = Copy(r);
	  if (SwigType_isqualifier(c)) {
	    SwigType_del_qualifier(c);
	    if (SwigType_ispointer(c) || SwigType_isarray(c)) {
	      is_pointer_to_pointer = true;
	    }
	  }
	  Delete(c);
	}

	if (is_interface) {
	  if (!is_pointer_to_pointer) {
	    ret = base;
	    if (p_is_interface) {
	      *p_is_interface = true;
	    }
	  } else {
	    ret = NewString("uintptr");
	  }
	} else {
	  ret = NewString("*");
	  Append(ret, base);
	  Delete(base);
	}
      }

      Delete(r);
    } else if (SwigType_isreference(t)) {
      SwigType *r = Copy(t);
      SwigType_del_reference(r);

      // If this is a const reference, and we are looking at a pointer
      // to it, then we just use the pointer we already have.
      bool add_pointer = true;
      if (SwigType_isqualifier(r)) {
	String *q = SwigType_parm(r);
	if (Strcmp(q, "const") == 0) {
	  SwigType *c = Copy(r);
	  SwigType_del_qualifier(c);
	  if (SwigType_ispointer(c)) {
	    add_pointer = false;
	  }
	  Delete(c);
	}
      }
      if (add_pointer) {
	SwigType_add_pointer(r);
      }
      ret = goTypeWithInfo(n, r, p_is_interface);
      Delete(r);
    } else if (SwigType_isqualifier(t)) {
      SwigType *r = Copy(t);
      SwigType_del_qualifier(r);
      ret = goTypeWithInfo(n, r, p_is_interface);
      Delete(r);
    } else if (SwigType_isvarargs(t)) {
      ret = NewString("[]interface{}");
    }

    Delete(t);

    if (!ret) {
      Swig_warning(WARN_LANG_NATIVE_UNIMPL, input_file, line_number, "No Go typemap defined for %s\n", SwigType_str(type, 0));
      ret = NewString("uintptr");
    }

    return ret;
  }

  /* ----------------------------------------------------------------------
   * goWrapperType()
   *
   * Given a type, return a string for the type to use for the wrapped
   * Go function.  This function exists because for a C++ class we
   * need to convert interface and reference types.
   * ---------------------------------------------------------------------- */

  String *goWrapperType(Node *n, SwigType *type, bool is_result) {
    bool is_interface;
    String *ret = goTypeWithInfo(n, type, &is_interface);

    // If this is an interface, we want to pass the real type.
    if (is_interface) {
      Delete(ret);
      if (!is_result) {
	ret = NewString("uintptr");
      } else {
	SwigType *ty = SwigType_typedef_resolve_all(type);
	while (true) {
	  if (SwigType_ispointer(ty)) {
	    SwigType_del_pointer(ty);
	  } else if (SwigType_isarray(ty)) {
	    SwigType_del_array(ty);
	  } else if (SwigType_isreference(ty)) {
	    SwigType_del_reference(ty);
	  } else if (SwigType_isqualifier(ty)) {
	    SwigType_del_qualifier(ty);
	  } else {
	    break;
	  }
	}
	assert(SwigType_issimple(ty));
	String *p = goCPointerType(ty, true);
	Delete(ty);
	ret = p;
      }
    }

    return ret;
  }

  /* ----------------------------------------------------------------------
   * goCPointerType()
   *
   * Return the name of the Go type to use for the C pointer value.
   * The regular C type is the name of an interface type which wraps a
   * pointer whose name is returned by this function.
   * ---------------------------------------------------------------------- */

  String *goCPointerType(SwigType *type, bool add_to_hash) {
    SwigType *ty = SwigType_typedef_resolve_all(type);
    Node *cn = classLookup(ty);
    String *ex;
    String *ret;
    if (!cn) {
      if (add_to_hash) {
	Setattr(undefined_types, ty, ty);
      }
      ret = NewString("Swigcptr");
      ex = exportedName(ty);
      Append(ret, ex);
    } else {
      String *cname = Getattr(cn, "sym:name");
      if (!cname) {
	cname = Getattr(cn, "name");
      }
      ex = exportedName(cname);
      Node *cnmod = Getattr(cn, "module");
      if (!cnmod || Strcmp(Getattr(cnmod, "name"), module) == 0) {
	if (add_to_hash) {
	  Setattr(undefined_types, ty, ty);
	}
	ret = NewString("Swigcptr");
	Append(ret, ex);
      } else {
	ret = NewString("");
	Printv(ret, Getattr(cnmod, "name"), ".Swigcptr", ex, NULL);
      }
    }
    Delete(ty);
    Delete(ex);
    return ret;
  }

  /* ----------------------------------------------------------------------
   * gcCTypeForGoValue()
   *
   * Given a type, return the C/C++ type which will be used to catch
   * the value in Go.  This is the 6g/8g version.
   * ---------------------------------------------------------------------- */

  String *gcCTypeForGoValue(Node *n, SwigType *type, String *name) {
    bool is_interface;
    String *gt = goTypeWithInfo(n, type, &is_interface);
    bool is_string = Strcmp(gt, "string") == 0;
    bool is_slice = Strncmp(gt, "[]", 2) == 0;
    bool is_function = Strcmp(gt, "_swig_fnptr") == 0;
    bool is_member = Strcmp(gt, "_swig_memberptr") == 0;
    bool is_complex64 = Strcmp(gt, "complex64") == 0;
    bool is_complex128 = Strcmp(gt, "complex128") == 0;
    bool is_int8 = false;
    bool is_int16 = false;
    bool is_int = Strcmp(gt, "int") == 0 || Strcmp(gt, "uint") == 0;
    bool is_int32 = false;
    bool is_int64 = false;
    bool is_float32 = false;
    bool is_float64 = false;
    if ((n != NULL && Getattr(n, "tmap:gotype") != NULL) || hasGoTypemap(n, type)) {
      is_int8 = Strcmp(gt, "int8") == 0 || Strcmp(gt, "uint8") == 0 || Strcmp(gt, "byte") == 0;
      is_int16 = Strcmp(gt, "int16") == 0 || Strcmp(gt, "uint16") == 0;
      is_int32 = Strcmp(gt, "int32") == 0 || Strcmp(gt, "uint32") == 0;
      is_int64 = Strcmp(gt, "int64") == 0 || Strcmp(gt, "uint64") == 0;
      is_float32 = Strcmp(gt, "float32") == 0;
      is_float64 = Strcmp(gt, "float64") == 0;
    }
    Delete(gt);

    String *ret;
    if (is_string) {
      // Note that we don't turn a reference to a string into a
      // pointer to a string.  Strings are immutable anyhow.
      ret = NewString("_gostring_ ");
      Append(ret, name);
      return ret;
    } else if (is_slice) {
      // Slices are always passed as a _goslice_, whether or not references
      // are involved.
      ret = NewString("_goslice_ ");
      Append(ret, name);
      return ret;
    } else if (is_function || is_member) {
      ret = NewString("void *");
      Append(ret, name);
      return ret;
    } else if (is_complex64) {
      ret = NewString("_Complex float ");
    } else if (is_complex128) {
      ret = NewString("_Complex double ");
    } else if (is_interface) {
      SwigType *t = SwigType_typedef_resolve_all(type);
      SwigType_strip_qualifiers(t);
      if (SwigType_ispointer(t)) {
	SwigType_del_pointer(t);
	SwigType_strip_qualifiers(t);
      }
      if (SwigType_isreference(t)) {
	SwigType_del_reference(t);
	SwigType_strip_qualifiers(t);
      }
      SwigType_add_pointer(t);
      ret = SwigType_lstr(t, name);
      Delete(t);
      return ret;
    } else {
      SwigType *t = SwigType_typedef_resolve_all(type);
      if (SwigType_isreference(t)) {
	// A const reference to a known type, or to a pointer, is not
	// mapped to a pointer.
	SwigType_del_reference(t);
	if (SwigType_isqualifier(t)) {
	  String *q = SwigType_parm(t);
	  if (Strcmp(q, "const") == 0) {
	    SwigType_del_qualifier(t);
	    if (hasGoTypemap(n, t) || SwigType_ispointer(t)) {
	      if (is_int) {
		ret = NewString("intgo ");
		Append(ret, name);
	      } else {
		ret = SwigType_lstr(t, name);
	      }
	      Delete(q);
	      Delete(t);
	      return ret;
	    }
	  }
	  Delete(q);
	}
      }

      if (Language::enumLookup(t) != NULL || Strcmp(t, "enum ") == 0) {
	is_int = true;
      }

      Delete(t);
      if (is_int8) {
	ret = NewString("char ");
      } else if (is_int16) {
	ret = NewString("short ");
      } else if (is_int) {
	ret = NewString("intgo ");
      } else if (is_int32) {
	ret = NewString("int ");
      } else if (is_int64) {
	ret = NewString("long long ");
      } else if (is_float32) {
	ret = NewString("float ");
      } else if (is_float64) {
	ret = NewString("double ");
      } else {
	return SwigType_lstr(type, name);
      }
    }

    if (SwigType_isreference(type)) {
      Append(ret, "* ");
    }
    Append(ret, name);
    return ret;
  }

  /* ----------------------------------------------------------------------
   * gccgoCTypeForGoValue()
   *
   * Given a type, return the C/C++ type which will be used to catch
   * the value in Go.  This is the gccgo version.
   * ---------------------------------------------------------------------- */

  String *gccgoCTypeForGoValue(Node *n, SwigType *type, String *name) {
    return gcCTypeForGoValue(n, type, name);
  }

  /* ----------------------------------------------------------------------
   * goTypeIsInterface
   *
   * Return whether this C++ type is represented as an interface type
   * in Go.  These types require adjustments in the Go code when
   * passing them back and forth between Go and C++.
   * ---------------------------------------------------------------------- */

  bool goTypeIsInterface(Node *n, SwigType *type) {
    bool is_interface;
    Delete(goTypeWithInfo(n, type, &is_interface));
    return is_interface;
  }

  /* ----------------------------------------------------------------------
   * hasGoTypemap
   *
   * Return whether a type has a "gotype" typemap entry.
   * ---------------------------------------------------------------------- */

  bool hasGoTypemap(Node *n, SwigType *type) {
    Parm *p = NewParm(type, "test", n);
    SwigType *tm = Swig_typemap_lookup("gotype", p, "", NULL);
    Delete(p);
    if (tm && Strstr(tm, "$gotypename") == 0) {
      Delete(tm);
      return true;
    }
    Delete(tm);
    return false;
  }

  /* ----------------------------------------------------------------------
   * goEnumName()
   *
   * Given an enum node, return a string to use for the enum type in Go.
   * ---------------------------------------------------------------------- */

  String *goEnumName(Node *n) {
    String *ret = Getattr(n, "go:enumname");
    if (ret) {
      return Copy(ret);
    }

    if (Equal(Getattr(n, "type"), "enum ")) {
      return NewString("int");
    }

    String *type = Getattr(n, "enumtype");
    assert(type);
    char *p = Char(type);
    int len = Len(type);
    String *s = NewString("");
    bool capitalize = true;
    for (int i = 0; i < len; ++i, ++p) {
      if (*p == ':') {
	++i;
	++p;
	assert(*p == ':');
	capitalize = true;
      } else if (capitalize) {
	Putc(toupper(*p), s);
	capitalize = false;
      } else {
	Putc(*p, s);
      }
    }

    ret = Swig_name_mangle(s);
    Delete(s);
    return ret;
  }


  /* ----------------------------------------------------------------------
   * getParm()
   *
   * Get the real parameter to use.
   * ---------------------------------------------------------------------- */

  Parm *getParm(Parm *p) {
    while (p && checkAttribute(p, "tmap:in:numinputs", "0")) {
      p = Getattr(p, "tmap:in:next");
    }
    return p;
  }

  /* ----------------------------------------------------------------------
   * nextParm()
   *
   * Return the next parameter.
   * ---------------------------------------------------------------------- */

  Parm *nextParm(Parm *p) {
    if (!p) {
      return NULL;
    } else if (Getattr(p, "tmap:in")) {
      return Getattr(p, "tmap:in:next");
    } else {
      return nextSibling(p);
    }
  }

  /* ----------------------------------------------------------------------
   * isStatic
   *
   * Return whether a node should be considered as static rather than
   * as a member.
   * ---------------------------------------------------------------------- */

  bool isStatic(Node *n) {
    String *storage = Getattr(n, "storage");
    return (storage && (Strcmp(storage, "static") == 0 || Strcmp(storage, "friend") == 0) && (!SmartPointer || !Getattr(n, "allocate:smartpointeraccess")));
  }

  /* ----------------------------------------------------------------------
   * isFriend
   *
   * Return whether a node is a friend.
   * ---------------------------------------------------------------------- */

  bool isFriend(Node *n) {
    String *storage = Getattr(n, "storage");
    return storage && Strcmp(storage, "friend") == 0;
  }

};				/* class GO */

/* -----------------------------------------------------------------------------
 * swig_go()    - Instantiate module
 * ----------------------------------------------------------------------------- */

static Language *new_swig_go() {
  return new GO();
}
extern "C" Language *swig_go(void) {
  return new_swig_go();
}

/* -----------------------------------------------------------------------------
 * Static member variables
 * ----------------------------------------------------------------------------- */

// Usage message.
const char * const GO::usage = (char *) "\
Go Options (available with -go)\n\
     -gccgo              - Generate code for gccgo rather than 6g/8g\n\
     -go-prefix <p>      - Like gccgo -fgo-prefix option\n\
     -longsize <s>       - Set size of C/C++ long type--32 or 64 bits\n\
     -intgosize <s>      - Set size of Go int type--32 or 64 bits\n\
     -package <name>     - Set name of the Go package to <name>\n\
     -soname <name>      - Set shared library holding C/C++ code to <name>\n\
\n";
