Skip to content

Commit

Permalink
Move go name mangling to emitgo
Browse files Browse the repository at this point in the history
This change helps keep rules for each language separate by moving `go`
rules to `emitgo` while the C bindings stay closer to the original Qt
naming (that already is mostly C-safe).

Although it doesn't practically matter for go, it makes it slightly
easier to reuse the generated code in other languages which have
different keywords and naming conventions.

The cabi generator also gains a few helpers to help keep names
consistent across files which hopefully aids reading the generator code
- it did for me at least;)

The rule that converts under_score to CamelCase is left for another day
since moving it turns out to be more invasive due to name collision
handling - when underscores are kept, there are fewer name conflicts
which ends up causing name changes in  the public go api when done
naively.
  • Loading branch information
arnetheduck committed Jan 11, 2025
1 parent 3d864cd commit ffb2efc
Show file tree
Hide file tree
Showing 3,263 changed files with 332,434 additions and 332,377 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
5 changes: 0 additions & 5 deletions cmd/genbindings/clang2il.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,11 +702,6 @@ func parseMethod(node map[string]interface{}, mm *CppMethod) error {
}
}

// Block reserved Go words, replace with generic parameters
if goReservedWord(parmName) {
parmName += "Val"
}

// Update the name for the existing nth parameter
mm.Parameters[paramCounter].ParameterName = parmName

Expand Down
134 changes: 91 additions & 43 deletions cmd/genbindings/emitcabi.go

Large diffs are not rendered by default.

115 changes: 66 additions & 49 deletions cmd/genbindings/emitgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@ func goReservedWord(s string) bool {
}
}

func (nm CppMethod) goMethodName() string {
// Also make the first letter uppercase so it becomes public in Go
tmp := nm.SafeMethodName()
tmp = titleCase(tmp)
return tmp
}

func (p CppParameter) goParameterName() string {
// Also make the first letter uppercase so it becomes public in Go
parmName := p.ParameterName
if goReservedWord(parmName) {
parmName += "Val"
}

return parmName
}

func (p CppParameter) RenderTypeGo(gfs *goFileState) string {
if p.Pointer && p.ParameterType == "char" {
return "string"
Expand Down Expand Up @@ -247,7 +264,7 @@ func (gfs *goFileState) emitParametersGo(params []CppParameter) string {

} else {
// Ordinary parameter
tmp = append(tmp, p.ParameterName+" "+p.RenderTypeGo(gfs))
tmp = append(tmp, p.goParameterName()+" "+p.RenderTypeGo(gfs))

}
}
Expand Down Expand Up @@ -312,16 +329,16 @@ func (gfs *goFileState) emitParametersGo2CABIForwarding(m CppMethod) (preamble s

func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble string, rvalue string) {

nameprefix := makeNamePrefix(p.ParameterName)
nameprefix := makeNamePrefix(p.goParameterName())

if p.ParameterType == "QString" {
// Go: convert string -> miqt_string*
// CABI: convert miqt_string* -> real QString

gfs.imports["unsafe"] = struct{}{}
preamble += nameprefix + "_ms := C.struct_miqt_string{}\n"
preamble += nameprefix + "_ms.data = C.CString(" + p.ParameterName + ")\n"
preamble += nameprefix + "_ms.len = C.size_t(len(" + p.ParameterName + "))\n"
preamble += nameprefix + "_ms.data = C.CString(" + p.goParameterName() + ")\n"
preamble += nameprefix + "_ms.len = C.size_t(len(" + p.goParameterName() + "))\n"
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_ms.data))\n"

rvalue = nameprefix + "_ms"
Expand All @@ -333,8 +350,8 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble

gfs.imports["unsafe"] = struct{}{}
preamble += nameprefix + "_alias := C.struct_miqt_string{}\n"
preamble += nameprefix + "_alias.data = (*C.char)(unsafe.Pointer(&" + p.ParameterName + "[0]))\n"
preamble += nameprefix + "_alias.len = C.size_t(len(" + p.ParameterName + "))\n"
preamble += nameprefix + "_alias.data = (*C.char)(unsafe.Pointer(&" + p.goParameterName() + "[0]))\n"
preamble += nameprefix + "_alias.len = C.size_t(len(" + p.goParameterName() + "))\n"

rvalue = nameprefix + "_alias"

Expand All @@ -347,18 +364,18 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble

mallocSize := listType.mallocSizeCgoExpression()

preamble += nameprefix + "_CArray := (*[0xffff]" + listType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + mallocSize + " * len(" + p.ParameterName + "))))\n"
preamble += nameprefix + "_CArray := (*[0xffff]" + listType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + mallocSize + " * len(" + p.goParameterName() + "))))\n"
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_CArray))\n"

preamble += "for i := range " + p.ParameterName + "{\n"
preamble += "for i := range " + p.goParameterName() + "{\n"

listType.ParameterName = p.ParameterName + "[i]"
listType.ParameterName = p.goParameterName() + "[i]"
addPreamble, innerRvalue := gfs.emitParameterGo2CABIForwarding(listType)
preamble += addPreamble
preamble += nameprefix + "_CArray[i] = " + innerRvalue + "\n"
preamble += "}\n"

preamble += nameprefix + "_ma := C.struct_miqt_array{len: C.size_t(len(" + p.ParameterName + ")), data: unsafe.Pointer(" + nameprefix + "_CArray)}\n"
preamble += nameprefix + "_ma := C.struct_miqt_array{len: C.size_t(len(" + p.goParameterName() + ")), data: unsafe.Pointer(" + nameprefix + "_CArray)}\n"

rvalue = nameprefix + "_ma"

Expand All @@ -370,15 +387,15 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble

gfs.imports["unsafe"] = struct{}{}

preamble += nameprefix + "_Keys_CArray := (*[0xffff]" + kType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + kType.mallocSizeCgoExpression() + " * len(" + p.ParameterName + "))))\n"
preamble += nameprefix + "_Keys_CArray := (*[0xffff]" + kType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + kType.mallocSizeCgoExpression() + " * len(" + p.goParameterName() + "))))\n"
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_Keys_CArray))\n"

preamble += nameprefix + "_Values_CArray := (*[0xffff]" + vType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + vType.mallocSizeCgoExpression() + " * len(" + p.ParameterName + "))))\n"
preamble += nameprefix + "_Values_CArray := (*[0xffff]" + vType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + vType.mallocSizeCgoExpression() + " * len(" + p.goParameterName() + "))))\n"
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_Values_CArray))\n"

preamble += nameprefix + "_ctr := 0\n"

preamble += "for " + nameprefix + "_k, " + nameprefix + "_v := range " + p.ParameterName + "{\n"
preamble += "for " + nameprefix + "_k, " + nameprefix + "_v := range " + p.goParameterName() + "{\n"

kType.ParameterName = nameprefix + "_k"
addPreamble, innerRvalue := gfs.emitParameterGo2CABIForwarding(kType)
Expand All @@ -394,7 +411,7 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble

preamble += "}\n"

preamble += nameprefix + "_mm := C.struct_miqt_map{\nlen: C.size_t(len(" + p.ParameterName + ")),\nkeys: unsafe.Pointer(" + nameprefix + "_Keys_CArray),\nvalues: unsafe.Pointer(" + nameprefix + "_Values_CArray),\n}\n"
preamble += nameprefix + "_mm := C.struct_miqt_map{\nlen: C.size_t(len(" + p.goParameterName() + ")),\nkeys: unsafe.Pointer(" + nameprefix + "_Keys_CArray),\nvalues: unsafe.Pointer(" + nameprefix + "_Values_CArray),\n}\n"

rvalue = nameprefix + "_mm"

Expand All @@ -409,12 +426,12 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble
preamble += nameprefix + "_Second_CArray := (*[0xffff]" + vType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + vType.mallocSizeCgoExpression() + ")))\n"
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_Second_CArray))\n"

kType.ParameterName = p.ParameterName + ".First"
kType.ParameterName = p.goParameterName() + ".First"
addPreamble, innerRvalue := gfs.emitParameterGo2CABIForwarding(kType)
preamble += addPreamble
preamble += nameprefix + "_First_CArray[0] = " + innerRvalue + "\n"

vType.ParameterName = p.ParameterName + ".Second"
vType.ParameterName = p.goParameterName() + ".Second"
addPreamble, innerRvalue = gfs.emitParameterGo2CABIForwarding(vType)
preamble += addPreamble
preamble += nameprefix + "_Second_CArray[0] = " + innerRvalue + "\n"
Expand All @@ -426,7 +443,7 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble
} else if p.Pointer && p.ParameterType == "char" {
// Single char* argument
gfs.imports["unsafe"] = struct{}{}
preamble += nameprefix + "_Cstring := C.CString(" + p.ParameterName + ")\n"
preamble += nameprefix + "_Cstring := C.CString(" + p.goParameterName() + ")\n"
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_Cstring))\n"
rvalue = nameprefix + "_Cstring"

Expand All @@ -438,23 +455,23 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble

if classInfo, ok := KnownClassnames[p.ParameterType]; ok && gfs.currentPackageName != classInfo.PackageName {
// Cross-package
rvalue = "(" + p.parameterTypeCgo() + ")(" + p.ParameterName + ".UnsafePointer())"
rvalue = "(" + p.parameterTypeCgo() + ")(" + p.goParameterName() + ".UnsafePointer())"
} else {
// Same package
rvalue = p.ParameterName + ".cPointer()"
rvalue = p.goParameterName() + ".cPointer()"
}

} else if p.IntType() || p.IsFlagType() || p.IsKnownEnum() || 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
rvalue = "(" + p.parameterTypeCgo() + ")(unsafe.Pointer(" + p.goParameterName() + "))" // n.b. This may not work if the integer type conversion was wrong
} else {
rvalue = "(" + p.parameterTypeCgo() + ")(" + p.ParameterName + ")"
rvalue = "(" + p.parameterTypeCgo() + ")(" + p.goParameterName() + ")"
}

} else {
// Default
rvalue = p.ParameterName
rvalue = p.goParameterName()
}

return preamble, rvalue
Expand All @@ -464,7 +481,7 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue

shouldReturn := assignExpr // "return "
afterword := ""
namePrefix := makeNamePrefix(rt.ParameterName)
namePrefix := makeNamePrefix(rt.goParameterName())

if rt.Void() {
shouldReturn = ""
Expand Down Expand Up @@ -640,7 +657,7 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
return assignExpr + "(" + rt.RenderTypeGo(gfs) + ")(" + rvalue + ")\n"

} else {
panic(fmt.Sprintf("emitgo::emitCabiToGo missing type handler for parameter %+v", rt))
return "int /* TODO */" //panic(fmt.Sprintf("emitgo::emitCabiToGo missing type handler for parameter %+v", rt))
}

}
Expand Down Expand Up @@ -846,19 +863,19 @@ import "C"
}

// Populate outptr pointers
ret.WriteString("C." + cabiClassName(c.ClassName) + "_virtbase(h" + xbaseParams + ")\n")
ret.WriteString("C." + cabiVirtBaseName(c) + "(h" + xbaseParams + ")\n")

}

ret.WriteString(`
return &` + goClassName + `{` + localInit + `}
}
// UnsafeNew` + goClassName + ` constructs the type using only unsafe pointers.
func UnsafeNew` + goClassName + `(h unsafe.Pointer) *` + goClassName + ` {
return new` + goClassName + `( (*C.` + goClassName + `)(h) )
}
`)

//
Expand All @@ -885,12 +902,12 @@ import "C"

// Call Cgo constructor

ret.WriteString(`
ret := new` + goClassName + `(C.` + goClassName + `_new` + maybeSuffix(i) + `(` + forwarding + `))
ret.WriteString(`
ret := new` + goClassName + `(C.` + cabiNewName(c, i) + `(` + forwarding + `))
ret.isSubclass = true
return ret
}
`)

}
Expand All @@ -905,13 +922,13 @@ import "C"

returnTypeDecl := m.ReturnType.renderReturnTypeGo(&gfs)

rvalue := `C.` + goClassName + `_` + m.SafeMethodName() + `(` + forwarding + `)`
rvalue := `C.` + cabiMethodName(c, m) + `(` + forwarding + `)`

returnFunc := gfs.emitCabiToGo("return ", m.ReturnType, rvalue)

receiverAndMethod := `(this *` + goClassName + `) ` + m.SafeMethodName()
receiverAndMethod := `(this *` + goClassName + `) ` + m.goMethodName()
if m.IsStatic {
receiverAndMethod = goClassName + `_` + m.SafeMethodName()
receiverAndMethod = goClassName + `_` + m.goMethodName()
}

ret.WriteString(`
Expand Down Expand Up @@ -942,16 +959,16 @@ import "C"
conversion = "// Convert all CABI parameters to Go parameters\n"
}
for i, pp := range m.Parameters {
cgoNamedParams = append(cgoNamedParams, pp.ParameterName+" "+pp.parameterTypeCgo())
cgoNamedParams = append(cgoNamedParams, pp.goParameterName()+" "+pp.parameterTypeCgo())

paramNames = append(paramNames, fmt.Sprintf("slotval%d", i+1))
conversion += gfs.emitCabiToGo(fmt.Sprintf("slotval%d := ", i+1), pp, pp.ParameterName) + "\n"
conversion += gfs.emitCabiToGo(fmt.Sprintf("slotval%d := ", i+1), pp, pp.goParameterName()) + "\n"
}

goCbType := `func(` + gfs.emitParametersGo(m.Parameters) + `)`
callbackName := cabiCallbackName(c, m)
ret.WriteString(`func (this *` + goClassName + `) On` + m.SafeMethodName() + `(slot ` + goCbType + `) {
C.` + goClassName + `_connect_` + m.SafeMethodName() + `(this.h, C.intptr_t(cgo.NewHandle(slot)) )
ret.WriteString(`func (this *` + goClassName + `) On` + m.goMethodName() + `(slot ` + goCbType + `) {
C.` + cabiConnectName(c, m) + `(this.h, C.intptr_t(cgo.NewHandle(slot)) )
}
//export ` + callbackName + `
Expand All @@ -960,9 +977,9 @@ import "C"
if !ok {
panic("miqt: callback of non-callback type (heap corruption?)")
}
` + conversion + `
gofunc(` + strings.Join(paramNames, `, `) + ` )
}
Expand All @@ -986,9 +1003,9 @@ import "C"
returnTypeDecl := m.ReturnType.renderReturnTypeGo(&gfs)

ret.WriteString(`
func (this *` + goClassName + `) callVirtualBase_` + m.SafeMethodName() + `(` + gfs.emitParametersGo(m.Parameters) + `) ` + returnTypeDecl + ` {
func (this *` + goClassName + `) callVirtualBase_` + m.goMethodName() + `(` + gfs.emitParametersGo(m.Parameters) + `) ` + returnTypeDecl + ` {
` + preamble + `
` + gfs.emitCabiToGo("return ", m.ReturnType, `C.`+goClassName+`_virtualbase_`+m.SafeMethodName()+`(`+forwarding+`)`) + `
` + gfs.emitCabiToGo("return ", m.ReturnType, `C.`+cabiVirtualBaseName(c, m)+`(`+forwarding+`)`) + `
}
`)

Expand All @@ -1003,18 +1020,18 @@ import "C"
var cgoNamedParams []string
var paramNames []string
if !m.IsPureVirtual {
paramNames = append(paramNames, "(&"+goClassName+"{h: self}).callVirtualBase_"+m.SafeMethodName())
paramNames = append(paramNames, "(&"+goClassName+"{h: self}).callVirtualBase_"+m.goMethodName())
}
conversion := ""

if len(m.Parameters) > 0 {
conversion = "// Convert all CABI parameters to Go parameters\n"
}
for i, pp := range m.Parameters {
cgoNamedParams = append(cgoNamedParams, pp.ParameterName+" "+pp.parameterTypeCgo())
cgoNamedParams = append(cgoNamedParams, pp.goParameterName()+" "+pp.parameterTypeCgo())

paramNames = append(paramNames, fmt.Sprintf("slotval%d", i+1))
conversion += gfs.emitCabiToGo(fmt.Sprintf("slotval%d := ", i+1), pp, pp.ParameterName) + "\n"
conversion += gfs.emitCabiToGo(fmt.Sprintf("slotval%d := ", i+1), pp, pp.goParameterName()) + "\n"
}

cabiReturnType := m.ReturnType.parameterTypeCgo()
Expand All @@ -1034,11 +1051,11 @@ import "C"
goCbType += gfs.emitParametersGo(m.Parameters)
goCbType += `) ` + m.ReturnType.renderReturnTypeGo(&gfs)
callbackName := cabiCallbackName(c, m)
ret.WriteString(`func (this *` + goClassName + `) On` + m.SafeMethodName() + `(slot ` + goCbType + `) {
ret.WriteString(`func (this *` + goClassName + `) On` + m.goMethodName() + `(slot ` + goCbType + `) {
if ! this.isSubclass {
panic("miqt: can only override virtual methods for directly constructed types")
}
C.` + goClassName + `_override_virtual_` + m.SafeMethodName() + `(unsafe.Pointer(this.h), C.intptr_t(cgo.NewHandle(slot)) )
C.` + cabiOverrideVirtualName(c, m) + `(unsafe.Pointer(this.h), C.intptr_t(cgo.NewHandle(slot)) )
}
//export ` + callbackName + `
Expand All @@ -1047,7 +1064,7 @@ import "C"
if !ok {
panic("miqt: callback of non-callback type (heap corruption?)")
}
`)
ret.WriteString(conversion + "\n")
if cabiReturnType == "" {
Expand All @@ -1074,9 +1091,9 @@ import "C"
ret.WriteString(`
// Delete this object from C++ memory.
func (this *` + goClassName + `) Delete() {
C.` + goClassName + `_Delete(this.h, C.bool(this.isSubclass))
C.` + cabiDeleteName(c) + `(this.h, C.bool(this.isSubclass))
}
// GoGC adds a Go Finalizer to this pointer, so that it will be deleted
// from C++ memory once it is unreachable from Go memory.
func (this *` + goClassName + `) GoGC() {
Expand Down
3 changes: 0 additions & 3 deletions cmd/genbindings/intermediate.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,6 @@ func (nm CppMethod) SafeMethodName() string {
)
tmp = replacer.Replace(tmp)

// Also make the first letter uppercase so it becomes public in Go
tmp = titleCase(tmp)

// Replace spaces (e.g. `operator long long` with CamelCase
tmp = regexp.MustCompile(` ([a-zA-Z])`).ReplaceAllStringFunc(tmp, func(match string) string { return strings.ToUpper(match[1:]) })

Expand Down
Loading

0 comments on commit ffb2efc

Please sign in to comment.