Beispiel #1
0
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)
				}
			}
		}
	}
}
Beispiel #2
0
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)
			}
		}
	}
}
Beispiel #3
0
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())
	}
}
Beispiel #4
0
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
}
Beispiel #5
0
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())
	}
}