mirror of
https://github.com/mappu/miqt.git
synced 2024-12-22 08:58:37 +00:00
genbindings: wip
This commit is contained in:
parent
559aca01b2
commit
7319683a3f
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
# scratch files
|
||||
*.json
|
||||
gen_*
|
||||
|
||||
# binaries
|
||||
miqt
|
||||
|
@ -3,6 +3,8 @@ package main
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parseHeader(inner []interface{}) (*parsedHeader, error) {
|
||||
@ -42,7 +44,7 @@ func parseHeader(inner []interface{}) (*parsedHeader, error) {
|
||||
|
||||
fmt.Printf("-> %q name=%q\n", kind, nodename)
|
||||
if classInner, ok := node["inner"].([]interface{}); ok {
|
||||
obj, err := processType(classInner)
|
||||
obj, err := processType(classInner, nodename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -61,9 +63,11 @@ func parseHeader(inner []interface{}) (*parsedHeader, error) {
|
||||
return &ret, nil // done
|
||||
}
|
||||
|
||||
func processType(inner []interface{}) (nativeClass, error) {
|
||||
func processType(inner []interface{}, className string) (nativeClass, error) {
|
||||
var ret nativeClass
|
||||
ret.className = className
|
||||
|
||||
nextMethod:
|
||||
for _, node := range inner {
|
||||
node, ok := node.(map[string]interface{})
|
||||
if !ok {
|
||||
@ -76,8 +80,69 @@ func processType(inner []interface{}) (nativeClass, error) {
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case "CXXMethodDecl":
|
||||
// Method
|
||||
methodName, ok := node["name"].(string)
|
||||
if !ok {
|
||||
return nativeClass{}, errors.New("method has no name")
|
||||
}
|
||||
|
||||
var mm nativeMethod
|
||||
mm.methodName = methodName
|
||||
|
||||
if typobj, ok := node["type"].(map[string]interface{}); ok {
|
||||
if qualType, ok := typobj["qualType"].(string); ok {
|
||||
// The qualType is the whole type of the method, including its parameter types
|
||||
// If anything here is too complicated, skip the whole method
|
||||
if strings.Contains(qualType, `::`) {
|
||||
log.Printf("Skipping method %q with complex type %q", mm.methodName, qualType)
|
||||
continue nextMethod
|
||||
}
|
||||
|
||||
// We only want up to the first ( character
|
||||
mm.returnType, _, _ = strings.Cut(qualType, `(`)
|
||||
mm.returnType = strings.TrimSpace(mm.returnType)
|
||||
}
|
||||
}
|
||||
|
||||
if methodInner, ok := node["inner"].([]interface{}); ok {
|
||||
for _, methodObj := range methodInner {
|
||||
methodObj, ok := methodObj.(map[string]interface{})
|
||||
if !ok {
|
||||
return nativeClass{}, errors.New("inner[] element not an object")
|
||||
}
|
||||
|
||||
switch methodObj["kind"] {
|
||||
case "ParmVarDecl":
|
||||
// Parameter variable
|
||||
parmName, _ := methodObj["name"].(string) // n.b. may be unnamed
|
||||
if parmName == "" {
|
||||
parmName = fmt.Sprintf("param%d", len(mm.parameters)+1)
|
||||
}
|
||||
|
||||
var parmType string
|
||||
if typobj, ok := node["type"].(map[string]interface{}); ok {
|
||||
if qualType, ok := typobj["qualType"].(string); ok {
|
||||
parmType = qualType
|
||||
}
|
||||
}
|
||||
|
||||
mm.parameters = append(mm.parameters, nativeParameter{
|
||||
name: parmName,
|
||||
typ: parmType,
|
||||
})
|
||||
|
||||
default:
|
||||
fmt.Printf("==> %q\n", kind)
|
||||
// Something else inside a declaration??
|
||||
fmt.Printf("==> NOT IMPLEMENTED CXXMethodDecl->%q\n", kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret.methods = append(ret.methods, mm)
|
||||
|
||||
default:
|
||||
fmt.Printf("==> NOT IMPLEMENTED %q\n", kind)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,86 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func emitGo(src *parsedHeader) (string, error) {
|
||||
return "", errors.New("TODO")
|
||||
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 {
|
||||
tmp := make([]string, 0, len(params))
|
||||
for _, p := range params {
|
||||
tmp = append(tmp, p.typ+" "+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 + `
|
||||
|
||||
#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) {
|
||||
|
||||
ret := strings.Builder{}
|
||||
ret.WriteString("package miqt\n\n")
|
||||
|
||||
// CGO block
|
||||
|
||||
// Pure-Go block
|
||||
for _, c := range src.classes {
|
||||
_ = c
|
||||
}
|
||||
|
||||
return ret.String(), nil
|
||||
}
|
||||
|
@ -1,5 +1,10 @@
|
||||
package main
|
||||
|
||||
type nativeParameter struct {
|
||||
name string
|
||||
typ string
|
||||
}
|
||||
|
||||
type nativeProperty struct {
|
||||
propertyName string
|
||||
propertyType string
|
||||
@ -9,11 +14,12 @@ type nativeProperty struct {
|
||||
type nativeMethod struct {
|
||||
methodName string
|
||||
returnType string
|
||||
parameters []string
|
||||
parameters []nativeParameter
|
||||
}
|
||||
|
||||
type nativeClass struct {
|
||||
className string
|
||||
ctors []nativeMethod // only use the parameters
|
||||
extends []string
|
||||
methods []nativeMethod
|
||||
props []nativeProperty
|
||||
|
@ -3,8 +3,9 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -14,6 +15,7 @@ func main() {
|
||||
clang := flag.String("clang", "clang", "Custom path to clang")
|
||||
inputHeader := flag.String("inputHeader", `/usr/include/x86_64-linux-gnu/qt5/QtWidgets/qpushbutton.h`, "Input file")
|
||||
cflags := flag.String("cflags", `-DQT_WIDGETS_LIB -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtCore -DQT_GUI_LIB -I/usr/include/x86_64-linux-gnu/qt5/QtGui -DQT_CORE_LIB`, "Cflags to pass to clang (e.g. `pkg-config --cflags Qt5Widgets`)")
|
||||
outDir := flag.String("outdir", "..", "Output directory for generated gen_** files")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
@ -29,13 +31,40 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Emit Go code from the intermediate format
|
||||
// Emit 3 code files from the intermediate format
|
||||
outputName := filepath.Join(*outDir, "gen_"+strings.TrimSuffix(filepath.Base(*inputHeader), `.h`))
|
||||
|
||||
goSrc, err := emitGo(parsed)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(goSrc)
|
||||
err = ioutil.WriteFile(outputName+".go", []byte(goSrc), 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Printf("Processing %q completed", inputHeader)
|
||||
bindingCppSrc, err := emitBindingCpp(parsed)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(outputName+".cpp", []byte(bindingCppSrc), 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bindingHSrc, err := emitBindingHeader(parsed, filepath.Base(*inputHeader))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(outputName+".h", []byte(bindingHSrc), 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Done
|
||||
|
||||
log.Printf("Processing %q completed", *inputHeader)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user