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) if dd.Name == "U" { for _, dd := range dd.Type.Decls { exportDecl(dd) } } } } }
func fixQsortCmp(decl *cc.Decl) *cc.Type { ftyp := decl.Type if ftyp.Kind != cc.Func || len(ftyp.Decls) != 2 || !isGoVoidPtr(ftyp.Decls[0].Type) || !isGoVoidPtr(ftyp.Decls[1].Type) { fprintf(decl.Span, "invalid qsort cmp function %v - wrong args", c2go.GoString(ftyp)) return 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 == 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 indir1 = r != x.Right } } } }) if p1 == nil || p2 == nil { fprintf(decl.Span, "invalid qsort cmp function - cannot find arg extraction") return nil } if !sameType(p1.XType, p2.XType) { fprintf(decl.Span, "invalid qsort cmp function - different arg types %v and %v", c2go.GoString(p1.XType), c2go.GoString(p2.XType)) return nil } if indir1 != indir2 { fprintf(decl.Span, "invalid qsort cmp function - different arg indirection") return 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", c2go.GoString(typ)) return 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. 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.Op = cc.Name if ret.Op == cc.Plus { ret.Text = "true" } else { ret.Text = "false" } ret.Left = nil ret.XType = boolType return } case cc.Number: 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 }