diff --git a/GNUbase.mk b/GNUbase.mk index ddb5a1cc..cd47641e 100644 --- a/GNUbase.mk +++ b/GNUbase.mk @@ -50,7 +50,7 @@ $(OBJDIR)/%.o: %.m $(xHFILES) | $$(dir $$@).phony .PRECIOUS: %/.phony ui.h: ui.idl - @idl2h -extern _UI_EXTERN -guard __UI_UI_H__ < ui.idl > ui.h + @go run tools/idl2h.go -extern _UI_EXTERN -guard __UI_UI_H__ < ui.idl > ui.h @echo ====== Generated ui.h clean: diff --git a/tools/idl2h.go b/tools/idl2h.go new file mode 100644 index 00000000..f7cc533a --- /dev/null +++ b/tools/idl2h.go @@ -0,0 +1,188 @@ +// 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) + } + 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("#define %s%s(this) ((%s%s *) (this))\n", + prefix, i.Name, + 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") + } +} diff --git a/windows/profiler.go b/tools/profiler.go similarity index 100% rename from windows/profiler.go rename to tools/profiler.go