github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/program/struct.go (about) 1 package program 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/Konstantin8105/c4go/ast" 8 ) 9 10 type TypeOfStruct int 11 12 const ( 13 UnionType TypeOfStruct = iota 14 StructType 15 ClassType 16 ) 17 18 // Struct represents the definition for a C struct. 19 type Struct struct { 20 // The name of the struct. 21 Name string 22 23 // IsGlobal is true for case global struct 24 IsGlobal bool 25 26 // This field is used to avoid to duplicate code for union case the type is the same. 27 Type TypeOfStruct 28 29 // Each of the fields and their C type. The field may be a string or an 30 // instance of Struct for nested structures. 31 Fields map[string]interface{} 32 33 // int - position of field 34 // string - name of field 35 FieldNames map[int]string 36 } 37 38 // NewStruct creates a new Struct definition from an ast.RecordDecl. 39 func NewStruct(p *Program, n *ast.RecordDecl) (st *Struct, err error) { 40 defer func() { 41 if err != nil { 42 err = fmt.Errorf("cannot create new structure : %T. Error : %v", 43 n, err) 44 } else { 45 p.Structs[n.Name] = st 46 } 47 }() 48 fields := make(map[string]interface{}) 49 names := map[int]string{} 50 51 counter := 0 52 for _, field := range n.Children() { 53 switch f := field.(type) { 54 case *ast.FieldDecl: 55 fields[f.Name] = f.Type 56 names[counter] = f.Name 57 58 case *ast.IndirectFieldDecl: 59 fields[f.Name] = f.Type 60 names[counter] = f.Name 61 62 case *ast.RecordDecl: 63 fields[f.Name], err = NewStruct(p, f) 64 if err != nil { 65 return 66 } 67 68 case *ast.MaxFieldAlignmentAttr, 69 *ast.AlignedAttr, 70 *ast.PackedAttr, 71 *ast.EnumDecl, 72 *ast.TransparentUnionAttr, 73 *ast.FullComment: 74 // FIXME: Should these really be ignored? 75 76 default: 77 err = fmt.Errorf("cannot decode: %#v", f) 78 return 79 } 80 counter++ 81 } 82 83 var t TypeOfStruct 84 switch n.Kind { 85 case "union": 86 t = UnionType 87 case "class": 88 t = ClassType 89 case "struct": 90 t = StructType 91 default: 92 err = fmt.Errorf("undefine kind of RecordDecl `%v`", n.Kind) 93 return 94 } 95 96 return &Struct{ 97 Name: n.Name, 98 IsGlobal: p.Function == nil, 99 Type: t, 100 Fields: fields, 101 FieldNames: names, 102 }, nil 103 } 104 105 // IsUnion - return true if the cType is 'union' or 106 // typedef of union 107 func (p *Program) IsUnion(cType string) bool { 108 if strings.HasPrefix(cType, "union ") { 109 return true 110 } 111 if _, ok := p.Unions[cType]; ok { 112 return true 113 } 114 if _, ok := p.Unions["union "+cType]; ok { 115 return true 116 } 117 if _, ok := p.GetBaseTypeOfTypedef("union " + cType); ok { 118 return true 119 } 120 if t, ok := p.GetBaseTypeOfTypedef(cType); ok { 121 if t == cType { 122 panic(fmt.Errorf("cannot be same name: %s", t)) 123 } 124 if strings.HasPrefix(t, "struct ") { 125 return false 126 } 127 if t == "" { 128 panic(fmt.Errorf("type cannot be empty")) 129 } 130 return p.IsUnion(t) 131 } 132 return false 133 } 134 135 // GetBaseTypeOfTypedef - return typedef type 136 func (p *Program) GetBaseTypeOfTypedef(cTypedef string) ( 137 cBase string, ok bool) { 138 139 cBase, ok = p.TypedefType[cTypedef] 140 if cBase == "" && ok { 141 panic(fmt.Errorf("type cannot be empty")) 142 } 143 144 if cBase == cTypedef { 145 panic(fmt.Errorf("typedef loop for : %s", cBase)) 146 } 147 148 return 149 }