[Go] Add imtype, goin, goout, godirectorin, and godirectorout

typemaps, to support writing Go code to convert between types.
This commit is contained in:
Ian Lance Taylor 2014-09-05 17:54:19 -07:00
commit 1addbb46a8
9 changed files with 744 additions and 101 deletions

View file

@ -5,6 +5,11 @@ See the RELEASENOTES file for a summary of changes in each release.
Version 3.0.3 (in progress)
===========================
2014-09-05: ianlancetaylor
[Go] Add imtype, goin, goout, godirectorin, and
godirectorout typemaps, to support writing Go code to
convert between types.
2014-09-02: olly
[Python] Fix regression in indentation of python code produced with
-modern, introduced by changes in #188. Reported by fabiencastan

View file

@ -861,6 +861,7 @@
<li><a href="Go.html#Go_primitive_type_mappings">Default Go primitive type mappings</a>
<li><a href="Go.html#Go_output_arguments">Output arguments</a>
<li><a href="Go.html#Go_adding_additional_code">Adding additional go code</a>
<li><a href="Go.html#Go_typemaps">Go typemaps</a>
</ul>
</ul>
</div>

View file

@ -30,6 +30,7 @@
<li><a href="#Go_primitive_type_mappings">Default Go primitive type mappings</a>
<li><a href="#Go_output_arguments">Output arguments</a>
<li><a href="#Go_adding_additional_code">Adding additional go code</a>
<li><a href="#Go_typemaps">Go typemaps</a>
</ul>
</ul>
</div>
@ -692,5 +693,123 @@ func bar() {
</pre>
</div>
<H3><a name="Go_typemaps"></a>23.3.11 Go typemaps</H3>
<p>
You can use the <tt>%typemap</tt> directive to modify SWIG's default
wrapping behavior for specific C/C++ types. You need to be familiar
with the material in the general
"<a href="Typemaps.html#Typemaps">Typemaps</a>" chapter. That chapter
explains how to define a typemap. This section describes some
specific typemaps used for Go.
</p>
<p>
In general type conversion code may be written either in C/C++ or in
Go. The choice to make normally depends on where memory should be
allocated. To allocate memory controlled by the Go garbage collector,
write Go code. To allocate memory in the C/C++ heap, write C code.
</p>
<table BORDER summary="Go Typemaps">
<tr>
<td><b>Typemap</b></td>
<td><b>Description</b></td>
</tr>
<tr>
<td>gotype</td>
<td>
The Go type to use for a C++ type. This type will appear in the
generated Go wrapper function. If this is not defined SWIG will use a
default as <a href="#Go_primitive_type_mappings">described above</a>.
</td>
</tr>
<tr>
<td>imtype</td>
<td>
An intermediate Go type used by the "goin", "goout", "godirectorin",
and "godirectorout" typemaps. If this typemap is not defined for a
C/C++ type, the gotype typemape will be used. This is useful when
gotype is best converted to C/C++ using Go code.
</td>
</tr>
<tr>
<td>goin</td>
<td>
Go code to convert from gotype to imtype when calling a C/C++
function. SWIG will then internally convert imtype to a C/C++ type
and pass it down. If this is not defined no conversion is done.
</td>
</tr>
<tr>
<td>in</td>
<td>
C/C++ code to convert the internally generated C/C++ type, based on
imtype, into the C/C++ type that a function call expects. If this is
not defined the value will simply be cast to the desired type.
</td>
</tr>
<tr>
<td>out</td>
<td>
C/C++ code to convert the C/C++ type that a function call returns into
the internally generated C/C++ type, based on imtype, that will be
returned to Go. If this is not defined the value will simply be cast
to the desired type.
</td>
</tr>
<tr>
<td>goout</td>
<td>
Go code to convert a value returned from a C/C++ function from imtype
to gotype. If this is not defined no conversion is done.
</td>
</tr>
<tr>
<td>directorin</td>
<td>
C/C++ code to convert the C/C++ type used to call a director method
into the internally generated C/C++ type, based on imtype, that will
be passed to Go. If this is not defined the value will simply be cast
to the desired type.
</td>
</tr>
<tr>
<td>godirectorin</td>
<td>
Go code to convert a value used to call a director method from imtype
to gotype. If this is not defined no conversion is done.
</td>
</tr>
<tr>
<td>godirectorout</td>
<td>
Go code to convert a value returned from a director method from gotype
to imtype. If this is not defined no conversion is done.
</td>
</tr>
<tr>
<td>directorout</td>
<td>
C/C++ code to convert a value returned from a director method from the
internally generated C/C++ type, based on imtype, into the type that
the method should return If this is not defined the value will simply
be cast to the desired type.
</td>
</tr>
</table>
</body>
</html>

View file

@ -24,6 +24,10 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
CPP_TEST_CASES = \
go_inout \
go_director_inout
include $(srcdir)/../common.mk
.SUFFIXES: .cpptest .ctest .multicpptest

View file

@ -0,0 +1,32 @@
package main
import (
wrap "./go_director_inout"
)
type GoMyClass struct {}
func (p *GoMyClass) Adjust(m map[string]interface{}) wrap.GoRetStruct {
s := ""
for k, v := range m {
s += k + "," + v.(string) + ";"
}
return wrap.GoRetStruct{s}
}
func main() {
a := wrap.NewDirectorMyClass(&GoMyClass{})
m := map[string]interface{}{
"first": "second",
}
s := a.Adjust(m)
if s.Str != "first,second;" {
panic(s)
}
a = wrap.NewDirectorMyClass(nil)
s = a.Adjust(m)
if s.Str != `{"first":"second"}` {
panic(s.Str)
}
}

View file

@ -0,0 +1,35 @@
package main
import (
"encoding/json"
"fmt"
"reflect"
"./go_inout"
)
type S struct {
A int
B string
C float64
}
func (p *S) MarshalJSON() ([]byte, error) {
return json.Marshal(*p)
}
func main() {
v := &S{12, "hi", 34.5}
m := go_inout.Same(v)
want := map[string]interface{}{
// The type of A changes from int to float64 because
// JSON has no ints.
"A": float64(12),
"B": "hi",
"C": 34.5,
}
if !reflect.DeepEqual(m, want) {
fmt.Println("got", m, "want", want)
panic(m)
}
}

View file

@ -0,0 +1,121 @@
// Test the goin and goout typemaps for directors.
%module(directors="1") go_director_inout
%{
#include <string>
%}
%inline
%{
struct MyStruct {
std::string str;
};
struct RetStruct {
std::string str;
};
%}
%go_import("encoding/json")
%insert(go_header)
%{
type GoRetStruct struct {
Str string
}
%}
%typemap(gotype) RetStruct "GoRetStruct"
%typemap(imtype) RetStruct "string"
%typemap(goin) RetStruct
%{
$result = $input.Str
%}
%typemap(in) RetStruct
%{
$result.str.assign($input.p, $input.n);
%}
%typemap(out) RetStruct
%{
$result = _swig_makegostring($1.str.data(), $1.str.length());
%}
%typemap(goout) RetStruct
%{
$result = GoRetStruct{Str: $input}
%}
%typemap(godirectorout) RetStruct
%{
$result = $input.Str
%}
%typemap(directorout) RetStruct
%{
$result.str.assign($input.p, $input.n);
%}
%typemap(godirectorin) RetStruct
%{
%}
%typemap(gotype) MyStruct "map[string]interface{}"
%typemap(imtype) MyStruct "string"
%typemap(goin) MyStruct
%{
if b, err := json.Marshal($input); err != nil {
panic(err)
} else {
$result = string(b)
}
%}
%typemap(directorin) MyStruct
%{
$input = _swig_makegostring($1.str.data(), $1.str.length());
%}
%typemap(out) MyStruct
%{
$result = _swig_makegostring($1.str.data(), $1.str.length());
%}
%typemap(godirectorin) MyStruct
%{
if err := json.Unmarshal([]byte($input), &$result); err != nil {
panic(err)
}
%}
%typemap(in) MyStruct
%{
$1.str.assign($input.p, $input.n);
%}
%feature("director") MyClass;
%inline
%{
class MyClass {
public:
virtual ~MyClass() {}
virtual RetStruct Adjust(MyStruct s) {
RetStruct r;
r.str = s.str;
return r;
}
};
%}

View file

@ -0,0 +1,79 @@
// Test the goin and goout typemaps.
%module go_inout
%{
#include <string>
%}
%inline
%{
struct MyStruct {
std::string str;
};
struct RetStruct {
std::string str;
};
%}
// Write a typemap that calls C++ by converting in and out of JSON.
%go_import("encoding/json")
%insert(go_header)
%{
type In json.Marshaler
%}
%typemap(gotype) MyStruct "In"
%typemap(imtype) MyStruct "string"
%typemap(goin) MyStruct
%{
{
b, err := $input.MarshalJSON()
if err != nil {
panic(err)
}
$result = string(b)
}
%}
%typemap(in) MyStruct
%{
$1.str.assign($input.p, $input.n);
%}
%typemap(gotype) RetStruct "map[string]interface{}"
%typemap(imtype) RetStruct "string"
%typemap(out) RetStruct
%{
$result = _swig_makegostring($1.str.data(), $1.str.length());
%}
%typemap(goout) RetStruct
%{
if err := json.Unmarshal([]byte($1), &$result); err != nil {
panic(err)
}
%}
%inline
%{
RetStruct Same(MyStruct s)
{
RetStruct r;
r.str = s.str;
return r;
}
%}

View file

@ -867,6 +867,8 @@ private:
emit_attach_parmmaps(parms, dummy);
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("imtype", parms, dummy);
int parm_count = emit_num_arguments(parms);
int required_count = emit_num_required(parms);
@ -884,26 +886,28 @@ private:
receiver = NULL;
}
String *goout = Swig_typemap_lookup("goout", n, "swig_r", NULL);
bool add_to_interface = (interfaces && !is_constructor && !is_destructor && !is_static && !overname && checkFunctionVisibility(n, NULL));
bool needs_wrapper = (gccgo_flag || receiver || is_constructor || is_destructor || parm_count > required_count);
// See whether any of the function parameters are represented by
// interface values When calling the C++ code, we need to convert
// interface values. When calling the C++ code, we need to convert
// back to a uintptr.
if (!needs_wrapper) {
Parm *p = parms;
for (int i = 0; i < parm_count; ++i) {
p = getParm(p);
String *ty = Getattr(p, "type");
if (goTypeIsInterface(p, ty)) {
if (goTypeIsInterface(p, ty) || Getattr(p, "tmap:goin") != NULL) {
needs_wrapper = true;
break;
}
p = nextParm(p);
}
}
if (goTypeIsInterface(n, result)) {
if (goTypeIsInterface(n, result) || goout != NULL) {
needs_wrapper = true;
}
@ -1077,46 +1081,49 @@ private:
}
}
String *call = NewString("");
bool need_return_var = SwigType_type(result) != T_VOID && ((gccgo_flag && is_constructor) || goout != NULL);
if (need_return_var) {
Printv(f_go_wrappers, "\tvar swig_r ", NULL);
if (is_constructor) {
String *cl = exportedName(class_name);
Printv(f_go_wrappers, cl, NULL);
Delete(cl);
} else {
Printv(f_go_wrappers, goImType(n, result), NULL);
}
Printv(f_go_wrappers, "\n", NULL);
}
if (gccgo_flag) {
if (!is_constructor) {
Printv(f_go_wrappers, "\tdefer SwigCgocallDone()\n", NULL);
Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL);
} else {
// For a constructor the wrapper function will return a
// uintptr but we will return an interface. We want to
// convert the uintptr to the interface after calling
// SwigCgocallDone, so that we don't try to allocate memory
// while the Go scheduler can't see us.
Printv(f_go_wrappers, "\tvar done bool\n", NULL);
Printv(f_go_wrappers, "\tdefer func() {\n", NULL);
Printv(f_go_wrappers, "\t\tif !done {\n", NULL);
Printv(f_go_wrappers, "\t\t\tSwigCgocallDone()\n", NULL);
Printv(f_go_wrappers, "\t\t}\n", NULL);
Printv(f_go_wrappers, "\t}()\n", NULL);
Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL);
if (goout != NULL || is_constructor) {
Printv(call, "\tfunc() {\n", NULL);
}
Printv(call, "\tdefer SwigCgocallDone()\n", NULL);
Printv(call, "\tSwigCgocall()\n", NULL);
}
Printv(f_go_wrappers, "\t", NULL);
Printv(call, "\t", NULL);
if (SwigType_type(result) != T_VOID) {
if (gccgo_flag && is_constructor) {
Printv(f_go_wrappers, "swig_r := ", NULL);
if (need_return_var) {
Printv(call, "swig_r = ", NULL);
} else {
Printv(f_go_wrappers, "return ", NULL);
Printv(call, "return ", NULL);
}
}
Printv(f_go_wrappers, wrapper_name, "(", NULL);
Printv(call, wrapper_name, "(", NULL);
if (parm_count > required_count) {
Printv(f_go_wrappers, "len(_swig_args)", NULL);
Printv(call, "len(_swig_args)", NULL);
}
if (base && receiver) {
if (parm_count > required_count) {
Printv(f_go_wrappers, ", ", NULL);
Printv(call, ", ", NULL);
}
Printv(f_go_wrappers, "_swig_base", NULL);
Printv(call, "_swig_base", NULL);
}
Parm *p = parms;
@ -1124,26 +1131,53 @@ private:
p = getParm(p);
if (i > 0 || (base && receiver)
|| parm_count > required_count) {
Printv(f_go_wrappers, ", ", NULL);
Printv(call, ", ", NULL);
}
Printv(f_go_wrappers, Getattr(p, "lname"), NULL);
// If this is a destructor, then the C function expects the
// C++ value, and we have the interface. We need to get the
// C++ value. The same is true for a type represented as an
// interface.
if ((i == 0 && is_destructor) || ((i > 0 || !receiver || base || is_constructor) && goTypeIsInterface(p, Getattr(p, "type")))) {
Printv(f_go_wrappers, ".Swigcptr()", NULL);
SwigType *pt = Getattr(p, "type");
String *ln = Getattr(p, "lname");
String *goin = Getattr(p, "tmap:goin");
if (goin == NULL) {
Printv(call, ln, NULL);
if ((i == 0 && is_destructor) || ((i > 0 || !receiver || base || is_constructor) && goTypeIsInterface(p, pt))) {
Printv(call, ".Swigcptr()", NULL);
}
} else {
String *ivar = NewString("");
Printf(ivar, "_swig_i_%d", i);
String *itm = goImType(p, pt);
Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, NULL);
goin = Copy(goin);
Replaceall(goin, "$input", ln);
Replaceall(goin, "$result", ivar);
Printv(f_go_wrappers, goin, NULL);
Delete(goin);
Printv(call, ivar, NULL);
}
p = nextParm(p);
}
Printv(f_go_wrappers, ")\n", NULL);
Printv(call, ")\n", NULL);
if (gccgo_flag && is_constructor) {
Printv(f_go_wrappers, "\tSwigCgocallDone()\n", NULL);
Printv(f_go_wrappers, "\tdone = true\n", NULL);
Printv(f_go_wrappers, "\treturn swig_r\n", NULL);
if (gccgo_flag && (goout != NULL || is_constructor)) {
Printv(call, "\t}()\n", NULL);
}
Printv(f_go_wrappers, call, NULL);
Delete(call);
if (need_return_var) {
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, NULL);
Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL);
}
}
Printv(f_go_wrappers, "}\n", NULL);
@ -1348,6 +1382,7 @@ private:
String *ln = Getattr(p, "lname");
String *input = NewString("");
Printv(input, "swig_a->", ln, NULL);
tm = Copy(tm);
Replaceall(tm, "$input", input);
Setattr(p, "emit:input", input);
if (i < required_count) {
@ -1357,6 +1392,7 @@ private:
Printv(f->code, "\t\t", tm, "\n", NULL);
Printv(f->code, "\t}\n", NULL);
}
Delete(tm);
}
p = nextParm(p);
}
@ -1486,6 +1522,7 @@ private:
String *ln = Getattr(p, "lname");
String *pn = NewString("g");
Append(pn, ln);
tm = Copy(tm);
Replaceall(tm, "$input", pn);
Setattr(p, "emit:input", pn);
if (i < required_count) {
@ -1495,6 +1532,7 @@ private:
Printv(f->code, " ", tm, "\n", NULL);
Printv(f->code, " }\n", NULL);
}
Delete(tm);
}
p = nextParm(p);
@ -1543,17 +1581,19 @@ private:
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");
}
}
}
/* -----------------------------------------------------------------------
* getGoAction()
* emitGoAction()
*
* Get the action of the function. This is used for C/C++ function.
* 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) {
@ -1626,9 +1666,11 @@ private:
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");
}
}
@ -1650,8 +1692,10 @@ private:
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");
}
}
@ -2047,7 +2091,7 @@ private:
}
Append(f_go_wrappers, interfaces);
Printf(f_go_wrappers, "}\n\n", NULL);
Printv(f_go_wrappers, "}\n\n", NULL);
Delete(interfaces);
interfaces = NULL;
@ -2640,6 +2684,7 @@ private:
DelWrapper(dummy);
Swig_typemap_attach_parms("gotype", parms, NULL);
Swig_typemap_attach_parms("imtype", parms, NULL);
int parm_count = emit_num_arguments(parms);
String *func_name = NewString("NewDirector");
@ -3075,6 +3120,7 @@ private:
DelWrapper(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");
@ -3122,6 +3168,8 @@ private:
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);
if (!is_ignored) {
// We use an interface to see if this method is defined in Go.
@ -3234,29 +3282,82 @@ private:
if (GetFlag(n, "abstract")) {
Printv(f_go_wrappers, "\tpanic(\"call to pure virtual method\")\n", NULL);
} else {
if (gccgo_flag) {
Printv(f_go_wrappers, "\tdefer SwigCgocallDone()\n", NULL);
Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL);
String *goout = NULL;
if (SwigType_type(result) != T_VOID) {
Printv(f_go_wrappers, "\tvar swig_r ", goImType(n, result), "\n", NULL);
goout = Swig_typemap_lookup("goout", n, "swig_r", NULL);
}
Printv(f_go_wrappers, "\t", NULL);
if (SwigType_type(result) != T_VOID) {
Printv(f_go_wrappers, "return ", NULL);
String *call = NewString("");
if (gccgo_flag) {
if (goout != NULL) {
Printv(call, "\tfunc() {\n", NULL);
}
Printv(call, "\tdefer SwigCgocallDone()\n", NULL);
Printv(call, "\tSwigCgocall()\n", NULL);
}
Printv(f_go_wrappers, upcall_gc_name, "(swig_p.", go_type_name, NULL);
Printv(call, "\t", NULL);
if (SwigType_type(result) != T_VOID) {
Printv(call, "swig_r = ", NULL);
}
Printv(call, upcall_gc_name, "(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");
Printv(f_go_wrappers, ", ", Getattr(p, "lname"), NULL);
if (goTypeIsInterface(p, pt)) {
Printv(f_go_wrappers, ".Swigcptr()", NULL);
String *ln = Getattr(p, "lname");
// This is an ordinary call from Go to C++, so adjust using
// the goin typemap.
String *goin = Getattr(p, "tmap:goin");
if (goin == NULL) {
Printv(call, ln, NULL);
if (goTypeIsInterface(p, pt)) {
Printv(call, ".Swigcptr()", NULL);
}
} else {
String *ivar = NewString("");
Printf(ivar, "_swig_i_%d", i);
String *itm = goImType(p, pt);
Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, NULL);
goin = Copy(goin);
Replaceall(goin, "$input", ln);
Replaceall(goin, "$result", ivar);
Printv(f_go_wrappers, goin, NULL);
Delete(goin);
Printv(call, ivar, NULL);
Delete(ivar);
}
p = nextParm(p);
}
Printv(f_go_wrappers, ")\n", NULL);
Printv(call, ")\n", NULL);
if (gccgo_flag && goout != NULL) {
Printv(call, "\t}()\n", 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 = 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, NULL);
Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL);
}
}
}
Printv(f_go_wrappers, "}\n\n", NULL);
@ -3389,29 +3490,83 @@ private:
Printv(f_go_wrappers, " {\n", NULL);
if (gccgo_flag) {
Printv(f_go_wrappers, "\tdefer SwigCgocallDone()\n", NULL);
Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL);
String *goout = NULL;
if (SwigType_type(result) != T_VOID) {
Printv(f_go_wrappers, "\tvar swig_r ", goImType(n, result), "\n", NULL);
goout = Swig_typemap_lookup("goout", n, "swig_r", NULL);
}
Printv(f_go_wrappers, "\t", NULL);
if (SwigType_type(result) != T_VOID) {
Printv(f_go_wrappers, "return ", NULL);
String *call = NewString("");
if (gccgo_flag) {
if (goout != NULL) {
Printv(call, "\tfunc() {\n", NULL);
}
Printv(call, "\tdefer SwigCgocallDone()\n", NULL);
Printv(call, "\tSwigCgocall()\n", NULL);
}
Printv(f_go_wrappers, upcall_gc_name, "(p.(*", director_struct_name, ").", go_type_name, NULL);
Printv(call, "\t", NULL);
if (SwigType_type(result) != T_VOID) {
Printv(call, "swig_r = ", NULL);
}
Printv(call, upcall_gc_name, "(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");
Printv(f_go_wrappers, ", ", Getattr(p, "lname"), NULL);
String *ln = Copy(Getattr(p, "lname"));
if (goTypeIsInterface(p, pt)) {
Printv(f_go_wrappers, ".Swigcptr()", NULL);
Printv(ln, ".Swigcptr()", NULL);
}
String *goin = Getattr(p, "tmap:goin");
if (goin == NULL) {
Printv(call, ln, NULL);
} else {
String *ivar = NewString("");
Printf(ivar, "_swig_i_%d", i);
String *itm = goImType(p, pt);
Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, NULL);
goin = Copy(goin);
Replaceall(goin, "$input", ln);
Replaceall(goin, "$result", ivar);
Printv(f_go_wrappers, goin, NULL);
Delete(goin);
Printv(call, ivar, NULL);
Delete(ivar);
}
Delete(ln);
p = nextParm(p);
}
Printv(f_go_wrappers, ")\n", NULL);
Printv(call, ")\n", NULL);
if (gccgo_flag && goout != NULL) {
Printv(call, "\t}()\n", 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 = 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, NULL);
Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL);
}
}
Printv(f_go_wrappers, "}\n\n", NULL);
}
@ -3437,34 +3592,53 @@ private:
}
Printv(f_go_wrappers, "{\n", NULL);
if (gccgo_flag) {
Printv(f_go_wrappers, "\tSwigCgocallBack()\n", NULL);
Printv(f_go_wrappers, "\tdefer SwigCgocallBackDone()\n", NULL);
}
Printv(f_go_wrappers, "\t", NULL);
if (is_ignored) {
Printv(f_go_wrappers, "return\n", NULL);
Printv(f_go_wrappers, "\treturn\n", NULL);
} else {
bool result_is_interface = false;
String *goout = NULL;
if (SwigType_type(result) != T_VOID) {
Printv(f_go_wrappers, "return ", NULL);
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 = Swig_typemap_lookup("godirectorout", n, "swig_r", NULL);
}
String *call = NewString("");
if (gccgo_flag) {
if (goout != NULL) {
Printv(call, "\tfunc() {\n", NULL);
}
Printv(call, "\tSwigCgocallBack()\n", NULL);
Printv(call, "\tdefer SwigCgocallBackDone()\n", NULL);
}
Printv(call, "\t", NULL);
if (SwigType_type(result) != T_VOID) {
Printv(call, "swig_r = ", NULL);
if (result_is_interface) {
Printv(f_go_wrappers, result_wrapper, "(", NULL);
Printv(call, result_wrapper, "(", NULL);
}
}
Printv(f_go_wrappers, "p.", go_with_over_name, "(", NULL);
Printv(call, "p.", go_with_over_name, "(", NULL);
p = parms;
for (int i = 0; i < parm_count; ++i) {
p = getParm(p);
if (i > 0) {
Printv(f_go_wrappers, ", ", NULL);
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.
@ -3473,26 +3647,64 @@ private:
// Passing is_result as true to goWrapperType gives us the
// name of the Go type we need to convert to an interface.
String *wt = goWrapperType(p, pt, true);
Printv(f_go_wrappers, wt, "(", NULL);
Printv(ln, wt, "(", NULL);
Delete(wt);
}
Printv(f_go_wrappers, Getattr(p, "lname"), NULL);
Printv(ln, Getattr(p, "lname"), NULL);
if (is_interface) {
Printv(f_go_wrappers, ")", NULL);
Printv(ln, ")", NULL);
}
String *goin = Getattr(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, NULL);
goin = Copy(goin);
Replaceall(goin, "$input", ln);
Replaceall(goin, "$result", ivar);
Printv(f_go_wrappers, goin, NULL);
Delete(goin);
Printv(call, ivar, NULL);
Delete(ivar);
}
Delete(ln);
p = nextParm(p);
}
Printv(f_go_wrappers, ")", NULL);
Printv(call, ")", NULL);
if (result_is_interface) {
Printv(f_go_wrappers, ".Swigcptr())", NULL);
Printv(call, ".Swigcptr())", NULL);
}
Printv(call, "\n", NULL);
if (gccgo_flag && goout != NULL) {
Printv(call, "\t}()\n", NULL);
}
Printv(f_go_wrappers, "\n", 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, NULL);
Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL);
}
}
}
Printv(f_go_wrappers, "}\n\n", NULL);
@ -3610,6 +3822,7 @@ private:
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);
String *ln = Getattr(p, "lname");
String *input = NewString("");
Printv(input, "swig_a.", ln, NULL);
@ -3618,6 +3831,7 @@ private:
Replaceall(tm, "$owner", "0");
Delete(input);
Printv(w->code, "\t", tm, "\n", NULL);
Delete(tm);
}
p = Getattr(p, "tmap:directorin:next");
}
@ -3683,9 +3897,11 @@ private:
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);
}
@ -3722,9 +3938,11 @@ private:
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", NIL);
Delete(tm);
p = Getattr(p, "tmap:directorargout:next");
} else {
p = nextSibling(p);
@ -4462,7 +4680,19 @@ private:
* ---------------------------------------------------------------------- */
String *goType(Node *n, SwigType *type) {
return goTypeWithInfo(n, type, NULL);
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);
}
/* ----------------------------------------------------------------------
@ -4470,6 +4700,8 @@ private:
*
* 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
@ -4477,24 +4709,39 @@ private:
* forth with C/C++.
* ---------------------------------------------------------------------- */
String *goTypeWithInfo(Node *n, SwigType *type, bool *p_is_interface) {
String *goTypeWithInfo(Node *n, SwigType *type, bool use_imtype, bool *p_is_interface) {
if (p_is_interface) {
*p_is_interface = false;
}
String *ret;
if (n && Cmp(type, Getattr(n, "type")) == 0) {
ret = NULL;
if (Strcmp(Getattr(n, "nodeType"), "parm") == 0) {
ret = Getattr(n, "tmap:gotype");
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) {
ret = Swig_typemap_lookup("gotype", n, "", NULL);
}
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);
}
} else {
Parm *p = NewParm(type, "goType", n);
ret = Swig_typemap_lookup("gotype", p, "", NULL);
Delete(p);
}
if (ret && Strstr(ret, "$gotypename") != 0) {
@ -4563,7 +4810,7 @@ private:
ret = NewString("uintptr");
} else {
bool is_interface;
String *base = goTypeWithInfo(n, r, &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
@ -4627,12 +4874,12 @@ private:
if (add_pointer) {
SwigType_add_pointer(r);
}
ret = goTypeWithInfo(n, r, p_is_interface);
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, p_is_interface);
ret = goTypeWithInfo(n, r, false, p_is_interface);
Delete(r);
} else if (SwigType_isvarargs(t)) {
ret = NewString("[]interface{}");
@ -4658,7 +4905,7 @@ private:
String *goWrapperType(Node *n, SwigType *type, bool is_result) {
bool is_interface;
String *ret = goTypeWithInfo(n, type, &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) {
@ -4742,7 +4989,7 @@ private:
String *gcCTypeForGoValue(Node *n, SwigType *type, String *name) {
bool is_interface;
String *gt = goTypeWithInfo(n, type, &is_interface);
String *gt = goTypeWithInfo(n, type, true, &is_interface);
bool is_string = Strcmp(gt, "string") == 0;
bool is_slice = Strncmp(gt, "[]", 2) == 0;
bool is_function = Strcmp(gt, "_swig_fnptr") == 0;
@ -4885,7 +5132,7 @@ private:
bool goTypeIsInterface(Node *n, SwigType *type) {
bool is_interface;
Delete(goTypeWithInfo(n, type, &is_interface));
Delete(goTypeWithInfo(n, type, false, &is_interface));
return is_interface;
}