mirror of
https://github.com/mappu/miqt.git
synced 2024-12-23 01:18:37 +00:00
180 lines
4.2 KiB
Go
180 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
)
|
|
|
|
func parseHeader(inner []interface{}) (*parsedHeader, error) {
|
|
|
|
var ret parsedHeader
|
|
|
|
fmt.Printf("package miqt\n\n")
|
|
|
|
for _, node := range inner {
|
|
|
|
node, ok := node.(map[string]interface{})
|
|
if !ok {
|
|
return nil, errors.New("inner[] element not an object")
|
|
}
|
|
|
|
kind, ok := node["kind"].(string)
|
|
if !ok {
|
|
return nil, errors.New("node has no kind")
|
|
}
|
|
|
|
switch kind {
|
|
|
|
case "CXXRecordDecl":
|
|
// Must have a name
|
|
nodename, ok := node["name"].(string)
|
|
if !ok {
|
|
return nil, errors.New("node has no name")
|
|
}
|
|
|
|
fmt.Printf("-> %q name=%q\n", kind, nodename)
|
|
if classInner, ok := node["inner"].([]interface{}); ok {
|
|
|
|
// Check if this was 'struct' (default visible) or 'class' (default invisible)
|
|
visible := true
|
|
if tagUsed, ok := node["tagUsed"].(string); ok && tagUsed == "class" {
|
|
visible = false
|
|
}
|
|
|
|
// Process the inner class definition
|
|
obj, err := processType(classInner, nodename, visible)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ret.classes = append(ret.classes, obj)
|
|
}
|
|
|
|
case "StaticAssertDecl":
|
|
// ignore
|
|
|
|
default:
|
|
return nil, fmt.Errorf("missing handling for clang ast node type %q", kind)
|
|
}
|
|
}
|
|
|
|
return &ret, nil // done
|
|
}
|
|
|
|
func processType(inner []interface{}, className string, visibility bool) (nativeClass, error) {
|
|
var ret nativeClass
|
|
ret.className = className
|
|
|
|
nextMethod:
|
|
for _, node := range inner {
|
|
node, ok := node.(map[string]interface{})
|
|
if !ok {
|
|
return nativeClass{}, errors.New("inner[] element not an object")
|
|
}
|
|
|
|
kind, ok := node["kind"]
|
|
if !ok {
|
|
panic("inner element has no kind")
|
|
}
|
|
|
|
switch kind {
|
|
case "AccessSpecDecl":
|
|
// Swap between visible/invisible
|
|
access, ok := node["access"].(string)
|
|
if !ok {
|
|
panic("AccessSpecDecl missing `access` field")
|
|
}
|
|
|
|
switch access {
|
|
case "public":
|
|
visibility = true
|
|
case "private", "protected":
|
|
visibility = false
|
|
default:
|
|
panic("unexpected access visibility '" + access + "'")
|
|
}
|
|
|
|
case "CXXConstructorDecl", "":
|
|
// panic("TODO")
|
|
|
|
case "CXXMethodDecl":
|
|
if !visibility {
|
|
continue // Skip private/protected
|
|
}
|
|
|
|
// 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
|
|
}
|
|
}
|
|
|
|
// 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{
|
|
name: parmName,
|
|
typ: parmType,
|
|
})
|
|
|
|
default:
|
|
// 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)
|
|
}
|
|
}
|
|
|
|
return ret, nil // done
|
|
}
|