mirror of
https://github.com/mappu/miqt.git
synced 2024-12-22 08:58:37 +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
|
||||
// Qt has a warning in the docs saying these pointers must be valid
|
||||
// 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 += "argc := (*C.int)(C.malloc(8))\n"
|
||||
@ -193,89 +195,84 @@ func (gfs *goFileState) emitParametersGo2CABIForwarding(m CppMethod) (preamble s
|
||||
// Skip this parameter, already handled
|
||||
skipNext = false
|
||||
|
||||
} else if p.ParameterType == "QString" {
|
||||
// Go: convert string -> miqt_string*
|
||||
// CABI: convert miqt_string* -> real QString
|
||||
|
||||
preamble += p.ParameterName + "_ms := miqt_strdupg(" + p.ParameterName + ")\n"
|
||||
preamble += "defer C.free(" + p.ParameterName + "_ms)\n"
|
||||
tmp = append(tmp, "(*C.struct_miqt_string)("+p.ParameterName+"_ms)")
|
||||
|
||||
} else if listType, ok := p.QListOf(); ok {
|
||||
// QList<T>
|
||||
// Go: convert T[] -> t* and len
|
||||
// CABI: create a real QList<>
|
||||
|
||||
gfs.imports["runtime"] = 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 += 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"
|
||||
if listType.QtClassType() {
|
||||
preamble += p.ParameterName + "_CArray[i] = " + p.ParameterName + "[i].cPointer()\n"
|
||||
} else {
|
||||
preamble += p.ParameterName + "_CArray[i] = (" + listType.parameterTypeCgo() + ")(" + p.ParameterName + "[i])\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 if p.Pointer && p.ParameterType == "char" {
|
||||
// Single char* argument
|
||||
gfs.imports["unsafe"] = struct{}{}
|
||||
preamble += p.ParameterName + "_Cstring := C.CString(" + p.ParameterName + ")\n"
|
||||
preamble += "defer C.free(unsafe.Pointer(" + p.ParameterName + "_Cstring))\n"
|
||||
tmp = append(tmp, p.ParameterName+"_Cstring")
|
||||
|
||||
} else if /*(p.Pointer || p.ByRef) &&*/ p.QtClassType() {
|
||||
// The C++ type is a pointer to Qt class
|
||||
// We want our functions to accept the Go wrapper type, and forward as cPointer()
|
||||
tmp = append(tmp, p.ParameterName+".cPointer()")
|
||||
|
||||
} else if p.IntType() || p.ParameterType == "bool" {
|
||||
if p.Pointer || p.ByRef {
|
||||
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
|
||||
} else {
|
||||
tmp = append(tmp, "("+p.parameterTypeCgo()+")("+p.ParameterName+")")
|
||||
}
|
||||
|
||||
} else {
|
||||
// Default
|
||||
tmp = append(tmp, p.ParameterName)
|
||||
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*
|
||||
// CABI: convert miqt_string* -> real QString
|
||||
|
||||
preamble += nameprefix + "_ms := miqt_strdupg(" + p.ParameterName + ")\n"
|
||||
preamble += "defer C.free(" + nameprefix + "_ms)\n"
|
||||
|
||||
rvalue = "(*C.struct_miqt_string)(" + nameprefix + "_ms)"
|
||||
|
||||
} else if listType, ok := p.QListOf(); ok {
|
||||
// QList<T>
|
||||
// Go: convert T[] -> t* and len
|
||||
// CABI: create a real QList<>
|
||||
|
||||
gfs.imports["runtime"] = struct{}{}
|
||||
gfs.imports["unsafe"] = struct{}{}
|
||||
|
||||
preamble += "// For the C ABI, malloc a C array of raw pointers\n"
|
||||
preamble += nameprefix + "_CArray := (*[0xffff]" + listType.parameterTypeCgo() + ")(C.malloc(C.size_t(8 * len(" + p.ParameterName + "))))\n"
|
||||
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_CArray))\n"
|
||||
|
||||
preamble += "for i := range " + p.ParameterName + "{\n"
|
||||
|
||||
listType.ParameterName = p.ParameterName + "[i]"
|
||||
addPreamble, innerRvalue := gfs.emitParameterGo2CABIForwarding(listType)
|
||||
preamble += addPreamble
|
||||
preamble += nameprefix + "_CArray[i] = " + innerRvalue + "\n"
|
||||
preamble += "}\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(" + nameprefix + "_ma))\n"
|
||||
|
||||
rvalue = p.ParameterName + "_ma"
|
||||
|
||||
} else if p.Pointer && p.ParameterType == "char" {
|
||||
// Single char* argument
|
||||
gfs.imports["unsafe"] = struct{}{}
|
||||
preamble += nameprefix + "_Cstring := C.CString(" + p.ParameterName + ")\n"
|
||||
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_Cstring))\n"
|
||||
rvalue = nameprefix + "_Cstring"
|
||||
|
||||
} else if /*(p.Pointer || p.ByRef) &&*/ p.QtClassType() {
|
||||
// The C++ type is a pointer to Qt class
|
||||
// We want our functions to accept the Go wrapper type, and forward as cPointer()
|
||||
rvalue = p.ParameterName + ".cPointer()"
|
||||
|
||||
} else if p.IntType() || p.ParameterType == "bool" {
|
||||
if p.Pointer || p.ByRef {
|
||||
gfs.imports["unsafe"] = struct{}{}
|
||||
rvalue = "(" + p.parameterTypeCgo() + ")(unsafe.Pointer(" + p.ParameterName + "))" // n.b. This may not work if the integer type conversion was wrong
|
||||
} else {
|
||||
rvalue = "(" + p.parameterTypeCgo() + ")(" + p.ParameterName + ")"
|
||||
}
|
||||
|
||||
} else {
|
||||
// Default
|
||||
rvalue = p.ParameterName
|
||||
}
|
||||
|
||||
return preamble, rvalue
|
||||
}
|
||||
|
||||
func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue string) string {
|
||||
|
||||
shouldReturn := "return "
|
||||
@ -309,37 +306,16 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
||||
gfs.imports["unsafe"] = struct{}{}
|
||||
|
||||
shouldReturn = "var " + namePrefix + "_ma *C.struct_miqt_array = "
|
||||
if t.ParameterType == "QString" {
|
||||
// Combo
|
||||
|
||||
afterword += namePrefix + "_ret := make([]string, int(" + namePrefix + "_ma.len))\n"
|
||||
afterword += "_outCast := (*[0xffff]*C.struct_miqt_string)(unsafe.Pointer(" + namePrefix + "_ma.data)) // hey ya\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 += "}\n"
|
||||
afterword += "C.free(unsafe.Pointer(" + namePrefix + "_ma))\n"
|
||||
afterword += assignExpr + " " + namePrefix + "_ret\n"
|
||||
afterword += namePrefix + "_ret := make([]" + t.RenderTypeGo() + ", int(" + namePrefix + "_ma.len))\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"
|
||||
|
||||
} else {
|
||||
afterword += gfs.emitCabiToGo(namePrefix+"_ret[i] = ", t, namePrefix+"_outCast[i]")
|
||||
|
||||
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"
|
||||
}
|
||||
afterword += "}\n"
|
||||
afterword += "C.free(unsafe.Pointer(" + namePrefix + "_ma))\n"
|
||||
afterword += assignExpr + " " + namePrefix + "_ret\n"
|
||||
|
||||
} else if rt.QtClassType() {
|
||||
// Construct our Go type based on this inner CABI type
|
||||
@ -347,7 +323,7 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
||||
|
||||
if rt.Pointer || rt.ByRef {
|
||||
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 {
|
||||
// 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" {
|
||||
// Need to cast Cgo type to Go int type
|
||||
shouldReturn = "" + namePrefix + "_ret := "
|
||||
afterword += assignExpr + "(" + rt.RenderTypeGo() + ")(" + namePrefix + "_ret)\n"
|
||||
// Optimize assignment to avoid temporary
|
||||
return assignExpr + "(" + rt.RenderTypeGo() + ")(" + rvalue + ")\n"
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user