mirror of
https://github.com/mappu/miqt.git
synced 2025-01-03 06:08:38 +00:00
genbindings/go: refactor to reuse template emitters
This commit is contained in:
parent
a1d6b6a543
commit
15f4c367d0
@ -178,6 +178,8 @@ func (gfs *goFileState) emitParametersGo2CABIForwarding(m CppMethod) (preamble s
|
|||||||
// QApplication constructor. Convert 'args' into Qt's wanted types
|
// QApplication constructor. Convert 'args' into Qt's wanted types
|
||||||
// Qt has a warning in the docs saying these pointers must be valid
|
// Qt has a warning in the docs saying these pointers must be valid
|
||||||
// for the entire lifetype of QApplication, so, malloc + never free
|
// for the entire lifetype of QApplication, so, malloc + never free
|
||||||
|
// This transformation only affects the Go side. The CABI side is
|
||||||
|
// projected naturally
|
||||||
|
|
||||||
preamble += "// Convert []string to long-lived int& argc, char** argv, never call free()\n"
|
preamble += "// Convert []string to long-lived int& argc, char** argv, never call free()\n"
|
||||||
preamble += "argc := (*C.int)(C.malloc(8))\n"
|
preamble += "argc := (*C.int)(C.malloc(8))\n"
|
||||||
@ -193,13 +195,30 @@ func (gfs *goFileState) emitParametersGo2CABIForwarding(m CppMethod) (preamble s
|
|||||||
// Skip this parameter, already handled
|
// Skip this parameter, already handled
|
||||||
skipNext = false
|
skipNext = false
|
||||||
|
|
||||||
} else if p.ParameterType == "QString" {
|
} else {
|
||||||
|
addPreamble, rvalue := gfs.emitParameterGo2CABIForwarding(p)
|
||||||
|
|
||||||
|
preamble += addPreamble
|
||||||
|
tmp = append(tmp, rvalue)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return preamble, strings.Join(tmp, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble string, rvalue string) {
|
||||||
|
|
||||||
|
nameprefix := strings.Replace(strings.Replace(p.ParameterName, `[`, `_`, -1), `]`, "", -1)
|
||||||
|
|
||||||
|
if p.ParameterType == "QString" {
|
||||||
// Go: convert string -> miqt_string*
|
// Go: convert string -> miqt_string*
|
||||||
// CABI: convert miqt_string* -> real QString
|
// CABI: convert miqt_string* -> real QString
|
||||||
|
|
||||||
preamble += p.ParameterName + "_ms := miqt_strdupg(" + p.ParameterName + ")\n"
|
preamble += nameprefix + "_ms := miqt_strdupg(" + p.ParameterName + ")\n"
|
||||||
preamble += "defer C.free(" + p.ParameterName + "_ms)\n"
|
preamble += "defer C.free(" + nameprefix + "_ms)\n"
|
||||||
tmp = append(tmp, "(*C.struct_miqt_string)("+p.ParameterName+"_ms)")
|
|
||||||
|
rvalue = "(*C.struct_miqt_string)(" + nameprefix + "_ms)"
|
||||||
|
|
||||||
} else if listType, ok := p.QListOf(); ok {
|
} else if listType, ok := p.QListOf(); ok {
|
||||||
// QList<T>
|
// QList<T>
|
||||||
@ -209,71 +228,49 @@ func (gfs *goFileState) emitParametersGo2CABIForwarding(m CppMethod) (preamble s
|
|||||||
gfs.imports["runtime"] = struct{}{}
|
gfs.imports["runtime"] = struct{}{}
|
||||||
gfs.imports["unsafe"] = struct{}{}
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
|
|
||||||
if listType.ParameterType == "QString" {
|
|
||||||
// Combo
|
|
||||||
|
|
||||||
preamble += "// For the C ABI, malloc two C arrays; raw char* pointers and their lengths\n"
|
|
||||||
preamble += p.ParameterName + "_CArray := (*[0xffff]" + listType.parameterTypeCgo() + ")(C.malloc(C.size_t(8 * len(" + p.ParameterName + "))))\n"
|
|
||||||
preamble += "defer C.free(unsafe.Pointer(" + p.ParameterName + "_CArray))\n"
|
|
||||||
|
|
||||||
preamble += "for i := range " + p.ParameterName + "{\n"
|
|
||||||
preamble += "single_ms := miqt_strdupg(" + p.ParameterName + "[i])\n"
|
|
||||||
preamble += "defer C.free(single_ms)\n"
|
|
||||||
preamble += p.ParameterName + "_CArray[i] = (*C.struct_miqt_string)(single_ms)\n"
|
|
||||||
preamble += "}\n"
|
|
||||||
|
|
||||||
preamble += p.ParameterName + "_ma := &C.struct_miqt_array{len: C.size_t(len(" + p.ParameterName + ")), data: unsafe.Pointer(" + p.ParameterName + "_CArray)}\n"
|
|
||||||
preamble += "defer runtime.KeepAlive(unsafe.Pointer(" + p.ParameterName + "_ma))\n"
|
|
||||||
|
|
||||||
tmp = append(tmp, p.ParameterName+"_ma")
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
preamble += "// For the C ABI, malloc a C array of raw pointers\n"
|
preamble += "// For the C ABI, malloc a C array of raw pointers\n"
|
||||||
preamble += p.ParameterName + "_CArray := (*[0xffff]" + listType.parameterTypeCgo() + ")(C.malloc(C.size_t(8 * len(" + p.ParameterName + "))))\n"
|
preamble += nameprefix + "_CArray := (*[0xffff]" + listType.parameterTypeCgo() + ")(C.malloc(C.size_t(8 * len(" + p.ParameterName + "))))\n"
|
||||||
preamble += "defer C.free(unsafe.Pointer(" + p.ParameterName + "_CArray))\n"
|
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_CArray))\n"
|
||||||
|
|
||||||
preamble += "for i := range " + p.ParameterName + "{\n"
|
preamble += "for i := range " + p.ParameterName + "{\n"
|
||||||
if listType.QtClassType() {
|
|
||||||
preamble += p.ParameterName + "_CArray[i] = " + p.ParameterName + "[i].cPointer()\n"
|
listType.ParameterName = p.ParameterName + "[i]"
|
||||||
} else {
|
addPreamble, innerRvalue := gfs.emitParameterGo2CABIForwarding(listType)
|
||||||
preamble += p.ParameterName + "_CArray[i] = (" + listType.parameterTypeCgo() + ")(" + p.ParameterName + "[i])\n"
|
preamble += addPreamble
|
||||||
}
|
preamble += nameprefix + "_CArray[i] = " + innerRvalue + "\n"
|
||||||
preamble += "}\n"
|
preamble += "}\n"
|
||||||
|
|
||||||
preamble += p.ParameterName + "_ma := &C.struct_miqt_array{len: C.size_t(len(" + p.ParameterName + ")), data: unsafe.Pointer(" + p.ParameterName + "_CArray)}\n"
|
preamble += p.ParameterName + "_ma := &C.struct_miqt_array{len: C.size_t(len(" + p.ParameterName + ")), data: unsafe.Pointer(" + nameprefix + "_CArray)}\n"
|
||||||
preamble += "defer runtime.KeepAlive(unsafe.Pointer(" + p.ParameterName + "_ma))\n"
|
preamble += "defer runtime.KeepAlive(unsafe.Pointer(" + nameprefix + "_ma))\n"
|
||||||
|
|
||||||
tmp = append(tmp, p.ParameterName+"_ma")
|
rvalue = p.ParameterName + "_ma"
|
||||||
}
|
|
||||||
|
|
||||||
} else if p.Pointer && p.ParameterType == "char" {
|
} else if p.Pointer && p.ParameterType == "char" {
|
||||||
// Single char* argument
|
// Single char* argument
|
||||||
gfs.imports["unsafe"] = struct{}{}
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
preamble += p.ParameterName + "_Cstring := C.CString(" + p.ParameterName + ")\n"
|
preamble += nameprefix + "_Cstring := C.CString(" + p.ParameterName + ")\n"
|
||||||
preamble += "defer C.free(unsafe.Pointer(" + p.ParameterName + "_Cstring))\n"
|
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_Cstring))\n"
|
||||||
tmp = append(tmp, p.ParameterName+"_Cstring")
|
rvalue = nameprefix + "_Cstring"
|
||||||
|
|
||||||
} else if /*(p.Pointer || p.ByRef) &&*/ p.QtClassType() {
|
} else if /*(p.Pointer || p.ByRef) &&*/ p.QtClassType() {
|
||||||
// The C++ type is a pointer to Qt class
|
// The C++ type is a pointer to Qt class
|
||||||
// We want our functions to accept the Go wrapper type, and forward as cPointer()
|
// We want our functions to accept the Go wrapper type, and forward as cPointer()
|
||||||
tmp = append(tmp, p.ParameterName+".cPointer()")
|
rvalue = p.ParameterName + ".cPointer()"
|
||||||
|
|
||||||
} else if p.IntType() || p.ParameterType == "bool" {
|
} else if p.IntType() || p.ParameterType == "bool" {
|
||||||
if p.Pointer || p.ByRef {
|
if p.Pointer || p.ByRef {
|
||||||
gfs.imports["unsafe"] = struct{}{}
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
tmp = append(tmp, "("+p.parameterTypeCgo()+")(unsafe.Pointer("+p.ParameterName+"))") // n.b. This may not work if the integer type conversion was wrong
|
rvalue = "(" + p.parameterTypeCgo() + ")(unsafe.Pointer(" + p.ParameterName + "))" // n.b. This may not work if the integer type conversion was wrong
|
||||||
} else {
|
} else {
|
||||||
tmp = append(tmp, "("+p.parameterTypeCgo()+")("+p.ParameterName+")")
|
rvalue = "(" + p.parameterTypeCgo() + ")(" + p.ParameterName + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Default
|
// Default
|
||||||
tmp = append(tmp, p.ParameterName)
|
rvalue = p.ParameterName
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return preamble, strings.Join(tmp, ", ")
|
return preamble, rvalue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue string) string {
|
func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue string) string {
|
||||||
@ -309,45 +306,24 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
|||||||
gfs.imports["unsafe"] = struct{}{}
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
|
|
||||||
shouldReturn = "var " + namePrefix + "_ma *C.struct_miqt_array = "
|
shouldReturn = "var " + namePrefix + "_ma *C.struct_miqt_array = "
|
||||||
if t.ParameterType == "QString" {
|
|
||||||
// Combo
|
|
||||||
|
|
||||||
afterword += namePrefix + "_ret := make([]string, int(" + namePrefix + "_ma.len))\n"
|
afterword += namePrefix + "_ret := make([]" + t.RenderTypeGo() + ", int(" + namePrefix + "_ma.len))\n"
|
||||||
afterword += "_outCast := (*[0xffff]*C.struct_miqt_string)(unsafe.Pointer(" + namePrefix + "_ma.data)) // hey ya\n"
|
afterword += namePrefix + "_outCast := (*[0xffff]" + t.parameterTypeCgo() + ")(unsafe.Pointer(" + namePrefix + "_ma.data)) // hey ya\n"
|
||||||
afterword += "for i := 0; i < int(" + namePrefix + "_ma.len); i++ {\n"
|
afterword += "for i := 0; i < int(" + namePrefix + "_ma.len); i++ {\n"
|
||||||
afterword += namePrefix + "_ret[i] = C.GoStringN(&_outCast[i].data, C.int(int64(_outCast[i].len)))\n"
|
|
||||||
afterword += "C.free(unsafe.Pointer(_outCast[i])) // free the inner miqt_string*\n"
|
afterword += gfs.emitCabiToGo(namePrefix+"_ret[i] = ", t, namePrefix+"_outCast[i]")
|
||||||
|
|
||||||
afterword += "}\n"
|
afterword += "}\n"
|
||||||
afterword += "C.free(unsafe.Pointer(" + namePrefix + "_ma))\n"
|
afterword += "C.free(unsafe.Pointer(" + namePrefix + "_ma))\n"
|
||||||
afterword += assignExpr + " " + namePrefix + "_ret\n"
|
afterword += assignExpr + " " + namePrefix + "_ret\n"
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
afterword += "" + namePrefix + "_ret := make([]" + t.RenderTypeGo() + ", int(" + namePrefix + "_ma.len))\n"
|
|
||||||
afterword += "_outCast := (*[0xffff]" + t.parameterTypeCgo() + ")(unsafe.Pointer(" + namePrefix + "_ma.data)) // mrs jackson\n"
|
|
||||||
afterword += "for i := 0; i < int(" + namePrefix + "_ma.len); i++ {\n"
|
|
||||||
if t.QtClassType() {
|
|
||||||
if !t.Pointer {
|
|
||||||
// new, but then dereference it
|
|
||||||
afterword += "" + namePrefix + "_ret[i] = *new" + cabiClassName(t.ParameterType) + "(_outCast[i])\n"
|
|
||||||
} else {
|
|
||||||
afterword += "" + namePrefix + "_ret[i] = new" + cabiClassName(t.ParameterType) + "(_outCast[i])\n"
|
|
||||||
}
|
|
||||||
} else { // plain int type
|
|
||||||
afterword += "" + namePrefix + "_ret[i] = (" + t.RenderTypeGo() + ")(_outCast[i])\n"
|
|
||||||
}
|
|
||||||
afterword += "}\n"
|
|
||||||
afterword += "C.free(unsafe.Pointer(" + namePrefix + "_ma))\n"
|
|
||||||
afterword += assignExpr + " " + namePrefix + "_ret\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if rt.QtClassType() {
|
} else if rt.QtClassType() {
|
||||||
// Construct our Go type based on this inner CABI type
|
// Construct our Go type based on this inner CABI type
|
||||||
shouldReturn = "" + namePrefix + "_ret := "
|
shouldReturn = "" + namePrefix + "_ret := "
|
||||||
|
|
||||||
if rt.Pointer || rt.ByRef {
|
if rt.Pointer || rt.ByRef {
|
||||||
gfs.imports["unsafe"] = struct{}{}
|
gfs.imports["unsafe"] = struct{}{}
|
||||||
afterword = assignExpr + " new" + cabiClassName(rt.ParameterType) + "_U(unsafe.Pointer(" + namePrefix + "_ret))"
|
return assignExpr + " new" + cabiClassName(rt.ParameterType) + "_U(unsafe.Pointer(" + rvalue + "))"
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// This is return by value, but CABI has new'd it into a
|
// This is return by value, but CABI has new'd it into a
|
||||||
@ -371,8 +347,8 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
|||||||
|
|
||||||
} else if rt.IntType() || rt.ParameterType == "bool" {
|
} else if rt.IntType() || rt.ParameterType == "bool" {
|
||||||
// Need to cast Cgo type to Go int type
|
// Need to cast Cgo type to Go int type
|
||||||
shouldReturn = "" + namePrefix + "_ret := "
|
// Optimize assignment to avoid temporary
|
||||||
afterword += assignExpr + "(" + rt.RenderTypeGo() + ")(" + namePrefix + "_ret)\n"
|
return assignExpr + "(" + rt.RenderTypeGo() + ")(" + rvalue + ")\n"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user