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