swig/Source/Modules/go.cxx
Olly Betts 4ac3c87a29 Sort out predefined SWIG-specific macros
Ensure that SWIG_VERSION is defined both at SWIG-time and in the
generated C/C++ wrapper code (it was only defined in the wrapper
for some target languages previously).

SWIGGO and SWIGJAVASCRIPT are now defined in the generated wrappers
to match behaviour for all other target languages.

Stop defining SWIGVERSION in the wrapper.  This only happened as a
side-effect of how SWIG_VERSION was defined but was never documented and
is redundant.

The new testcase also checks that SWIG is defined at SWIG-time but not
in the generated wrapper, and that exactly one of a list of
target-language specific macros is defined.

Fixes #1050
2022-10-05 12:40:15 +13:00

5702 lines
164 KiB
C++

/* -----------------------------------------------------------------------------
* 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>
/* ----------------------------------------------------------------------
* siphash()
*
* 64-bit SipHash-2-4 to generate unique id for each module
* ---------------------------------------------------------------------- */
// An unsigned 64-bit integer that works on a 32-bit host.
typedef struct {
// Assume unsigned long is at least 32 bits.
unsigned long hi;
unsigned long lo;
} swig_uint64;
// Rotate v left by bits, which must be <= 32.
static inline void _rotl(swig_uint64 *v, int bits) {
assert(bits <= 32);
unsigned long tmp = v->hi;
if (bits == 32) {
v->hi = v->lo;
v->lo = tmp;
} else {
v->hi = (tmp << bits) | ((0xfffffffful & v->lo) >> (32 - bits));
v->lo = (v->lo << bits) | ((0xfffffffful & tmp) >> (32 - bits));
}
}
// dst ^= src
static inline void _xor(swig_uint64 *dst, swig_uint64 *src) {
dst->lo ^= src->lo;
dst->hi ^= src->hi;
}
// dst += src
static inline void _add(swig_uint64 *dst, swig_uint64 *src) {
dst->lo += src->lo;
dst->hi += src->hi + ((dst->lo & 0xfffffffful) < (src->lo&0xfffffffful) ? 1 : 0);
}
#define SIPROUND \
do { \
_add(&v0, &v1); _rotl(&v1, 13); _xor(&v1, &v0); _rotl(&v0, 32); \
_add(&v2, &v3); _rotl(&v3, 16); _xor(&v3, &v2); \
_add(&v0, &v3); _rotl(&v3, 21); _xor(&v3, &v0); \
_add(&v2, &v1); _rotl(&v1, 17); _xor(&v1, &v2); _rotl(&v2, 32); \
} while(0)
// Set out to the hash of inc/inlen.
static void siphash(swig_uint64 *out, const char *inc, unsigned long inlen) {
/* "somepseudorandomlygeneratedbytes" */
swig_uint64 v0 = {0x736f6d65UL, 0x70736575UL};
swig_uint64 v1 = {0x646f7261UL, 0x6e646f6dUL};
swig_uint64 v2 = {0x6c796765UL, 0x6e657261UL};
swig_uint64 v3 = {0x74656462UL, 0x79746573UL};
swig_uint64 b;
/* hard-coded k. */
swig_uint64 k0 = {0x07060504UL, 0x03020100UL};
swig_uint64 k1 = {0x0F0E0D0CUL, 0x0B0A0908UL};
int i;
const int cROUNDS = 2, dROUNDS = 4;
const unsigned char *in = (const unsigned char *)inc;
const unsigned char *end = in + inlen - (inlen % 8);
int left = inlen & 7;
_xor(&v3, &k1); _xor(&v2, &k0); _xor(&v1, &k1); _xor(&v0, &k0);
for (; in != end; in += 8) {
b.hi = 0; b.lo = 0;
for (i = 0; i < 4; i++) {
b.lo |= ((unsigned long)in[i]) << (8*i);
}
for (i = 0; i < 4; i++) {
b.hi |= ((unsigned long)in[i+4]) << (8*i);
}
_xor(&v3, &b);
for (i = 0; i < cROUNDS; i++) {
SIPROUND;
}
_xor(&v0, &b);
}
b.hi = (inlen & 0xff)<<24; b.lo = 0;
for (; left; left--) {
if (left > 4) {
b.hi |= ((unsigned long)in[left-1]) << (8*left-8-32);
} else {
b.lo |= ((unsigned long)in[left-1]) << (8*left-8);
}
}
_xor(&v3, &b);
for(i=0; i<cROUNDS; i++) {
SIPROUND;
}
_xor(&v0, &b); v2.lo ^= 0xff;
for(i=0; i<dROUNDS; i++) {
SIPROUND;
}
out->lo = 0; out->hi = 0;
_xor(out, &v0); _xor(out, &v1); _xor(out, &v2); _xor(out, &v3);
}
#undef SIPROUND
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;
// -fgo-prefix option.
String *prefix_option;
// -fgo-pkgpath option.
String *pkgpath_option;
// Prefix for translating %import directive to import statements.
String *import_prefix;
// Whether to use a shared library.
bool use_shlib;
// Name of shared library to import.
String *soname;
// 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;
/* 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_imports;
File *f_go_runtime;
File *f_go_header;
File *f_go_wrappers;
File *f_go_directors;
File *f_cgo_comment;
File *f_cgo_comment_typedefs;
// 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 enum types that we have seen but which may not have
// been defined. The index is a SwigType.
Hash *undefined_enum_types;
// 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;
// A hash table of all the go_imports already imported. The index is a full
// import name e.g. '"runtime"' or '_ "runtime/cgo"' or 'sc "syscall"'.
Hash *go_imports;
// A unique ID used to make public symbols unique.
String *unique_id;
public:
GO():package(NULL),
module(NULL),
gccgo_flag(false),
go_prefix(NULL),
prefix_option(NULL),
pkgpath_option(NULL),
import_prefix(NULL),
use_shlib(false),
soname(NULL),
intgo_type_size(0),
f_c_begin(NULL),
f_go_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_imports(NULL),
f_go_runtime(NULL),
f_go_header(NULL),
f_go_wrappers(NULL),
f_go_directors(NULL),
f_cgo_comment(NULL),
f_cgo_comment_typedefs(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_enum_types(NULL),
undefined_types(NULL),
defined_types(NULL),
go_imports(NULL),
unique_id(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 saw_nocgo_flag = 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], "-cgo") == 0) {
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-no-cgo") == 0) {
Swig_mark_arg(i);
saw_nocgo_flag = true;
} 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]) {
prefix_option = NewString(argv[i + 1]);
Swig_mark_arg(i);
Swig_mark_arg(i + 1);
i++;
} else {
Swig_arg_error();
}
} else if (strcmp(argv[i], "-go-pkgpath") == 0) {
if (argv[i + 1]) {
pkgpath_option = NewString(argv[i + 1]);
Swig_mark_arg(i);
Swig_mark_arg(i + 1);
i++;
} else {
Swig_arg_error();
}
} else if (strcmp(argv[i], "-import-prefix") == 0) {
if (argv[i + 1]) {
import_prefix = NewString(argv[i + 1]);
Swig_mark_arg(i);
Swig_mark_arg(i + 1);
i++;
} else {
Swig_arg_error();
}
} else if (strcmp(argv[i], "-use-shlib") == 0) {
Swig_mark_arg(i);
use_shlib = true;
} 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) {
// Ignore for backward compatibility.
if (argv[i + 1]) {
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) {
Printf(stdout, "%s\n", usage);
}
}
}
if (saw_nocgo_flag) {
Printf(stderr, "SWIG -go: -no-cgo option is no longer supported\n");
Exit(EXIT_FAILURE);
}
if (gccgo_flag && !pkgpath_option && !prefix_option) {
prefix_option = NewString("go");
}
// Add preprocessor symbol to parser.
Preprocessor_define("SWIGGO 1", 0);
if (gccgo_flag) {
Preprocessor_define("SWIGGO_GCCGO 1", 0);
}
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 gc, 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 && use_shlib) {
soname = Copy(package);
Append(soname, ".so");
}
if (gccgo_flag) {
String *pref;
if (pkgpath_option) {
pref = pkgpath_option;
} else {
pref = prefix_option;
}
go_prefix = NewString("");
for (char *p = Char(pref); *p != '\0'; p++) {
if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '.' || *p == '$') {
Putc(*p, go_prefix);
} else {
Putc('_', go_prefix);
}
}
if (!pkgpath_option) {
Append(go_prefix, ".");
Append(go_prefix, getModuleName(package));
}
}
// Get filenames.
String *swig_filename = Getattr(n, "infile");
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);
// Generate a unique ID based on a hash of the SWIG input.
swig_uint64 hash = {0, 0};
FILE *swig_input = Swig_open(swig_filename);
if (swig_input == NULL) {
FileErrorDisplay(swig_filename);
Exit(EXIT_FAILURE);
}
String *swig_input_content = Swig_read_file(swig_input);
siphash(&hash, Char(swig_input_content), Len(swig_input_content));
Delete(swig_input_content);
fclose(swig_input);
unique_id = NewString("");
Printf(unique_id, "_%s_%08x%08x", getModuleName(package), hash.hi, hash.lo);
// Open files.
f_c_begin = NewFile(c_filename, "w", SWIG_output_files());
if (!f_c_begin) {
FileErrorDisplay(c_filename);
Exit(EXIT_FAILURE);
}
if (directorsEnabled()) {
if (!c_filename_h) {
Printf(stderr, "Unable to determine outfile_h\n");
Exit(EXIT_FAILURE);
}
f_c_directors_h = NewFile(c_filename_h, "w", SWIG_output_files());
if (!f_c_directors_h) {
FileErrorDisplay(c_filename_h);
Exit(EXIT_FAILURE);
}
}
f_go_begin = NewFile(go_filename, "w", SWIG_output_files());
if (!f_go_begin) {
FileErrorDisplay(go_filename);
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_imports = NewString("");
f_go_runtime = NewString("");
f_go_header = NewString("");
f_go_wrappers = NewString("");
f_go_directors = NewString("");
f_cgo_comment = NewString("");
f_cgo_comment_typedefs = 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_imports", f_go_imports);
Swig_register_filebyname("go_runtime", f_go_runtime);
Swig_register_filebyname("go_header", f_go_header);
Swig_register_filebyname("go_wrapper", f_go_wrappers);
Swig_register_filebyname("go_director", f_go_directors);
Swig_register_filebyname("cgo_comment", f_cgo_comment);
Swig_register_filebyname("cgo_comment_typedefs", f_cgo_comment_typedefs);
Swig_banner(f_c_begin);
if (CPlusPlus) {
Printf(f_c_begin, "\n// source: %s\n\n", swig_filename);
} else {
Printf(f_c_begin, "\n/* source: %s */\n\n", swig_filename);
}
Printf(f_c_runtime, "#define SWIGMODULE %s\n", module);
Printf(f_c_runtime, "#ifndef SWIGGO\n#define SWIGGO\n#endif\n\n");
if (gccgo_flag) {
Printf(f_c_runtime, "#define SWIGGO_PREFIX %s\n", go_prefix);
}
if (directorsEnabled()) {
Printf(f_c_runtime, "#define SWIG_DIRECTORS\n");
Swig_banner(f_c_directors_h);
Printf(f_c_directors_h, "\n// source: %s\n\n", swig_filename);
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_h, "class Swig_memory;\n\n");
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);
Printf(f_go_begin, "\n// source: %s\n", swig_filename);
Printv(f_cgo_comment_typedefs, "/*\n", NULL);
// The cgo program defines the intgo type after our function
// definitions, but we want those definitions to be able to use
// intgo also.
Printv(f_cgo_comment_typedefs, "#define intgo swig_intgo\n", NULL);
Printv(f_cgo_comment_typedefs, "typedef void *swig_voidp;\n", NULL);
// Output module initialization code.
Printf(f_go_begin, "\npackage %s\n\n", getModuleName(package));
// 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_enum_types = NewHash();
undefined_types = NewHash();
defined_types = NewHash();
go_imports = NewHash();
// Emit code.
Language::top(n);
if (directorsEnabled()) {
// Insert director runtime into the f_runtime file (make it occur before %header section)
Swig_insert_file("director_common.swg", f_c_runtime);
Swig_insert_file("director.swg", f_c_runtime);
}
Delete(go_imports);
// Write out definitions for the types not defined by SWIG.
if (Len(undefined_enum_types) > 0)
Printv(f_go_wrappers, "\n", NULL);
for (Iterator p = First(undefined_enum_types); p.key; p = Next(p)) {
String *name = p.item;
Printv(f_go_wrappers, "type ", name, " int\n", NULL);
}
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_enum_types);
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);
// End the cgo comment.
Printv(f_cgo_comment, "#undef intgo\n", NULL);
Printv(f_cgo_comment, "*/\n", NULL);
Printv(f_cgo_comment, "import \"C\"\n", NULL);
Printv(f_cgo_comment, "\n", NULL);
bool need_panic = false;
if (Strstr(f_c_runtime, "SWIG_contract_assert(") != 0 || Strstr(f_c_wrappers, "SWIG_contract_assert(") != 0) {
Printv(f_c_begin, "\n#define SWIG_contract_assert(expr, msg) if (!(expr)) { _swig_gopanic(msg); } else\n\n", NULL);
need_panic = true;
}
if (!gccgo_flag && (need_panic || Strstr(f_c_runtime, "_swig_gopanic") != 0 || Strstr(f_c_wrappers, "_swig_gopanic") != 0)) {
Printv(f_go_header, "//export cgo_panic_", unique_id, "\n", NULL);
Printv(f_go_header, "func cgo_panic_", unique_id, "(p *byte) {\n", NULL);
Printv(f_go_header, "\ts := (*[1024]byte)(unsafe.Pointer(p))[:]\n", NULL);
Printv(f_go_header, "\tfor i, b := range s {\n", NULL);
Printv(f_go_header, "\t\tif b == 0 {\n", NULL);
Printv(f_go_header, "\t\t\tpanic(string(s[:i]))\n", NULL);
Printv(f_go_header, "\t\t}\n", NULL);
Printv(f_go_header, "\t}\n", NULL);
Printv(f_go_header, "\tpanic(string(s))\n", NULL);
Printv(f_go_header, "}\n\n", NULL);
Printv(f_c_begin, "\nextern\n", NULL);
Printv(f_c_begin, "#ifdef __cplusplus\n", NULL);
Printv(f_c_begin, " \"C\"\n", NULL);
Printv(f_c_begin, "#endif\n", NULL);
Printv(f_c_begin, " void cgo_panic_", unique_id, "(const char*);\n", NULL);
Printv(f_c_begin, "static void _swig_gopanic(const char *p) {\n", NULL);
Printv(f_c_begin, " cgo_panic_", unique_id, "(p);\n", NULL);
Printv(f_c_begin, "}\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_cgo_comment_typedefs, f_go_begin);
Dump(f_cgo_comment, f_go_begin);
Dump(f_go_imports, f_go_begin);
Dump(f_go_header, f_go_begin);
Dump(f_go_runtime, f_go_begin);
Dump(f_go_wrappers, f_go_begin);
if (directorsEnabled()) {
Dump(f_go_directors, f_go_begin);
}
Delete(f_c_runtime);
Delete(f_c_header);
Delete(f_c_wrappers);
Delete(f_c_init);
Delete(f_go_imports);
Delete(f_go_runtime);
Delete(f_go_header);
Delete(f_go_wrappers);
Delete(f_go_directors);
Delete(f_cgo_comment);
Delete(f_cgo_comment_typedefs);
Delete(f_c_begin);
Delete(f_go_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) {
if (!Getattr(go_imports, modname)) {
Setattr(go_imports, modname, modname);
Printv(f_go_imports, "import \"", NULL);
if (import_prefix) {
Printv(f_go_imports, import_prefix, "/", NULL);
}
Printv(f_go_imports, modname, "\"\n", NULL);
}
imported_package = modname;
saw_import = true;
}
int r = Language::importDirective(n);
imported_package = hold_import;
return r;
}
/* ----------------------------------------------------------------------
* Language::insertDirective()
*
* If the section is go_imports, store them for later.
* ---------------------------------------------------------------------- */
virtual int insertDirective(Node *n) {
char *section = Char(Getattr(n, "section"));
if ((ImportMode && !Getattr(n, "generated")) ||
!section || (strcmp(section, "go_imports") != 0)) {
return Language::insertDirective(n);
}
char *code = Char(Getattr(n, "code"));
char *pch = strtok(code, ",");
while (pch != NULL) {
// Do not import same thing more than once.
if (!Getattr(go_imports, pch)) {
Setattr(go_imports, pch, pch);
Printv(f_go_imports, "import ", pch, "\n", NULL);
}
pch = strtok(NULL, ",");
}
return SWIG_OK;
}
/* ----------------------------------------------------------------------
* 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;
}
// Don't emit constructors for abstract director classes. They
// will never succeed anyhow.
if (Swig_methodclass(n) && Swig_directorclass(n)
&& Strcmp(Char(Getattr(n, "wrap:action")), director_prot_ctor_code) == 0) {
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)) {
// 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);
}
Append(wname, unique_id);
Setattr(n, "wrap:name", wname);
ParmList *parms = Getattr(n, "parms");
Setattr(n, "wrap:parms", parms);
int r = makeWrappers(n, 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.
* 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 a virtual 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 *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static) {
assert(result);
int ret = SWIG_OK;
int r = makeCgoWrappers(n, go_name, overname, wname, base, parms, result, is_static);
if (r != SWIG_OK) {
ret = r;
}
if (class_methods) {
Setattr(class_methods, Getattr(n, "name"), NewString(""));
}
return ret;
}
/* ----------------------------------------------------------------------
* struct cgoWrapperInfo
*
* Information needed by the CGO wrapper functions.
* ---------------------------------------------------------------------- */
struct cgoWrapperInfo {
// The function we are generating code for.
Node *n;
// The name of the Go function.
String *go_name;
// The overload string for an overloaded function.
String *overname;
// The name of the C wrapper function.
String *wname;
// The base classes.
List *base;
// The parameters.
ParmList *parms;
// The result type.
SwigType *result;
// Whether this is a static function, not a class method.
bool is_static;
// The Go receiver type.
String *receiver;
// Whether this is a class constructor.
bool is_constructor;
// Whether this is a class destructor.
bool is_destructor;
};
/* ----------------------------------------------------------------------
* makeCgoWrappers()
*
* Write out the wrappers for a function when producing cgo input
* files.
* ---------------------------------------------------------------------- */
int makeCgoWrappers(Node *n, String *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static) {
Swig_save("makeCgoWrappers", n, "emit:cgotype", "emit:cgotypestruct", NULL);
cgoWrapperInfo info;
info.n = n;
info.go_name = go_name;
info.overname = overname;
info.wname = wname;
info.base = base;
info.parms = parms;
info.result = result;
info.is_static = is_static;
info.receiver = class_receiver;
if (is_static) {
info.receiver = NULL;
}
String *nodetype = Getattr(n, "nodeType");
info.is_constructor = Cmp(nodetype, "constructor") == 0;
info.is_destructor = Cmp(nodetype, "destructor") == 0;
if (info.is_constructor || info.is_destructor) {
assert(class_receiver);
assert(!base);
info.receiver = NULL;
}
int ret = SWIG_OK;
int r = cgoGoWrapper(&info);
if (r != SWIG_OK) {
ret = r;
}
r = cgoCommentWrapper(&info);
if (r != SWIG_OK) {
ret = r;
}
r = cgoGccWrapper(&info);
if (r != SWIG_OK) {
ret = r;
}
Swig_restore(n);
return ret;
}
/* ----------------------------------------------------------------------
* cgoGoWrapper()
*
* Write out Go code to call a cgo function. This code will go into
* the generated Go output file.
* ---------------------------------------------------------------------- */
int cgoGoWrapper(const cgoWrapperInfo *info) {
Wrapper *dummy = initGoTypemaps(info->parms);
bool add_to_interface = interfaces && !info->is_constructor && !info->is_destructor && !info->is_static && !info->overname && checkFunctionVisibility(info->n, NULL);
Printv(f_go_wrappers, "func ", NULL);
Parm *p = info->parms;
int pi = 0;
// Add the receiver first if this is a method.
if (info->receiver) {
Printv(f_go_wrappers, "(", NULL);
if (info->base && info->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, " ", info->receiver, ") ", NULL);
}
Printv(f_go_wrappers, info->go_name, NULL);
if (info->overname) {
Printv(f_go_wrappers, info->overname, NULL);
}
Printv(f_go_wrappers, "(", NULL);
// If we are doing methods, add this method to the interface.
if (add_to_interface) {
Printv(interfaces, "\t", info->go_name, "(", NULL);
}
// Write out the parameters to both the function definition and
// the interface.
String *parm_print = NewString("");
int parm_count = emit_num_arguments(info->parms);
int required_count = emit_num_required(info->parms);
int args = 0;
for (; pi < parm_count; ++pi) {
p = getParm(p);
if (pi == 0 && info->is_destructor) {
String *cl = exportedName(class_name);
Printv(parm_print, Getattr(p, "lname"), " ", cl, NULL);
Delete(cl);
++args;
} else {
if (args > 0) {
Printv(parm_print, ", ", NULL);
}
++args;
if (pi >= required_count) {
Printv(parm_print, "_swig_args ...interface{}", NULL);
break;
}
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 (info->is_constructor) {
String *cl = exportedName(class_name);
Printv(parm_print, " (_swig_ret ", cl, ")", NULL);
Delete(cl);
} else {
if (SwigType_type(info->result) != T_VOID) {
String *tm = goType(info->n, info->result);
Printv(parm_print, " (_swig_ret ", tm, ")", NULL);
Delete(tm);
}
}
Printv(f_go_wrappers, parm_print, NULL);
if (add_to_interface) {
Printv(interfaces, parm_print, "\n", NULL);
}
// Write out the function body.
Printv(f_go_wrappers, " {\n", NULL);
if (parm_count > required_count) {
Parm *p = info->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);
}
}
String *call = NewString("\t");
String *ret_type = NULL;
bool memcpy_ret = false;
String *wt = NULL;
if (SwigType_type(info->result) != T_VOID) {
if (info->is_constructor) {
ret_type = exportedName(class_name);
} else {
ret_type = goImType(info->n, info->result);
}
Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL);
bool c_struct_type;
Delete(cgoTypeForGoValue(info->n, info->result, &c_struct_type));
if (c_struct_type) {
memcpy_ret = true;
}
if (memcpy_ret) {
Printv(call, "swig_r_p := ", NULL);
} else {
Printv(call, "swig_r = (", ret_type, ")(", NULL);
}
if (info->is_constructor || goTypeIsInterface(info->n, info->result)) {
if (info->is_constructor) {
wt = Copy(class_receiver);
} else {
wt = goWrapperType(info->n, info->result, true);
}
Printv(call, wt, "(", NULL);
}
}
Printv(call, "C.", info->wname, "(", NULL);
args = 0;
if (parm_count > required_count) {
Printv(call, "C.swig_intgo(len(_swig_args))", NULL);
++args;
}
if (info->base && info->receiver) {
if (args > 0) {
Printv(call, ", ", NULL);
}
++args;
Printv(call, "C.uintptr_t(_swig_base)", NULL);
}
p = info->parms;
for (int i = 0; i < parm_count; ++i) {
p = getParm(p);
if (args > 0) {
Printv(call, ", ", NULL);
}
++args;
SwigType *pt = Getattr(p, "type");
String *ln = Getattr(p, "lname");
String *ivar = NewStringf("_swig_i_%d", i);
String *goin = goGetattr(p, "tmap:goin");
if (goin == NULL) {
Printv(f_go_wrappers, "\t", ivar, " := ", NULL);
bool need_close = false;
if ((i == 0 && info->is_destructor) || ((i > 0 || !info->receiver || info->base || info->is_constructor) && goTypeIsInterface(p, pt))) {
Printv(f_go_wrappers, "getSwigcptr(", NULL);
need_close = true;
}
Printv(f_go_wrappers, ln, NULL);
if (need_close) {
Printv(f_go_wrappers, ")", NULL);
}
Printv(f_go_wrappers, "\n", NULL);
Setattr(p, "emit:goinput", ln);
} else {
String *itm = goImType(p, pt);
Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL);
goin = Copy(goin);
Replaceall(goin, "$input", ln);
Replaceall(goin, "$result", ivar);
Printv(f_go_wrappers, goin, "\n", NULL);
Delete(goin);
Setattr(p, "emit:goinput", ivar);
}
bool c_struct_type;
String *ct = cgoTypeForGoValue(p, pt, &c_struct_type);
if (c_struct_type) {
Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL);
} else {
Printv(call, "C.", ct, "(", ivar, ")", NULL);
}
Delete(ct);
p = nextParm(p);
}
Printv(f_go_wrappers, call, ")", NULL);
Delete(call);
if (wt) {
// Close the type conversion to the wrapper type.
Printv(f_go_wrappers, ")", NULL);
}
if (SwigType_type(info->result) != T_VOID && !memcpy_ret) {
// Close the type conversion of the return value.
Printv(f_go_wrappers, ")", NULL);
}
Printv(f_go_wrappers, "\n", NULL);
if (memcpy_ret) {
Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL);
}
if (ret_type) {
Delete(ret_type);
}
goargout(info->parms);
if (SwigType_type(info->result) != T_VOID) {
Swig_save("cgoGoWrapper", info->n, "type", "tmap:goout", NULL);
Setattr(info->n, "type", info->result);
String *goout = goTypemapLookup("goout", info->n, "swig_r");
if (goout == NULL) {
Printv(f_go_wrappers, "\treturn swig_r\n", NULL);
} else {
String *tm = goType(info->n, info->result);
Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL);
goout = Copy(goout);
Replaceall(goout, "$input", "swig_r");
Replaceall(goout, "$result", "swig_r_1");
Printv(f_go_wrappers, goout, "\n", NULL);
Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL);
}
Swig_restore(info->n);
}
Printv(f_go_wrappers, "}\n\n", NULL);
DelWrapper(dummy);
return SWIG_OK;
}
/* ----------------------------------------------------------------------
* cgoCommentWrapper()
*
* Write out a cgo function to call a C/C++ function. This code
* will go into the cgo comment in the generated Go output file.
* ---------------------------------------------------------------------- */
int cgoCommentWrapper(const cgoWrapperInfo *info) {
String *ret_type;
if (SwigType_type(info->result) == T_VOID) {
ret_type = NewString("void");
} else {
bool c_struct_type;
ret_type = cgoTypeForGoValue(info->n, info->result, &c_struct_type);
}
Printv(f_cgo_comment, "extern ", ret_type, " ", info->wname, "(", NULL);
Delete(ret_type);
int parm_count = emit_num_arguments(info->parms);
int required_count = emit_num_required(info->parms);
int args = 0;
if (parm_count > required_count) {
Printv(f_cgo_comment, "intgo _swig_args", NULL);
++args;
}
if (info->base && info->receiver) {
if (args > 0) {
Printv(f_cgo_comment, ", ", NULL);
}
++args;
Printv(f_cgo_comment, "uintptr_t _swig_base", NULL);
}
Parm *p = info->parms;
for (int i = 0; i < parm_count; ++i) {
p = getParm(p);
if (args > 0) {
Printv(f_cgo_comment, ", ", NULL);
}
++args;
SwigType *pt = Getattr(p, "type");
String *ln = Getattr(p, "lname");
bool c_struct_type;
String *ct = cgoTypeForGoValue(p, pt, &c_struct_type);
Printv(f_cgo_comment, ct, " ", ln, NULL);
Delete(ct);
p = nextParm(p);
}
if (args == 0) {
Printv(f_cgo_comment, "void", NULL);
}
Printv(f_cgo_comment, ");\n", NULL);
return SWIG_OK;
}
/* ----------------------------------------------------------------------
* cgoGccWrapper()
*
* Write out code to the C/C++ wrapper file. This code will be
* called by the code generated by cgoCommentWrapper.
* ---------------------------------------------------------------------- */
int cgoGccWrapper(const cgoWrapperInfo *info) {
Wrapper *f = NewWrapper();
Swig_save("cgoGccWrapper", info->n, "parms", NULL);
ParmList *parms = info->parms;
Parm *base_parm = NULL;
if (info->base && !isStatic(info->n)) {
SwigType *base_type = Copy(getClassType());
SwigType_add_pointer(base_type);
base_parm = NewParm(base_type, NewString("arg1"), info->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(info->n, info->result, f);
// Start the function definition.
String *fnname = NewString("");
Printv(fnname, info->wname, "(", NULL);
int args = 0;
if (parm_count > required_count) {
Printv(fnname, "intgo _swig_optargc", NULL);
++args;
}
Parm *p = parms;
for (int i = 0; i < parm_count; ++i) {
if (args > 0) {
Printv(fnname, ", ", NULL);
}
++args;
p = getParm(p);
SwigType *pt = Copy(Getattr(p, "type"));
if (SwigType_isarray(pt) && Getattr(p, "tmap:gotype") == NULL) {
SwigType_del_array(pt);
SwigType_add_pointer(pt);
}
String *pn = NewStringf("_swig_go_%d", i);
String *ct = gcCTypeForGoValue(p, pt, pn);
Printv(fnname, ct, NULL);
Delete(ct);
Delete(pn);
Delete(pt);
p = nextParm(p);
}
Printv(fnname, ")", NULL);
if (SwigType_type(info->result) == T_VOID) {
Printv(f->def, "void ", fnname, NULL);
} else {
String *ct = gcCTypeForGoValue(info->n, info->result, fnname);
Printv(f->def, ct, NULL);
Delete(ct);
String *ln = NewString("_swig_go_result");
ct = gcCTypeForGoValue(info->n, info->result, ln);
Wrapper_add_local(f, "_swig_go_result", ct);
Delete(ct);
Delete(ln);
}
Delete(fnname);
Printv(f->def, " {\n", NULL);
// Apply the in typemaps.
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 {
tm = Copy(tm);
String *pn = NewStringf("_swig_go_%d", i);
Replaceall(tm, "$input", pn);
if (i < required_count) {
Printv(f->code, "\t", tm, "\n", NULL);
} else {
Printf(f->code, "\tif (_swig_optargc > %d) {\n", i - required_count);
Printv(f->code, "\t\t", tm, "\n", NULL);
Printv(f->code, "\t}\n", NULL);
}
Delete(tm);
Setattr(p, "emit:input", pn);
}
p = nextParm(p);
}
Printv(f->code, "\n", NULL);
// Do the real work of the function.
checkConstraints(parms, f);
emitGoAction(info->n, info->base, parms, info->result, f);
argout(parms, f);
cleanupFunction(info->n, f, parms);
if (SwigType_type(info->result) != T_VOID) {
Printv(f->code, "\treturn _swig_go_result;\n", NULL);
}
Printv(f->code, "}\n", NULL);
Wrapper_print(f, f_c_wrappers);
Swig_restore(info->n);
DelWrapper(f);
if (base_parm) {
Delete(base_parm);
}
return SWIG_OK;
}
/* ----------------------------------------------------------------------
* initGoTypemaps()
*
* Initialize the typenames for a Go wrapper, returning a dummy
* Wrapper*. Also set consistent names for the parameters.
* ---------------------------------------------------------------------- */
Wrapper* initGoTypemaps(ParmList *parms) {
Wrapper *dummy = NewWrapper();
emit_attach_parmmaps(parms, dummy);
Parm *p = parms;
int parm_count = emit_num_arguments(parms);
for (int i = 0; i < parm_count; ++i) {
p = getParm(p);
Swig_cparm_name(p, i);
p = nextParm(p);
}
Swig_typemap_attach_parms("default", parms, dummy);
Swig_typemap_attach_parms("gotype", parms, dummy);
Swig_typemap_attach_parms("goin", parms, dummy);
Swig_typemap_attach_parms("goargout", parms, dummy);
Swig_typemap_attach_parms("imtype", parms, dummy);
return dummy;
}
/* -----------------------------------------------------------------------
* 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 {
tm = Copy(tm);
Replaceall(tm, "$input", Getattr(p, "emit:input"));
Printv(f->code, tm, "\n\n", NULL);
Delete(tm);
p = Getattr(p, "tmap:check:next");
}
}
}
/* -----------------------------------------------------------------------
* emitGoAction()
*
* Emit the action of the function. This is used for the 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("");
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"));
Replace(code, Getattr(parms, "lname"), current, DOH_REPLACE_ANY | DOH_REPLACE_ID);
Delete(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 {
Replaceall(tm, "$result", "_swig_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 {
tm = Copy(tm);
Replaceall(tm, "$result", Swig_cresult_name());
Replaceall(tm, "$input", Getattr(p, "emit:input"));
Printv(f->code, tm, "\n", NULL);
Delete(tm);
p = Getattr(p, "tmap:argout:next");
}
}
}
/* -----------------------------------------------------------------------
* goargout()
*
* Handle Go argument output code if any. This is used for the Go
* function. This assumes that each parameter has an "emit:goinput"
* property with the name to use to refer to that parameter.
* ----------------------------------------------------------------------- */
void goargout(ParmList *parms) {
Parm *p = parms;
while (p) {
String *tm = Getattr(p, "tmap:goargout");
if (!tm) {
p = nextSibling(p);
} else {
tm = Copy(tm);
Replaceall(tm, "$result", "swig_r");
Replaceall(tm, "$input", Getattr(p, "emit:goinput"));
Printv(f_go_wrappers, tm, "\n", NULL);
Delete(tm);
p = Getattr(p, "tmap:goargout:next");
}
}
// If we need to memcpy a parameter to pass it to the C code, the
// compiler may think that the parameter is not live during the
// function call. If the garbage collector runs while the C/C++
// function is running, the parameter may be freed. Force the
// compiler to see the parameter as live across the C/C++ function.
int parm_count = emit_num_arguments(parms);
p = parms;
for (int i = 0; i < parm_count; ++i) {
p = getParm(p);
bool c_struct_type;
Delete(cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type));
if (c_struct_type) {
Printv(f_go_wrappers, "\tif Swig_escape_always_false {\n", NULL);
Printv(f_go_wrappers, "\t\tSwig_escape_val = ", Getattr(p, "emit:goinput"), "\n", NULL);
Printv(f_go_wrappers, "\t}\n", NULL);
}
p = nextParm(p);
}
}
/* -----------------------------------------------------------------------
* 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 {
tm = Copy(tm);
Replaceall(tm, "$input", Getattr(p, "emit:input"));
Printv(ret, tm, "\n", NULL);
Delete(tm);
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) {
Printv(f->code, tm, "\n", NULL);
Delete(tm);
}
}
Replaceall(f->code, "$cleanup", cleanup);
Delete(cleanup);
/* See if there is any return cleanup code */
String *tm;
if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) {
Printf(f->code, "%s\n", tm);
Delete(tm);
}
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 (Swig_storage_isstatic(n)) {
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 = (int)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) {
if (getCurrentClass() && (cplus_mode != PUBLIC))
return SWIG_NOWRAP;
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, getModuleName(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;
}
Swig_require("enumvalueDeclaration", n, "*sym:name", NIL);
Node *parent = parentNode(n);
if (Getattr(parent, "unnamed")) {
Setattr(n, "type", NewString("int"));
} else {
Setattr(n, "type", Getattr(parent, "enumtype"));
}
if (GetFlag(parent, "scopedenum")) {
String *symname = Getattr(n, "sym:name");
symname = Swig_name_member(0, Getattr(parent, "sym:name"), symname);
Setattr(n, "sym:name", symname);
Delete(symname);
}
int ret = goComplexConstant(n, Getattr(n, "type"));
Swig_restore(n);
return ret;
}
/* -----------------------------------------------------------------------
* 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 *rawval = Getattr(n, "rawval");
if (rawval && Len(rawval)) {
// Based on Swig_VargetToFunction
String *nname = NewStringf("(%s)", rawval);
String *call;
if (SwigType_isclass(type)) {
call = NewStringf("%s", nname);
} else {
call = SwigType_lcaststr(type, nname);
}
String *cres = Swig_cresult(type, Swig_cresult_name(), call);
Setattr(n, "wrap:action", cres);
Delete(nname);
Delete(call);
Delete(cres);
} else {
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) {
Printv(get, "(char *)", NULL);
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);
Delete(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);
Append(wname, unique_id);
Setattr(n, "wrap:name", wname);
int r = makeWrappers(n, 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);
Printv(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)) {
int r = goBaseEntry(n, bases, local, 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;
}
/* ------------------------------------------------------------
* goBaseEntry()
*
* Implement one entry defined in a parent class for a child class.
* n is the child class.
* ------------------------------------------------------------ */
int goBaseEntry(Node* n, List* bases, Hash *local, Node* entry) {
if (GetFlag(entry, "feature:ignore")) {
return SWIG_OK;
}
if (!is_public(entry)) {
return SWIG_OK;
}
String *type = Getattr(entry, "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) {
return SWIG_OK;
}
if (Strcmp(type, "extend") == 0) {
for (Node* extend = firstChild(entry); extend; extend = nextSibling(extend)) {
if (isStatic(extend)) {
// If we don't do this, the extend_default test case fails.
continue;
}
int r = goBaseEntry(n, bases, local, extend);
if (r != SWIG_OK) {
return r;
}
}
return SWIG_OK;
}
String *storage = Getattr(entry, "storage");
if (storage && (Strcmp(storage, "typedef") == 0 || Strcmp(storage, "friend") == 0)) {
return SWIG_OK;
}
String *mname = Getattr(entry, "sym:name");
if (!mname) {
return SWIG_OK;
}
String *lname = Getattr(entry, "name");
if (Getattr(class_methods, lname)) {
return SWIG_OK;
}
if (Getattr(local, lname)) {
return SWIG_OK;
}
Setattr(local, lname, NewString(""));
String *ty = NewString(Getattr(entry, "type"));
SwigType_push(ty, Getattr(entry, "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, entry);
if (r != SWIG_OK) {
return r;
}
if (Getattr(entry, "sym:overloaded")) {
for (Node *on = Getattr(entry, "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(entry);
if (is_static) {
receiver = NULL;
}
String *go_name = buildGoName(Getattr(entry, "sym:name"), is_static, false);
r = makeDispatchFunction(entry, go_name, receiver, is_static, NULL, false);
Delete(go_name);
if (r != SWIG_OK) {
return r;
}
}
} else {
int r = goBaseVariable(n, bases, entry);
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);
}
Append(wname, unique_id);
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));
}
}
// A method added by %extend in a base class may have void parms.
ParmList* parms = Getattr(method, "parms");
if (parms != NULL && SwigType_type(Getattr(parms, "type")) == T_VOID) {
parms = NULL;
}
int r = makeWrappers(method, go_name, overname, wname, bases, 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);
int flags = Extend | SmartPointer | use_naturalvar_mode(var);
if (isNonVirtualProtectedAccess(var)) {
flags |= CWRAP_ALL_PROTECTED_ACCESS;
}
// Copied from Swig_wrapped_member_var_type.
if (SwigType_isclass(vt)) {
if (flags & CWRAP_NATURAL_VAR) {
if (CPlusPlus) {
if (!SwigType_isconst(vt)) {
SwigType_add_qualifier(vt, "const");
}
SwigType_add_reference(vt);
}
} else {
SwigType_add_pointer(vt);
}
}
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);
Append(wname, unique_id);
ParmList *parms = NewParm(vt, var_name, var);
String *result = NewString("void");
int r = makeWrappers(var, 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);
Append(wname, unique_id);
int r = makeWrappers(var, 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, "(getSwigcptr(p))\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);
Append(wname, unique_id);
Setattr(n, "wrap:name", wname);
SwigType *result = Copy(Getattr(b.item, "classtypeobj"));
SwigType_add_pointer(result);
int r = makeWrappers(n, 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 getSwigcptr(p.", go_type_name, ")\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 *fn_with_over_name = Copy(fn_name);
if (overname) {
Append(fn_with_over_name, overname);
}
String *wname = Swig_name_wrapper(fn_name);
if (overname) {
Append(wname, overname);
}
Append(wname, unique_id);
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);
Swig_typemap_attach_parms("goin", parms, NULL);
Swig_typemap_attach_parms("goargout", parms, NULL);
Swig_typemap_attach_parms("imtype", 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("int");
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) {
Printv(f_cgo_comment, "extern uintptr_t ", wname, "(int", NULL);
p = parms;
for (int i = 0; i < parm_count; ++i) {
p = getParm(p);
bool c_struct_type;
String *ct = cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type);
Printv(f_cgo_comment, ", ", ct, " ", Getattr(p, "lname"), NULL);
p = nextParm(p);
}
Printv(f_cgo_comment, ");\n", NULL);
// Write out the Go function that calls the wrapper.
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);
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);
String *call = NewString("");
Printv(call, "\tp.", class_receiver, " = ", NULL);
Printv(call, go_type_name, "(C.", wname, "(C.int(swigDirectorAdd(p))", NULL);
p = parms;
for (int i = 0; i < parm_count; ++i) {
Printv(call, ", ", NULL);
p = getParm(p);
String *pt = Getattr(p, "type");
String *ln = Getattr(p, "lname");
String *ivar = NewStringf("_swig_i_%d", i);
String *goin = goGetattr(p, "tmap:goin");
if (goin == NULL) {
Printv(f_go_wrappers, "\t", ivar, " := ", NULL);
bool need_close = false;
if (goTypeIsInterface(p, pt)) {
Printv(f_go_wrappers, "getSwigcptr(", NULL);
need_close = true;
}
Printv(f_go_wrappers, ln, NULL);
if (need_close) {
Printv(f_go_wrappers, ")", NULL);
}
Printv(f_go_wrappers, "\n", NULL);
} else {
String *itm = goImType(p, pt);
Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL);
goin = Copy(goin);
Replaceall(goin, "$input", ln);
Replaceall(goin, "$result", ivar);
Printv(f_go_wrappers, goin, "\n", NULL);
Delete(goin);
}
Setattr(p, "emit:goinput", ivar);
bool c_struct_type;
String *ct = cgoTypeForGoValue(p, pt, &c_struct_type);
if (c_struct_type) {
Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL);
} else {
Printv(call, "C.", ct, "(", ivar, ")", NULL);
}
Delete(ct);
p = nextParm(p);
}
Printv(call, "))", NULL);
Printv(f_go_wrappers, call, "\n", NULL);
goargout(parms);
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);
String *dwname = Swig_name_wrapper(name);
Append(dwname, unique_id);
Setattr(n, "wrap:name", dwname);
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);
cgoWrapperInfo info;
info.n = n;
info.go_name = func_name;
info.overname = overname;
info.wname = wname;
info.base = NULL;
info.parms = first_parm;
info.result = result;
info.is_static = false;
info.receiver = NULL;
info.is_constructor = true;
info.is_destructor = false;
int r = cgoGccWrapper(&info);
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);
Printv(f_c_directors_h, " ", decl, ";\n", NULL);
Delete(decl);
decl = Swig_method_decl(NULL, Getattr(n, "decl"), cxx_director_name, first_parm, 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), swig_mem(0)\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(fn_with_over_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);
Append(wname, unique_id);
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, 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 *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);
String *director_sig = NewString("");
Printv(director_sig, "SwigDirector_", class_name, "::~SwigDirector_", class_name, "()", NULL);
if (throws) {
Printv(director_sig, " ", throws, NULL);
Delete(throws);
}
Printv(director_sig, "\n", NULL);
Printv(director_sig, "{\n", NULL);
if (is_ignored) {
Printv(f_c_directors, director_sig, NULL);
} else {
makeDirectorDestructorWrapper(go_name, director_struct_name, director_sig);
}
Printv(f_c_directors, " delete swig_mem;\n", NULL);
Printv(f_c_directors, "}\n\n", NULL);
Delete(director_sig);
Delete(go_name);
Delete(cn);
Delete(director_struct_name);
return SWIG_OK;
}
/* ------------------------------------------------------------
* makeDirectorDestructorWrapper
*
* Emit the function wrapper for the destructor of a director class.
* ------------------------------------------------------------ */
void makeDirectorDestructorWrapper(String *go_name, String *director_struct_name, String *director_sig) {
String *wname = Copy(go_name);
Append(wname, unique_id);
Printv(f_go_wrappers, "//export ", wname, "\n", NULL);
Printv(f_go_wrappers, "func ", wname, "(c int) {\n", NULL);
Printv(f_go_wrappers, "\tswigDirectorLookup(c).(*", director_struct_name, ").", class_receiver, " = 0\n", NULL);
Printv(f_go_wrappers, "\tswigDirectorDelete(c)\n", NULL);
Printv(f_go_wrappers, "}\n\n", NULL);
Printv(f_c_directors, "extern \"C\" void ", wname, "(intgo);\n", NULL);
Printv(f_c_directors, director_sig, NULL);
Printv(f_c_directors, " ", wname, "(go_val);\n", NULL);
}
/* ------------------------------------------------------------
* 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);
(void)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"));
Append(wn, unique_id);
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;
}
if (!GetFlag(n, "abstract")) {
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(go_upcall);
}
Delete(director_struct_name);
Delete(go_name);
Delete(cn);
}
}
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);
Swig_typemap_attach_parms("gotype", parms, NULL);
Swig_typemap_attach_parms("imtype", 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);
}
Append(callback_name, unique_id);
String *upcall_name = Copy(director_struct_name);
Append(upcall_name, "_upcall_");
Append(upcall_name, go_name);
String *upcall_wname = Swig_name_wrapper(upcall_name);
if (overname) {
Append(upcall_wname, overname);
}
Append(upcall_wname, unique_id);
String *upcall_gc_name = buildGoWrapperName(upcall_name, overname);
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);
Swig_typemap_attach_parms("godirectorin", parms, w);
Swig_typemap_attach_parms("goin", parms, dummy);
Swig_typemap_attach_parms("goargout", parms, dummy);
DelWrapper(dummy);
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);
if (!GetFlag(n, "abstract")) {
Printv(f_cgo_comment, "extern ", NULL);
if (SwigType_type(result) == T_VOID) {
Printv(f_cgo_comment, "void", NULL);
} else {
bool c_struct_type;
String *ret_type = cgoTypeForGoValue(n, result, &c_struct_type);
Printv(f_cgo_comment, ret_type, NULL);
Delete(ret_type);
}
Printv(f_cgo_comment, " ", upcall_wname, "(uintptr_t", NULL);
p = parms;
for (int i = 0; i < parm_count; ++i) {
p = getParm(p);
bool c_struct_type;
String *ct = cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type);
Printv(f_cgo_comment, ", ", ct, " ", Getattr(p, "lname"), NULL);
p = nextParm(p);
}
Printv(f_cgo_comment, ");\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 (GetFlag(n, "abstract")) {
Printv(f_go_wrappers, "\tpanic(\"call to pure virtual method\")\n", NULL);
} else {
String *ret_type = NULL;
bool memcpy_ret = false;
String *wt = NULL;
String *goout = NULL;
if (SwigType_type(result) != T_VOID) {
ret_type = goImType(n, result);
Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL);
goout = goTypemapLookup("goout", n, "swig_r");
bool c_struct_type;
Delete(cgoTypeForGoValue(n, result, &c_struct_type));
if (c_struct_type) {
memcpy_ret = true;
}
}
String *call = NewString("");
Printv(call, "\t", NULL);
if (SwigType_type(result) != T_VOID) {
if (memcpy_ret) {
Printv(call, "swig_r_p := ", NULL);
} else {
Printv(call, "swig_r = (", ret_type, ")(", NULL);
}
if (goTypeIsInterface(n, result)) {
wt = goWrapperType(n, result, true);
Printv(call, "(", wt, ")(", NULL);
}
}
Printv(call, "C.", upcall_wname, "(C.uintptr_t(swig_p.",
go_type_name, ")", NULL);
p = parms;
for (int i = 0; i < parm_count; ++i) {
Printv(call, ", ", NULL);
p = getParm(p);
SwigType *pt = Getattr(p, "type");
String *ln = Getattr(p, "lname");
String *ivar = NewStringf("_swig_i_%d", i);
// This is an ordinary call from Go to C++, so adjust using
// the goin typemap.
String *goin = goGetattr(p, "tmap:goin");
if (goin == NULL) {
Printv(f_go_wrappers, "\t", ivar, " := ", NULL);
bool need_close = false;
if (goTypeIsInterface(p, pt)) {
Printv(f_go_wrappers, "getSwigcptr(", NULL);
need_close = true;
}
Printv(f_go_wrappers, ln, NULL);
if (need_close) {
Printv(f_go_wrappers, ")", NULL);
}
Printv(f_go_wrappers, "\n", NULL);
} else {
String *itm = goImType(p, pt);
Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL);
goin = Copy(goin);
Replaceall(goin, "$input", ln);
Replaceall(goin, "$result", ivar);
Printv(f_go_wrappers, goin, "\n", NULL);
Delete(goin);
}
Setattr(p, "emit:goinput", ivar);
bool c_struct_type;
String *ct = cgoTypeForGoValue(p, pt, &c_struct_type);
if (c_struct_type) {
Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL);
} else {
Printv(call, "C.", ct, "(", ivar, ")", NULL);
}
p = nextParm(p);
}
Printv(call, ")", NULL);
if (wt) {
// Close the type conversion to the wrapper type.
Printv(call, ")", NULL);
}
if (SwigType_type(result) != T_VOID && !memcpy_ret) {
// Close the type conversion of the return value.
Printv(call, ")", NULL);
}
Printv(call, "\n", NULL);
Printv(f_go_wrappers, call, NULL);
Delete(call);
if (memcpy_ret) {
Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL);
}
goargout(parms);
if (SwigType_type(result) != T_VOID) {
if (goout == NULL) {
Printv(f_go_wrappers, "\treturn swig_r\n", NULL);
} else {
String *tm = goType(n, result);
Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL);
Replaceall(goout, "$input", "swig_r");
Replaceall(goout, "$result", "swig_r_1");
Printv(f_go_wrappers, goout, "\n", NULL);
Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL);
}
}
if (ret_type) {
Delete(ret_type);
}
if (wt) {
Delete(wt);
}
}
Printv(f_go_wrappers, "}\n\n", NULL);
if (!GetFlag(n, "abstract")) {
// Define a function that 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, "(swig_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);
String *ret_type = NULL;
bool memcpy_ret = false;
String *wt = NULL;
String *goout = NULL;
if (SwigType_type(result) != T_VOID) {
ret_type = goImType(n, result);
Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL);
goout = goTypemapLookup("goout", n, "swig_r");
bool c_struct_type;
Delete(cgoTypeForGoValue(n, result, &c_struct_type));
if (c_struct_type) {
memcpy_ret = true;
}
}
String *call = NewString("");
Printv(call, "\t", NULL);
if (SwigType_type(result) != T_VOID) {
if (memcpy_ret) {
Printv(call, "swig_r_p := ", NULL);
} else {
Printv(call, "swig_r = (", ret_type, ")(", NULL);
}
if (goTypeIsInterface(n, result)) {
wt = goWrapperType(n, result, true);
Printv(call, "(", wt, ")(", NULL);
}
}
Printv(call, "C.", upcall_wname, "(C.uintptr_t(swig_p.(*",
director_struct_name, ").", go_type_name, ")", NULL);
p = parms;
for (int i = 0; i < parm_count; ++i) {
Printv(call, ", ", NULL);
p = getParm(p);
SwigType *pt = Getattr(p, "type");
String *ivar = NewStringf("_swig_i_%d", i);
String *ln = Copy(Getattr(p, "lname"));
String *goin = goGetattr(p, "tmap:goin");
if (goin == NULL) {
Printv(f_go_wrappers, "\t", ivar, " := ", NULL);
bool need_close = false;
if (goTypeIsInterface(p, pt)) {
Printv(f_go_wrappers, "getSwigcptr(", NULL);
need_close = true;
}
Printv(f_go_wrappers, ln, NULL);
if (need_close) {
Printv(f_go_wrappers, ")", NULL);
}
Printv(f_go_wrappers, "\n", NULL);
} else {
String *itm = goImType(p, pt);
Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL);
goin = Copy(goin);
Replaceall(goin, "$input", ln);
Replaceall(goin, "$result", ivar);
Printv(f_go_wrappers, goin, "\n", NULL);
Delete(goin);
}
Setattr(p, "emit:goinput", ivar);
bool c_struct_type;
String *ct = cgoTypeForGoValue(p, pt, &c_struct_type);
if (c_struct_type) {
Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL);
} else {
Printv(call, "C.", ct, "(", ivar, ")", NULL);
}
Delete(ln);
p = nextParm(p);
}
Printv(call, ")", NULL);
if (wt) {
// Close the type conversion to the wrapper type.
Printv(call, ")", NULL);
}
if (SwigType_type(result) != T_VOID && !memcpy_ret) {
// Close the type conversion of the return value.
Printv(call, ")", NULL);
}
Printv(call, "\n", NULL);
Printv(f_go_wrappers, call, NULL);
Delete(call);
if (memcpy_ret) {
Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL);
}
goargout(parms);
if (SwigType_type(result) != T_VOID) {
if (goout == NULL) {
Printv(f_go_wrappers, "\treturn swig_r\n", NULL);
} else {
String *tm = goType(n, result);
Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL);
Replaceall(goout, "$input", "swig_r");
Replaceall(goout, "$result", "swig_r_1");
Printv(f_go_wrappers, goout, "\n", NULL);
Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL);
}
}
Printv(f_go_wrappers, "}\n\n", NULL);
if (ret_type) {
Delete(ret_type);
}
if (wt) {
Delete(wt);
}
// 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);
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);
cgoWrapperInfo info;
info.n = n;
info.go_name = go_name;
info.overname = overname;
info.wname = upcall_wname;
info.base = NULL;
info.parms = first_parm;
info.result = result;
info.is_static = is_static;
info.receiver = NULL;
info.is_constructor = false;
info.is_destructor = false;
int r = cgoGccWrapper(&info);
if (r != SWIG_OK) {
return r;
}
Delete(first_type);
if (first_parm != parms) {
Delete(first_parm);
}
Swig_restore(n);
Delete(upcall_method_name);
}
// The Go function which invokes the method. This is called by
// the C++ method on the director class.
Printv(f_go_wrappers, "//export ", callback_name, "\n",
"func ", callback_name, "(swig_c int", 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 (is_ignored) {
Printv(f_go_wrappers, "\treturn\n", NULL);
} else {
bool result_is_interface = false;
String *goout = NULL;
if (SwigType_type(result) != T_VOID) {
result_is_interface = goTypeIsInterface(NULL, result);
Printv(f_go_wrappers, "\tvar swig_r ", NULL);
if (!result_is_interface) {
Printv(f_go_wrappers, goType(n, result), NULL);
} else {
Printv(f_go_wrappers, result_wrapper, NULL);
}
Printv(f_go_wrappers, "\n", NULL);
goout = goTypemapLookup("godirectorout", n, "swig_r");
}
String *call = NewString("");
Printv(call, "\t", NULL);
if (SwigType_type(result) != T_VOID) {
Printv(call, "swig_r = ", NULL);
if (result_is_interface) {
Printv(call, result_wrapper, "(getSwigcptr(", NULL);
}
}
Printv(call, "swig_p.", go_with_over_name, "(", NULL);
String *goincode = NewString("");
p = parms;
for (int i = 0; i < parm_count; ++i) {
p = getParm(p);
if (i > 0) {
Printv(call, ", ", NULL);
}
SwigType *pt = Getattr(p, "type");
String *ln = NewString("");
// 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(ln, wt, "(", NULL);
Delete(wt);
}
Printv(ln, Getattr(p, "lname"), NULL);
if (is_interface) {
Printv(ln, ")", NULL);
}
String *goin = goGetattr(p, "tmap:godirectorin");
if (goin == NULL) {
Printv(call, ln, NULL);
} else {
String *ivar = NewString("");
Printf(ivar, "_swig_i_%d", i);
String *itm = goType(p, pt);
Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL);
goin = Copy(goin);
Replaceall(goin, "$input", ln);
Replaceall(goin, "$result", ivar);
Printv(goincode, goin, "\n", NULL);
Delete(goin);
Printv(call, ivar, NULL);
Delete(ivar);
}
Delete(ln);
p = nextParm(p);
}
Printv(call, ")", NULL);
if (result_is_interface) {
Printv(call, "))", NULL);
}
Printv(call, "\n", NULL);
Printv(f_go_wrappers, "\tswig_p := swigDirectorLookup(swig_c).(*", director_struct_name, ")\n", NULL);
Printv(f_go_wrappers, goincode, NULL);
Printv(f_go_wrappers, call, NULL);
Delete(call);
if (SwigType_type(result) != T_VOID) {
if (goout == NULL) {
Printv(f_go_wrappers, "\treturn swig_r\n", NULL);
} else {
String *tm = goImType(n, result);
Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL);
Replaceall(goout, "$input", "swig_r");
Replaceall(goout, "$result", "swig_r_1");
Printv(f_go_wrappers, goout, "\n", NULL);
Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL);
}
}
}
Printv(f_go_wrappers, "}\n\n", NULL);
Delete(result_wrapper);
Delete(upcall_wname);
Delete(upcall_gc_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);
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);
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) {
if (!SwigType_isclass(result)) {
if (!(SwigType_ispointer(result) || SwigType_isreference(result))) {
String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(result, 0));
Wrapper_add_localv(w, "c_result", SwigType_lstr(result, "c_result"), construct_result, NIL);
Delete(construct_result);
} else {
Wrapper_add_localv(w, "c_result", SwigType_lstr(result, "c_result"), "= 0", NIL);
}
} else {
String *cres = SwigType_lstr(result, "c_result");
Printf(w->code, "%s;\n", cres);
Delete(cres);
}
}
if (!is_ignored) {
makeDirectorMethodWrapper(n, w, callback_name);
} 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(callback_name);
Delete(upcall_name);
Delete(go_name);
DelWrapper(w);
return SWIG_OK;
}
/* ------------------------------------------------------------
* makeDirectorMethodWrapper
*
* Emit the function wrapper for a director method.
* ------------------------------------------------------------ */
void makeDirectorMethodWrapper(Node *n, Wrapper *w, String *callback_name) {
ParmList *parms = Getattr(n, "wrap:parms");
SwigType *result = Getattr(n, "type");
Printv(f_c_directors, "extern \"C\" ", NULL);
String *fnname = Copy(callback_name);
Append(fnname, "(int");
Parm *p = parms;
while (p) {
while (checkAttribute(p, "tmap:directorin:numinputs", "0")) {
p = Getattr(p, "tmap:directorin:next");
}
String *cg = gcCTypeForGoValue(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 = gcCTypeForGoValue(n, result, fnname);
Printv(f_c_directors, tm, NULL);
Delete(tm);
}
Delete(fnname);
Printv(f_c_directors, ";\n", NULL);
if (SwigType_type(result) != T_VOID) {
String *r = NewString(Swig_cresult_name());
String *tm = gcCTypeForGoValue(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("swig_");
Append(pn, Getattr(p, "lname"));
Setattr(p, "emit:directorinput", pn);
String *tm = gcCTypeForGoValue(p, 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 {
tm = Copy(tm);
Replaceall(tm, "$input", pn);
Replaceall(tm, "$owner", 0);
Printv(w->code, " ", tm, "\n", NULL);
Delete(tm);
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_name, "(go_val", args, ");\n", NULL);
/* Marshal outputs */
for (p = parms; p; ) {
String *tm;
if ((tm = Getattr(p, "tmap:directorargout"))) {
tm = Copy(tm);
Replaceall(tm, "$result", "jresult");
Replaceall(tm, "$input", Getattr(p, "emit:directorinput"));
Printv(w->code, tm, "\n", NULL);
Delete(tm);
p = Getattr(p, "tmap:directorargout:next");
} else {
p = nextSibling(p);
}
}
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 {
tm = Copy(tm);
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);
}
}
/* ------------------------------------------------------------
* 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, " intgo go_val;\n", NULL);
Printv(f_c_directors_h, " Swig_memory *swig_mem;\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) {
if (Getattr(n, "noexcept"))
return NewString("noexcept");
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 overloads have the same type in this position,
// we can omit the check.
SwigType *tm = goOverloadType(pj, Getattr(pj, "type"));
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 = goOverloadType(pl, Getattr(pl, "type"));
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 argument. 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);
(void)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, false, NULL);
}
/* ----------------------------------------------------------------------
* goImType()
*
* Given a SWIG type, return a string for the intermediate Go type
* to pass to C/C++. This is like goType except that it looks for
* an imtype typemap entry first.
* ---------------------------------------------------------------------- */
String *goImType(Node *n, SwigType *type) {
return goTypeWithInfo(n, type, true, NULL);
}
/* ----------------------------------------------------------------------
* goTypeWithInfo()
*
* Like goType, but return some more information.
*
* If use_imtype is true, this look for a imtype typemap entry.
*
* 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 use_imtype, bool *p_is_interface) {
if (p_is_interface) {
*p_is_interface = false;
}
String *ret = NULL;
if (use_imtype) {
if (n && Cmp(type, Getattr(n, "type")) == 0) {
if (Strcmp(Getattr(n, "nodeType"), "parm") == 0) {
ret = Getattr(n, "tmap:imtype");
}
if (!ret) {
ret = Swig_typemap_lookup("imtype", n, "", NULL);
}
} else {
Parm *p = NewParm(type, "goImType", n);
ret = Swig_typemap_lookup("imtype", p, "", NULL);
Delete(p);
}
}
if (!ret) {
if (n && Cmp(type, Getattr(n, "type")) == 0) {
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);
if (SwigType_isenum(t)) {
Node *e = Language::enumLookup(t);
if (e) {
ret = goEnumName(e);
} else if (Strcmp(t, "enum ") == 0) {
ret = NewString("int");
} else {
// An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) or an ignored enum
String *tt = Copy(t);
Replace(tt, "enum ", "", DOH_REPLACE_ANY);
ret = exportedName(tt);
Setattr(undefined_enum_types, t, ret);
Delete(tt);
}
} else if (SwigType_isfunctionpointer(t) || SwigType_isfunction(t)) {
ret = NewString("_swig_fnptr");
} else if (SwigType_ismemberpointer(t)) {
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, getModuleName(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, false, &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, false, p_is_interface);
Delete(r);
} else if (SwigType_isqualifier(t)) {
SwigType *r = Copy(t);
SwigType_del_qualifier(r);
ret = goTypeWithInfo(n, r, false, 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;
}
/* ----------------------------------------------------------------------
* cgoTypeForGoValue()
*
* Given a SWIG type, return a string for the C type to use for the
* cgo wrapper code. This always returns a simple identifier, since
* it is used in Go code as C.name.
*
* This sets *c_struct_type if the C type uses a struct where the Go
* type uses a simple type. This is true for strings and slices.
* When this is true the Go code has to jump through unsafe hoops to
* pass the type checker.
* ---------------------------------------------------------------------- */
String *cgoTypeForGoValue(Node *n, SwigType *type, bool *c_struct_type) {
*c_struct_type = false;
bool is_interface;
String *go_type = goTypeWithInfo(n, type, true, &is_interface);
if (is_interface) {
Delete(go_type);
return NewString("uintptr_t");
}
if (Strcmp(go_type, "uintptr") == 0) {
Delete(go_type);
return NewString("uintptr_t");
}
if (((char*)Char(go_type))[0] == '*') {
// Treat all pointers as void*. There is no meaningful type
// checking going on here anyhow, and that lets us avoid
// worrying about defining the base type of the pointer.
Delete(go_type);
return NewString("swig_voidp");
}
// Check for some Go types that are really pointers under the covers.
bool is_hidden_pointer = Strncmp(go_type, "func(", 5) == 0 || Strncmp(go_type, "map[", 4) == 0 || Strncmp(go_type, "chan ", 5) == 0;
Delete(go_type);
String *ct = Getattr(n, "emit:cgotype");
if (ct) {
*c_struct_type = Getattr(n, "emit:cgotypestruct") ? true : false;
return Copy(ct);
}
String *t = Copy(type);
if (SwigType_isarray(t) && Getattr(n, "tmap:gotype") == NULL) {
SwigType_del_array(t);
SwigType_add_pointer(t);
}
bool add_typedef = true;
static int count;
++count;
ct = NewStringf("swig_type_%d", count);
String *gct = gcCTypeForGoValue(n, t, ct);
Delete(t);
if (Strncmp(gct, "_gostring_", 10) == 0 || Strncmp(gct, "_goslice_", 9) == 0) {
*c_struct_type = true;
Setattr(n, "emit:cgotypestruct", type);
} else {
char *p = Strstr(gct, ct);
if (p != NULL && p > (char*)Char(gct) && p[-1] == '*' && p[Len(ct)] == '\0') {
// Treat all pointers as void*. See above.
Delete(ct);
--count;
ct = NewString("swig_voidp");
add_typedef = false;
if (is_hidden_pointer) {
// A Go type that is really a pointer, like func, map, chan,
// is being represented in C by a pointer. This is fine,
// but we have to memcpy the type rather than simply
// converting it.
*c_struct_type = true;
Setattr(n, "emit:cgotypestruct", type);
}
}
if (Strncmp(gct, "bool ", 5) == 0) {
// Change the C++ type bool to the C type _Bool.
Replace(gct, "bool", "_Bool", DOH_REPLACE_FIRST);
}
if (Strncmp(gct, "intgo ", 6) == 0) {
// We #define intgo to swig_intgo for the cgo comment.
Replace(gct, "intgo", "swig_intgo", DOH_REPLACE_FIRST);
}
p = Strstr(gct, ct);
if (p != NULL && p > (char*)Char(gct) && p[-1] == ' ' && p[Len(ct)] == '\0') {
String *q = NewStringWithSize(gct, Len(gct) - Len(ct) - 1);
if (validIdentifier(q)) {
// This is a simple type name, and we can use it directly.
Delete(ct);
--count;
ct = q;
add_typedef = false;
}
}
}
if (add_typedef) {
Printv(f_cgo_comment_typedefs, "typedef ", gct, ";\n", NULL);
}
Setattr(n, "emit:cgotype", ct);
Delete(gct);
return Copy(ct);
}
/* ----------------------------------------------------------------------
* 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, true, &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;
}
/* ----------------------------------------------------------------------
* goOverloadType()
*
* Given a type, return the Go type to use when dispatching of
* overloaded functions. This is normally just the usual Go type.
* However, for a C++ class, the usual Go type is an interface type.
* And if that interface type represents a C++ type that SWIG does
* not know about, then the interface type generated for any C++
* class will match that interface. So for that case, we match on
* the underlying integer type.
*
* It has to work this way so that we can handle a derived type of a
* %ignore'd type. It's unlikely that anybody will have a value of
* an undefined type, but we support it because it worked in the
* past.
* ---------------------------------------------------------------------- */
String *goOverloadType(Node *n, SwigType *type) {
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;
}
}
String* go_type = goType(n, ty);
if (Getattr(undefined_types, ty) && !Getattr(defined_types, go_type)) {
Delete(go_type);
return goWrapperType(n, type, true);
}
Delete(go_type);
return goType(n, type);
}
/* ----------------------------------------------------------------------
* 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, getModuleName(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 gc version.
* ---------------------------------------------------------------------- */
String *gcCTypeForGoValue(Node *n, SwigType *type, String *name) {
bool is_interface;
String *gt = goTypeWithInfo(n, type, true, &is_interface);
String *tail = NewString("");
SwigType *t = SwigType_typedef_resolve_all(type);
bool is_const_ref = false;
if (SwigType_isreference(t)) {
SwigType* tt = Copy(t);
SwigType_del_reference(tt);
if (SwigType_isqualifier(tt)) {
String* q = SwigType_parm(tt);
if (Strcmp(q, "const") == 0) {
is_const_ref = true;
}
}
Delete(tt);
}
if (!is_const_ref) {
while (Strncmp(gt, "*", 1) == 0) {
Replace(gt, "*", "", DOH_REPLACE_FIRST);
Printv(tail, "*", NULL);
}
}
Delete(t);
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_bool = false;
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;
bool has_typemap = (n != NULL && Getattr(n, "tmap:gotype") != NULL) || hasGoTypemap(n, type);
if (has_typemap) {
is_bool = Strcmp(gt, "bool") == 0;
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("");
Printv(ret, "_gostring_", tail, " ", name, NULL);
Delete(tail);
return ret;
} else if (is_slice) {
// Slices are always passed as a _goslice_, whether or not references
// are involved.
ret = NewString("");
Printv(ret, "_goslice_", tail, " ", name, NULL);
Delete(tail);
return ret;
} else if (is_function || is_member) {
ret = NewString("");
Printv(ret, "void*", tail, " ", name, NULL);
Delete(tail);
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);
if (SwigType_ispointer(t)) {
SwigType_del_pointer(t);
}
if (SwigType_isreference(t)) {
SwigType_del_reference(t);
}
SwigType_add_pointer(t);
ret = SwigType_lstr(t, name);
Delete(t);
Delete(tail);
return ret;
} else {
SwigType *t = SwigType_typedef_resolve_all(type);
if (!has_typemap && 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 if (is_int64) {
ret = NewString("long long ");
Append(ret, name);
} else {
ret = SwigType_lstr(t, name);
}
Delete(q);
Delete(t);
Delete(tail);
return ret;
}
}
Delete(q);
}
}
if (Language::enumLookup(t) != NULL) {
is_int = true;
} else {
SwigType *tstripped = SwigType_strip_qualifiers(t);
if (SwigType_isenum(tstripped))
is_int = true;
Delete(tstripped);
}
Delete(t);
if (is_bool) {
ret = NewString("bool ");
} else 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 {
Delete(tail);
return SwigType_lstr(type, name);
}
}
Append(ret, tail);
if (!has_typemap && SwigType_isreference(type)) {
Append(ret, "* ");
}
Append(ret, name);
Delete(tail);
return ret;
}
/* ----------------------------------------------------------------------
* 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, false, &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 && (Swig_storage_isstatic(n) || 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;
}
/* ----------------------------------------------------------------------
* goGetattr
*
* Fetch an attribute from a node but return NULL if it is the empty string.
* ---------------------------------------------------------------------- */
Node *goGetattr(Node *n, const char *name) {
Node *ret = Getattr(n, name);
if (ret != NULL && Len(ret) == 0) {
ret = NULL;
}
return ret;
}
/* ----------------------------------------------------------------------
* goTypemapLookup
*
* Look up a typemap but return NULL if it is the empty string.
* ---------------------------------------------------------------------- */
String *goTypemapLookup(const char *name, Node *node, const char *lname) {
String *ret = Swig_typemap_lookup(name, node, lname, NULL);
if (ret != NULL && Len(ret) == 0) {
ret = NULL;
}
return ret;
}
/* ----------------------------------------------------------------------
* getModuleName
*
* Return the name of a module. This is different from module path:
* "some/path/to/module" -> "module".
* ---------------------------------------------------------------------- */
String *getModuleName(String *module_path) {
char *suffix = strrchr(Char(module_path), '/');
if (suffix == NULL) {
return module_path;
}
return Str(suffix + 1);
}
}; /* 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 = "\
Go Options (available with -go)\n\
-cgo - Generate cgo input files\n\
-no-cgo - Do not generate cgo input files\n\
-gccgo - Generate code for gccgo rather than gc\n\
-go-pkgpath <p> - Like gccgo -fgo-pkgpath option\n\
-go-prefix <p> - Like gccgo -fgo-prefix option\n\
-import-prefix <p> - Prefix to add to %import directives\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\
-use-shlib - Force use of a shared library\n\
-soname <name> - Set shared library holding C/C++ code to <name>\n\
\n";