// 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, "") 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") } }