Beispiel #1
0
func toGoType(g *flowGroup, x cc.Syntax, typ *cc.Type, cache map[*cc.Type]*cc.Type) (ret *cc.Type) {
	if typ == nil {
		return nil
	}

	// Array and func implicitly convert to pointer types, so don't
	// trust the group they are in - they'll turn into pointers incorrectly.
	if g != nil && typ.Kind != cc.Array && typ.Kind != cc.Func {
		if g.goType != nil {
			return g.goType
		}
		defer func() {
			if ret != nil && ret.Kind <= cc.Enum {
				panic("bad go type override")
			}
			g.goType = ret
		}()
	}

	// Look in cache first. This cuts off recursion for self-referential types.
	// The cache only contains aggregate types - numeric types are shared
	// by many expressions in the program and we might want to translate
	// them differently in different contexts.
	if cache[typ] != nil {
		return cache[typ]
	}

	var force *cc.Type

	if d, ok := x.(*cc.Decl); ok {
		key := declKey(d)
		force = override[key]
	}

	switch typ.Kind {
	default:
		panic(fmt.Sprintf("unexpected C type %s", typ))

	case c2go.Ideal:
		return typ

	case cc.Void:
		return &cc.Type{Kind: cc.Struct} // struct{}

	case cc.Char, cc.Uchar, cc.Short, cc.Ushort, cc.Int, cc.Uint, cc.Long, cc.Ulong, cc.Longlong, cc.Ulonglong, cc.Float, cc.Double, cc.Enum:
		// TODO: Use group.
		if force != nil {
			return force
		}
		return &cc.Type{Kind: c2goKind[typ.Kind]}

	case cc.Ptr:
		t := &cc.Type{Kind: cc.Ptr}
		cache[typ] = t
		t.Base = toGoType(nil, nil, typ.Base, cache)

		if g != nil {
			if g.goKind != 0 {
				t.Kind = g.goKind
				return t
			}
			for _, f := range g.syntax {
				if f.ptrAdd || f.ptrIndex {
					t.Kind = c2go.Slice
				}
			}
		}

		if force != nil {
			if force.Base != nil {
				return force
			}
			if force.Kind == cc.Ptr || force.Kind == c2go.Slice {
				t.Kind = force.Kind
				return t
			}
		}

		if typ.Base.Kind == cc.Char {
			t.Kind = c2go.String
			t.Base = nil
			return t
		}

		return t

	case cc.Array:
		if typ.Base.Def().Kind == cc.Char {
			return &cc.Type{Kind: c2go.String}
		}
		t := &cc.Type{Kind: cc.Array, Width: typ.Width}
		cache[typ] = t
		t.Base = toGoType(nil, nil, typ.Base, cache)
		return t

	case cc.TypedefType:
		// If this is a typedef like uchar, translate the base type directly.
		def := typ.Base
		if cc.Char <= def.Kind && def.Kind <= cc.Enum {
			return toGoType(g, x, def, cache)
		}

		// Otherwise assume it is a struct or some such, and preserve the name
		// but translate the base.
		t := &cc.Type{Kind: cc.TypedefType, Name: typ.Name, TypeDecl: typ.TypeDecl}
		cache[typ] = t
		t.Base = toGoType(nil, nil, typ.Base, cache)
		return t

	case cc.Func:
		// A func Type contains Decls, and we don't fork the Decls, so don't fork the Type.
		// The Decls themselves appear in the group lists, so they'll be handled by rewriteTypes.
		// The return value has no Decl and needs to be converted.
		if !typ.Base.Is(cc.Void) {
			typ.Base = toGoType(nil, nil, typ.Base, cache)
		}
		return typ

	case cc.Struct:
		// A struct Type contains Decls, and we don't fork the Decls, so don't fork the Type.
		// The Decls themselves appear in the group lists, so they'll be handled by rewriteTypes.
		return typ
	}
}