libui/redo/tools/idl2h.go

200 lines
4.3 KiB
Go

// 15 april 2015
package main
import (
"fmt"
"os"
"flag"
"github.com/andlabs/pgidl"
)
var extern = flag.String("extern", "extern", "name for extern")
var guard = flag.String("guard", "", "#define name for include guards")
var pkgtypes = map[string]string{}
func typedecl(t *pgidl.Type, name string) string {
if t == nil {
return "void " + name
}
if t.IsFuncPtr {
return cfuncptrdecl(t.FuncType, name)
}
s := t.Name + " "
if pkgtypes[t.Name] != "" {
s = pkgtypes[t.Name] + " "
}
for i := uint(0); i < t.NumPtrs; i++ {
s += "*"
}
return s + name
}
func arglist(a []*pgidl.Arg) string {
if len(a) == 0 {
return "void"
}
s := typedecl(a[0].Type, a[0].Name)
for i := 1; i < len(a); i++ {
s += ", " + typedecl(a[i].Type, a[i].Name)
}
return s
}
func cfuncdecl(f *pgidl.Func, name string) string {
fd := name + "(" + arglist(f.Args) + ")"
return *extern + " " + typedecl(f.Ret, fd) + ";"
}
func cfuncptrdecl(f *pgidl.Func, name string) string {
name = "(*" + name + ")"
fd := name + "(" + arglist(f.Args) + ")"
return typedecl(f.Ret, fd)
}
func cmethodmacro(f *pgidl.Func, typename string) string {
s := "#define " + typename + f.Name + "("
first := true
for _, a := range f.Args {
if !first {
s += ", "
}
s += a.Name
first = false
}
s += ") ("
s += "(*((this)->" + f.Name + "))"
s += "("
first = true
for _, a := range f.Args {
if !first {
s += ", "
}
s += "(" + a.Name + ")"
first = false
}
s += ")"
s += ")"
return s
}
func genpkgfunc(f *pgidl.Func, prefix string) {
fmt.Printf("%s\n", cfuncdecl(f, prefix + f.Name))
}
func genstruct(s *pgidl.Struct, prefix string) {
fmt.Printf("struct %s%s {\n", prefix, s.Name)
for _, f := range s.Fields {
fmt.Printf("\t%s;\n", typedecl(f.Type, f.Name))
}
fmt.Printf("};\n")
}
func geniface(i *pgidl.Interface, prefix string) {
fmt.Printf("struct %s%s {\n", prefix, i.Name)
if i.From != "" {
fmt.Printf("\t%s%s base;\n", prefix, i.From)
} else {
fmt.Printf("\tuintmax_t Type;\n")
}
for _, f := range i.Fields {
fmt.Printf("\t%s;\n", typedecl(f.Type, f.Name))
}
for _, m := range i.Methods {
// hack our this pointer in
m.Args = append([]*pgidl.Arg{
&pgidl.Arg{
Name: "this",
Type: &pgidl.Type{
Name: prefix + i.Name,
NumPtrs: 1,
},
},
}, m.Args...)
fmt.Printf("\t%s;\n", cfuncptrdecl(m, m.Name))
fmt.Printf("%s\n", cmethodmacro(m, prefix + i.Name))
}
fmt.Printf("};\n")
fmt.Printf("%s uintmax_t %sType%s(void);\n",
*extern,
prefix, i.Name)
fmt.Printf("#define %s%s(this) ((%s%s *) %sIsA((this), %sType%s(), 1))\n",
prefix, i.Name,
prefix, i.Name,
prefix,
prefix, i.Name)
fmt.Printf("#define %sIs%s(this) (%sIsA((this), %sType%s(), 0) != NULL)\n",
prefix, i.Name,
prefix,
prefix, i.Name)
}
func genenum(e *pgidl.Enum, prefix string) {
fmt.Printf("enum %s%s {\n", prefix, e.Name)
for _, m := range e.Members {
fmt.Printf("\t%s%s%s,\n", prefix, e.Name, m)
}
fmt.Printf("};\n")
}
func genpkg(p *pgidl.Package) {
for _, s := range p.Structs {
fmt.Printf("typedef struct %s%s %s%s;\n",
p.Name, s.Name,
p.Name, s.Name)
pkgtypes[s.Name] = p.Name + s.Name
}
for _, i := range p.Interfaces {
fmt.Printf("typedef struct %s%s %s%s;\n",
p.Name, i.Name,
p.Name, i.Name)
pkgtypes[i.Name] = p.Name + i.Name
}
for _, e := range p.Enums {
fmt.Printf("typedef enum %s%s %s%s;\n",
p.Name, e.Name,
p.Name, e.Name)
pkgtypes[e.Name] = p.Name + e.Name
}
// apparently we have to fully define C enumerations before we can use them...
for _, e := range p.Enums {
genenum(e, p.Name)
}
for _, o := range p.Order {
switch o.Which {
case pgidl.Funcs:
genpkgfunc(p.Funcs[o.Index], p.Name)
case pgidl.Structs:
genstruct(p.Structs[o.Index], p.Name)
case pgidl.Interfaces:
geniface(p.Interfaces[o.Index], p.Name)
case pgidl.Raws:
fmt.Printf("%s\n", p.Raws[o.Index])
case pgidl.Enums:
// we did them already; see above
}
}
}
func main() {
flag.Parse()
idl, errs := pgidl.Parse(os.Stdin, "<stdin>")
if len(errs) != 0 {
for _, e := range errs {
fmt.Fprintf(os.Stderr, "%s\n", e)
}
os.Exit(1)
}
fmt.Printf("// generated by idl2h; do not edit\n")
if *guard != "" {
fmt.Printf("#ifndef %s\n", *guard)
fmt.Printf("#define %s\n", *guard)
}
for _, p := range idl {
genpkg(p)
}
if *guard != "" {
fmt.Printf("#endif\n")
}
}