func exportDecl(d *cc.Decl) { d.Name = exportName(d.Name) if d.Storage&cc.Typedef != 0 && d.Type.Kind == cc.Struct { for _, dd := range d.Type.Decls { exportDecl(dd) // type became type_, became Type_. Drop underscore now that it's not needed. if strings.HasSuffix(dd.Name, "_") && goKeyword[strings.ToLower(dd.Name[:len(dd.Name)-1])] { dd.Name = dd.Name[:len(dd.Name)-1] } if dd.Name == "U" { for _, dd := range dd.Type.Decls { exportDecl(dd) } } } } }
func renameDecl(cfg *Config, d *cc.Decl) { key := declKey(d) if cfg.rename[key] != "" { d.Name = cfg.rename[key] } if d.Storage&cc.Typedef != 0 && d.Type.Kind == cc.Struct { for _, dd := range d.Type.Decls { renameDecl(cfg, dd) if dd.Name == "U" { for _, dd := range dd.Type.Decls { renameDecl(cfg, dd) } } } } if d.Type != nil && d.Type.Kind == cc.Func && d.Body != nil { for _, s := range d.Body.Block { if s.Op == cc.StmtDecl && s.Decl.Storage&cc.Static != 0 { renameDecl(cfg, s.Decl) } } } }
func (w *Writer) genTypeDef(d *cc.Decl) { w.writeDocString(d.Name, "") goName := cNameToGoUpper(d.Name) switch d.Type.Kind { case cc.Struct: if d.Type.Decls == nil || goName == "Path" { // Opaque typedef. w.Print(`type %s struct { Ptr *C.%s }`, goName, d.Name) cFinalizer := d.Name if strings.HasSuffix(cFinalizer, "_t") { cFinalizer = cFinalizer[:len(cFinalizer)-2] } cFinalizer += "_destroy" w.Print("func free%s(obj *%s) {", goName, goName) w.Print("C.%s(obj.Ptr)", cFinalizer) w.Print("}") w.Print("func wrap%s(p *C.%s) *%s {", goName, d.Name, goName) w.Print("ret := &%s{p}", goName) w.Print("runtime.SetFinalizer(ret, free%s)", goName) w.Print("return ret") w.Print("}") } else { sharedTypes[d.Name] = goName w.Print("type %s struct {", goName) for _, d := range d.Type.Decls { typ := cTypeToMap(d.Type) w.Print("%s %s", cNameToGoUpper(d.Name), typ.goType) } w.Print("}") } case cc.Enum: type constEntry struct { goName, cName string } consts := make([]constEntry, 0, len(d.Type.Decls)) for _, d := range d.Type.Decls { constName := d.Name if strings.HasPrefix(constName, "CAIRO_") { constName = constName[len("CAIRO_"):] } constName = cNameToGoUpper(strings.ToLower(d.Name)) consts = append(consts, constEntry{constName, d.Name}) } w.Print("type %s int", goName) w.Print("const (") for _, c := range consts { w.Print("%s %s = C.%s", c.goName, goName, c.cName) } w.Print(")") if goName != "Status" { w.Print("func (i %s) String() string {", goName) w.Print("switch i {") for _, c := range consts { w.Print("case %s: return \"%s\"", c.goName, c.goName) } w.Print("default: return fmt.Sprintf(\"%s(%%d)\", i)", goName) w.Print("}") w.Print("}") } default: panic("unhandled decl " + d.String()) } }
func fixQsortCmp(decl *cc.Decl) (*cc.Type, *cc.Decl) { ftyp := decl.Type if ftyp.Kind != cc.Func || len(ftyp.Decls) != 2 || !isEmptyInterface(ftyp.Decls[0].Type) || !isEmptyInterface(ftyp.Decls[1].Type) { fprintf(decl.Span, "invalid qsort cmp function %v - wrong args", GoString(ftyp)) return nil, nil } a1, a2 := ftyp.Decls[0], ftyp.Decls[1] var eq1, eq2, p1, p2 *cc.Expr var indir1, indir2 bool cc.Preorder(decl.Body, func(x cc.Syntax) { switch x := x.(type) { case *cc.Expr: if x.Op != cc.Eq { return } r := x.Right if r.Op == cc.Indir { r = r.Left } if (r.Op == TypeAssert || r.Op == cc.Cast) && r.Left.Op == cc.Name { if r.Left.XDecl == a1 && p1 == nil { p1 = x.Left eq1 = x indir1 = r != x.Right } if r.Left.XDecl == a2 && p2 == nil { p2 = x.Left eq2 = x indir2 = r != x.Right } } } }) if p1 == nil || p2 == nil { fprintf(decl.Span, "invalid qsort cmp function - cannot find arg extraction") return nil, nil } if !sameType(p1.XType, p2.XType) { fprintf(decl.Span, "invalid qsort cmp function - different arg types %v and %v", GoString(p1.XType), GoString(p2.XType)) return nil, nil } if indir1 != indir2 { fprintf(decl.Span, "invalid qsort cmp function - different arg indirection") return nil, nil } typ := p1.XType if !indir1 { if typ.Def().Kind != cc.Ptr { fprintf(decl.Span, "invalid qsort cmp function - arg ptr cast to non-ptr %v", GoString(typ)) return nil, nil } typ = typ.Def().Base } // Have all the information. Committed. // Rewrite to take x, i, j, use x[i] for p1, x[j] for p2, // take address of x[i], x[j] if there was no indirect, // replace all return z with return z < 0. newDecl := *decl decl.Body = nil decl = &newDecl cmp := decl.Name decl.Name = "(x " + cmp + ") Less" decl.Type = &cc.Type{ Kind: cc.Func, Base: boolType, Decls: []*cc.Decl{ {Name: "i", Type: &cc.Type{Kind: cc.TypedefType}}, {Name: "j", Type: intType}, }, } prefix := "" if !indir1 { prefix = "&" } eq1.Right = &cc.Expr{Op: cc.Name, Text: prefix + "x[i]", XType: p1.XType} eq2.Right = &cc.Expr{Op: cc.Name, Text: prefix + "x[j]", XType: p1.XType} cc.Preorder(decl.Body, func(x cc.Syntax) { switch x := x.(type) { case *cc.Stmt: if x.Op == cc.Return && x.Expr != nil { ret := x.Expr // Pick off 0, -1, +1. // Otherwise rewrite ret to ret < 0. switch ret.Op { case cc.Minus, cc.Plus: if ret.Left.Op == cc.Number && ret.Left.Text == "1" { if ret.Op == cc.Plus { ret.Text = "false" } else { ret.Text = "true" } ret.Op = cc.Name ret.Left = nil ret.XType = boolType return } case cc.Number: if ret.Text == "0" { ret.Op = cc.Name ret.Text = "false" ret.XType = boolType return } } x.Expr = &cc.Expr{Op: cc.Lt, Left: ret, Right: &cc.Expr{Op: cc.Number, Text: "0"}, XType: boolType} return } } }) return typ, decl }
func (w *Writer) genTypeDef(d *cc.Decl) { w.writeDocString(d.Name, "") goName := cNameToGoUpper(d.Name) switch d.Type.Kind { case cc.Struct: if d.Type.Decls == nil || goName == "Path" { // Opaque typedef. w.Print(`type %s struct { Ptr *C.%s }`, goName, d.Name) cFinalizer := d.Name if strings.HasSuffix(cFinalizer, "_t") { cFinalizer = cFinalizer[:len(cFinalizer)-2] } cFinalizer += "_destroy" w.Print("func free%s(obj *%s) {", goName, goName) w.Print("C.%s(obj.Ptr)", cFinalizer) w.Print("}") w.Print("func wrap%s(p *C.%s) *%s {", goName, d.Name, goName) w.Print("ret := &%s{p}", goName) w.Print("runtime.SetFinalizer(ret, free%s)", goName) w.Print("return ret") w.Print("}") w.Print("// Wrap a C %s* found from some external source as a *%s. The Go side will destroy the reference when it's no longer used.", d.Name, goName) w.Print("func Wrap%s(p unsafe.Pointer) *%s {", goName, goName) w.Print("return wrap%s((*C.%s)(p))", goName, d.Name) w.Print("}") w.Print("// Construct a %s from a C %s* found from some exernal source. It is the caller's responsibility to ensure the pointer lives.", goName, d.Name) w.Print("func Borrow%s(p unsafe.Pointer) *%s {", goName, goName) w.Print("return &%s{(*C.%s)(p)}", goName, d.Name) w.Print("}") } else { sharedTypes[d.Name] = goName w.Print("type %s struct {", goName) for _, d := range d.Type.Decls { typ := cTypeToMap(d.Type) w.Print("%s %s", cNameToGoUpper(d.Name), typ.goType) } w.Print("}") } case cc.Enum: type constEntry struct { goName, cName string } consts := make([]constEntry, 0, len(d.Type.Decls)) for _, d := range d.Type.Decls { constName := d.Name if strings.HasPrefix(constName, "CAIRO_") { constName = constName[len("CAIRO_"):] } constName = cNameToGoUpper(strings.ToLower(d.Name)) consts = append(consts, constEntry{constName, d.Name}) } w.Print("type %s int", goName) w.Print("const (") for _, c := range consts { w.Print("%s %s = C.%s", c.goName, goName, c.cName) } w.Print(")") if goName != "Status" { w.Print("// String implements the Stringer interface, which is used in places like fmt's %%q. For all enums like this it returns the Go name of the constant.") w.Print("func (i %s) String() string {", goName) w.Print("switch i {") for _, c := range consts { w.Print("case %s: return \"%s\"", c.goName, c.goName) } w.Print("default: return fmt.Sprintf(\"%s(%%d)\", i)", goName) w.Print("}") w.Print("}") } default: panic("unhandled decl " + d.String()) } }