mirror of
https://github.com/mappu/miqt.git
synced 2025-04-01 19:30:23 +00:00
genbindings: further work on output generation
This commit is contained in:
parent
0514866d23
commit
3a802d0f5a
@ -96,6 +96,9 @@ nextMethod:
|
|||||||
panic("unexpected access visibility '" + access + "'")
|
panic("unexpected access visibility '" + access + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "CXXConstructorDecl", "":
|
||||||
|
// panic("TODO")
|
||||||
|
|
||||||
case "CXXMethodDecl":
|
case "CXXMethodDecl":
|
||||||
if !visibility {
|
if !visibility {
|
||||||
continue // Skip private/protected
|
continue // Skip private/protected
|
||||||
@ -147,6 +150,12 @@ nextMethod:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO fixup parameters
|
||||||
|
// Reference -> pointer
|
||||||
|
// Remove const
|
||||||
|
// Remove extra () -- if there are more than expected, skip method with complex type
|
||||||
|
// If this parameter is optional, expand it into multiple function overloads
|
||||||
|
|
||||||
mm.parameters = append(mm.parameters, nativeParameter{
|
mm.parameters = append(mm.parameters, nativeParameter{
|
||||||
name: parmName,
|
name: parmName,
|
||||||
typ: parmType,
|
typ: parmType,
|
||||||
|
107
cmd/genbindings/emitcabi.go
Normal file
107
cmd/genbindings/emitcabi.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func emitParametersCpp(params []nativeParameter, selfType string) string {
|
||||||
|
tmp := make([]string, 0, len(params)+1)
|
||||||
|
|
||||||
|
if selfType != "" {
|
||||||
|
tmp = append(tmp, "self "+selfType)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range params {
|
||||||
|
tmp = append(tmp, p.name+" "+p.typ)
|
||||||
|
}
|
||||||
|
return strings.Join(tmp, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func emitParametersNames(params []nativeParameter, selfType string) string {
|
||||||
|
tmp := make([]string, 0, len(params)+1)
|
||||||
|
|
||||||
|
if selfType != "" {
|
||||||
|
tmp = append(tmp, "self")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range params {
|
||||||
|
tmp = append(tmp, p.name)
|
||||||
|
}
|
||||||
|
return strings.Join(tmp, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func emitBindingHeader(src *parsedHeader, filename string) (string, error) {
|
||||||
|
ret := strings.Builder{}
|
||||||
|
|
||||||
|
includeGuard := strings.ToUpper(strings.Replace(filename, `.`, `_`, -1)) + "_H"
|
||||||
|
|
||||||
|
ret.WriteString(`#ifndef ` + includeGuard + `
|
||||||
|
#define ` + includeGuard + `
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
`)
|
||||||
|
|
||||||
|
for _, c := range src.classes {
|
||||||
|
ret.WriteString(`typedef void* P` + c.className + ";\n\n")
|
||||||
|
|
||||||
|
for i, ctor := range c.ctors {
|
||||||
|
ret.WriteString(fmt.Sprintf("P%s %s_new%s(%s);\n", c.className, maybeSuffix(i), emitParametersCpp(ctor.parameters, "")))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range c.methods {
|
||||||
|
ret.WriteString(fmt.Sprintf("%s %s_%s(%s);\n", m.returnType, c.className, m.SafeMethodName(), emitParametersCpp(m.parameters, "P"+c.className)))
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.WriteString(`
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern C */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
`)
|
||||||
|
return ret.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func emitBindingCpp(src *parsedHeader, filename string) (string, error) {
|
||||||
|
ret := strings.Builder{}
|
||||||
|
|
||||||
|
ret.WriteString(`#include "gen_` + filename + `"
|
||||||
|
#include "` + filename + `"
|
||||||
|
|
||||||
|
`)
|
||||||
|
|
||||||
|
for _, c := range src.classes {
|
||||||
|
|
||||||
|
for i, ctor := range c.ctors {
|
||||||
|
ret.WriteString(fmt.Sprintf(
|
||||||
|
"P%s %s_new%s(%s) {\n\treturn new %s(%s);\n}\n\n", c.className, maybeSuffix(i), emitParametersCpp(ctor.parameters, ""),
|
||||||
|
c.className, emitParametersNames(ctor.parameters, ""),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range c.methods {
|
||||||
|
// Need to take an extra 'self' parameter
|
||||||
|
|
||||||
|
shouldReturn := "return "
|
||||||
|
if m.returnType == "void" {
|
||||||
|
shouldReturn = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.WriteString(fmt.Sprintf("%s %s_%s(%s) {\n\t%sstatic_cast<%s*>(self)->%s(%s);\n}\n\n", m.returnType, c.className, m.SafeMethodName(), emitParametersCpp(m.parameters, "P"+c.className),
|
||||||
|
shouldReturn, c.className, m.methodName, emitParametersNames(m.parameters, c.className),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.String(), nil
|
||||||
|
}
|
@ -1,18 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"go/format"
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func emitParametersCpp(params []nativeParameter) string {
|
|
||||||
tmp := make([]string, 0, len(params))
|
|
||||||
for _, p := range params {
|
|
||||||
tmp = append(tmp, p.name+" "+p.typ)
|
|
||||||
}
|
|
||||||
return strings.Join(tmp, ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func emitParametersGo(params []nativeParameter) string {
|
func emitParametersGo(params []nativeParameter) string {
|
||||||
tmp := make([]string, 0, len(params))
|
tmp := make([]string, 0, len(params))
|
||||||
for _, p := range params {
|
for _, p := range params {
|
||||||
@ -21,66 +14,75 @@ func emitParametersGo(params []nativeParameter) string {
|
|||||||
return strings.Join(tmp, ", ")
|
return strings.Join(tmp, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitBindingHeader(src *parsedHeader, filename string) (string, error) {
|
|
||||||
ret := strings.Builder{}
|
|
||||||
|
|
||||||
includeGuard := strings.ToUpper(strings.Replace(filename, `.`, `_`, -1)) + "_H"
|
|
||||||
|
|
||||||
ret.WriteString(`#ifndef ` + includeGuard + `
|
|
||||||
#define ` + includeGuard + `
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
`)
|
|
||||||
|
|
||||||
for _, c := range src.classes {
|
|
||||||
ret.WriteString(`typedef void* P` + c.className + ";\n\n")
|
|
||||||
|
|
||||||
for i, ctor := range c.ctors {
|
|
||||||
suffix := ""
|
|
||||||
if i > 0 {
|
|
||||||
suffix = fmt.Sprintf("%d", i+1)
|
|
||||||
}
|
|
||||||
// TODO fixup parameters
|
|
||||||
ret.WriteString(fmt.Sprintf("P%s %s_new%s(%s);\n", c.className, suffix, emitParametersCpp(ctor.parameters)))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range c.methods {
|
|
||||||
ret.WriteString(fmt.Sprintf("%s %s_%s(%s);\n", m.returnType, c.className, m.methodName, emitParametersCpp(m.parameters)))
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.WriteString("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.WriteString(`
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern C */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
`)
|
|
||||||
return ret.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func emitBindingCpp(src *parsedHeader) (string, error) {
|
|
||||||
ret := strings.Builder{}
|
|
||||||
return ret.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func emitGo(src *parsedHeader) (string, error) {
|
func emitGo(src *parsedHeader) (string, error) {
|
||||||
|
|
||||||
ret := strings.Builder{}
|
ret := strings.Builder{}
|
||||||
ret.WriteString("package miqt\n\n")
|
ret.WriteString(`package miqt
|
||||||
|
|
||||||
// CGO block
|
/*
|
||||||
|
|
||||||
|
#cgo CFLAGS: -fPIC
|
||||||
|
#cgo pkg-config: Qt5Widgets
|
||||||
|
#include "binding.h"
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
`)
|
||||||
|
|
||||||
// Pure-Go block
|
|
||||||
for _, c := range src.classes {
|
for _, c := range src.classes {
|
||||||
_ = c
|
|
||||||
|
ret.WriteString(`
|
||||||
|
type ` + c.className + ` struct {
|
||||||
|
h C.P` + c.className + `
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *` + c.className + `) cPointer() C.P` + c.className + ` {
|
||||||
|
if this == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return this.h
|
||||||
|
}
|
||||||
|
|
||||||
|
`)
|
||||||
|
|
||||||
|
for i, ctor := range c.ctors {
|
||||||
|
ret.WriteString(`
|
||||||
|
// New` + c.className + maybeSuffix(i) + ` constructs a new ` + c.className + ` object.
|
||||||
|
func New` + c.className + maybeSuffix(i) + `(` + emitParametersGo(ctor.parameters) + `) {
|
||||||
|
ret := C.` + c.className + `_new` + maybeSuffix(i) + `(` + emitParametersNames(ctor.parameters, "") + `)
|
||||||
|
return &` + c.className + `{h: ret}
|
||||||
|
}
|
||||||
|
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range c.methods {
|
||||||
|
// TODO for any known pointer type, call its cPointer() method instead of passing it directly
|
||||||
|
|
||||||
|
shouldReturn := "return "
|
||||||
|
returnTypeDecl := m.returnType
|
||||||
|
if returnTypeDecl == "void" {
|
||||||
|
shouldReturn = ""
|
||||||
|
returnTypeDecl = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.WriteString(`
|
||||||
|
func (this *` + c.className + `) ` + m.methodName + `(` + emitParametersGo(m.parameters) + `) ` + returnTypeDecl + ` {
|
||||||
|
` + shouldReturn + ` C.` + c.className + `_` + m.SafeMethodName() + `(` + emitParametersNames(m.parameters, c.className) + `)
|
||||||
|
}
|
||||||
|
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret.String(), nil
|
// Run gofmt over the result
|
||||||
|
formattedSrc, err := format.Source([]byte(ret.String()))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("gofmt failure: %v", err)
|
||||||
|
formattedSrc = []byte(ret.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(formattedSrc), nil
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type nativeParameter struct {
|
type nativeParameter struct {
|
||||||
name string
|
name string
|
||||||
typ string
|
typ string
|
||||||
@ -17,6 +21,40 @@ type nativeMethod struct {
|
|||||||
parameters []nativeParameter
|
parameters []nativeParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nm nativeMethod) SafeMethodName() string {
|
||||||
|
// Operator-overload methods have names not representable in binding
|
||||||
|
// languages. Replace more specific cases first
|
||||||
|
replacer := strings.NewReplacer(
|
||||||
|
|
||||||
|
`==`, `Equal`,
|
||||||
|
`>=`, `GreaterOrEqual`,
|
||||||
|
`<=`, `LesserOrEqual`,
|
||||||
|
`=`, `Assign`,
|
||||||
|
`>`, `Greater`,
|
||||||
|
`<`, `Lesser`,
|
||||||
|
|
||||||
|
`+`, `Plus`,
|
||||||
|
`-`, `Minus`,
|
||||||
|
`*`, `Multiply`,
|
||||||
|
`/`, `Divide`,
|
||||||
|
`%`, `Modulo`,
|
||||||
|
|
||||||
|
`&&`, `LogicalAnd`,
|
||||||
|
`||`, `LogicalOr`,
|
||||||
|
`!`, `Not`,
|
||||||
|
`&`, `BitwiseAnd`,
|
||||||
|
`|`, `BitwiseOr`,
|
||||||
|
`~`, `BitwiseXor`,
|
||||||
|
`^`, `BitwiseNot`,
|
||||||
|
|
||||||
|
`->`, `PointerDereference`,
|
||||||
|
`[]`, `Subscript`,
|
||||||
|
`()`, `Call`,
|
||||||
|
)
|
||||||
|
|
||||||
|
return replacer.Replace(nm.methodName)
|
||||||
|
}
|
||||||
|
|
||||||
type nativeClass struct {
|
type nativeClass struct {
|
||||||
className string
|
className string
|
||||||
ctors []nativeMethod // only use the parameters
|
ctors []nativeMethod // only use the parameters
|
||||||
|
@ -67,7 +67,7 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingCppSrc, err := emitBindingCpp(parsed)
|
bindingCppSrc, err := emitBindingCpp(parsed, filepath.Base(*inputHeader))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
13
cmd/genbindings/util.go
Normal file
13
cmd/genbindings/util.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func maybeSuffix(counter int) string {
|
||||||
|
if counter == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%d", counter+1)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user