1 | // Copyright 2020 The CCGO Authors. All rights reserved.
|
---|
2 | // Use of this source code is governed by a BSD-style
|
---|
3 | // license that can be found in the LICENSE file.
|
---|
4 |
|
---|
5 | package ccgo // import "modernc.org/ccgo/v3/lib"
|
---|
6 |
|
---|
7 | import (
|
---|
8 | "fmt"
|
---|
9 | "sort"
|
---|
10 | "strings"
|
---|
11 |
|
---|
12 | "modernc.org/cc/v3"
|
---|
13 | )
|
---|
14 |
|
---|
15 | func isAggregateTypeOrUnion(t cc.Type) bool {
|
---|
16 | switch t.Kind() {
|
---|
17 | case cc.Struct, cc.Union, cc.Array:
|
---|
18 | return true
|
---|
19 | }
|
---|
20 |
|
---|
21 | return false
|
---|
22 | }
|
---|
23 |
|
---|
24 | // 6.7.8 Initialization
|
---|
25 | func (p *project) initializer(f *function, n *cc.Initializer, t cc.Type, sc cc.StorageClass, tld *tld) {
|
---|
26 | lm := map[*cc.Initializer][]cc.StringID{}
|
---|
27 | tm := map[*cc.Initializer][]cc.StringID{}
|
---|
28 | s := p.initializerFlatten(n, lm, tm)
|
---|
29 | sort.Slice(s, func(i, j int) bool {
|
---|
30 | a := s[i]
|
---|
31 | b := s[j]
|
---|
32 | if a.Offset < b.Offset {
|
---|
33 | return true
|
---|
34 | }
|
---|
35 |
|
---|
36 | if a.Offset > b.Offset {
|
---|
37 | return false
|
---|
38 | }
|
---|
39 |
|
---|
40 | if a.Field == nil || b.Field == nil || !a.Field.IsBitField() || !b.Field.IsBitField() {
|
---|
41 | panic(todo("%v: internal error: off %#x, %v: off %#x, t %v", a.Position(), a.Offset, b.Position(), b.Offset, t))
|
---|
42 | }
|
---|
43 |
|
---|
44 | return a.Field.BitFieldOffset() < b.Field.BitFieldOffset()
|
---|
45 | })
|
---|
46 | p.initializerInner("", 0, f, s, t, sc, tld, nil, lm, tm)
|
---|
47 | }
|
---|
48 |
|
---|
49 | func (p *project) initializerInner(tag string, off uintptr, f *function, s []*cc.Initializer, t cc.Type, sc cc.StorageClass, tld *tld, patchField cc.Field, lm, tm map[*cc.Initializer][]cc.StringID) {
|
---|
50 | // 11: The initializer for a scalar shall be a single expression, optionally
|
---|
51 | // enclosed in braces. The initial value of the object is that of the
|
---|
52 | // expression (after conversion); the same type constraints and conversions as
|
---|
53 | // for simple assignment apply, taking the type of the scalar to be the
|
---|
54 | // unqualified version of its declared type.
|
---|
55 | if t.IsScalarType() && len(s) == 1 {
|
---|
56 | p.w("%s%s", tidyComment("", s[0]), tag)
|
---|
57 | switch {
|
---|
58 | case tld != nil && t.Kind() == cc.Ptr && s[0].AssignmentExpression.Operand.Value() == nil:
|
---|
59 | tld.patches = append(tld.patches, initPatch{t, s[0], patchField})
|
---|
60 | p.w(" 0 ")
|
---|
61 | default:
|
---|
62 | p.assignmentExpression(f, s[0].AssignmentExpression, t, exprValue, 0)
|
---|
63 | }
|
---|
64 | return
|
---|
65 | }
|
---|
66 |
|
---|
67 | // 12: The rest of this subclause deals with initializers for objects that have
|
---|
68 | // aggregate or union type.
|
---|
69 |
|
---|
70 | k := t.Kind()
|
---|
71 |
|
---|
72 | // 13: The initializer for a structure or union object that has automatic
|
---|
73 | // storage duration shall be either an initializer list as described below, or
|
---|
74 | // a single expression that has compatible structure or union type. In the
|
---|
75 | // latter case, the initial value of the object, including unnamed members, is
|
---|
76 | // that of the expression.
|
---|
77 | if sc == cc.Automatic && len(s) == 1 {
|
---|
78 | switch k {
|
---|
79 | case cc.Struct, cc.Union:
|
---|
80 | if compatibleStructOrUnion(t, s[0].AssignmentExpression.Operand.Type()) {
|
---|
81 | p.w("%s%s", tidyComment("", s[0]), tag)
|
---|
82 | p.assignmentExpression(f, s[0].AssignmentExpression, t, exprValue, 0)
|
---|
83 | return
|
---|
84 | }
|
---|
85 | }
|
---|
86 | }
|
---|
87 |
|
---|
88 | if k == cc.Array && len(s) == 1 {
|
---|
89 | et := t.Elem()
|
---|
90 | switch {
|
---|
91 | case isCharType(et):
|
---|
92 | // 14: An array of character type may be initialized by a character string
|
---|
93 | // literal, optionally enclosed in braces. Successive characters of the
|
---|
94 | // character string literal (including the terminating null character if there
|
---|
95 | // is room or if the array is of unknown size) initialize the elements of the
|
---|
96 | // array.
|
---|
97 | if x, ok := s[0].AssignmentExpression.Operand.Value().(cc.StringValue); ok {
|
---|
98 | p.w("%s%s", tidyComment("", s[0]), tag)
|
---|
99 | str := cc.StringID(x).String()
|
---|
100 | slen := uintptr(len(str)) + 1
|
---|
101 | alen := t.Len()
|
---|
102 | switch {
|
---|
103 | case alen < slen-1:
|
---|
104 | p.w("*(*%s)(unsafe.Pointer(%s))", p.typ(s[0], t), p.stringLiteralString(str[:alen]))
|
---|
105 | case alen < slen:
|
---|
106 | p.w("*(*%s)(unsafe.Pointer(%s))", p.typ(s[0], t), p.stringLiteralString(str))
|
---|
107 | default: // alen >= slen
|
---|
108 | p.w("*(*%s)(unsafe.Pointer(%s))", p.typ(s[0], t), p.stringLiteralString(str+strings.Repeat("\x00", int(alen-slen))))
|
---|
109 | }
|
---|
110 | return
|
---|
111 | }
|
---|
112 | case p.isWCharType(et):
|
---|
113 | // 15: An array with element type compatible with wchar_t may be initialized by
|
---|
114 | // a wide string literal, optionally enclosed in braces. Successive wide
|
---|
115 | // characters of the wide string literal (including the terminating null wide
|
---|
116 | // character if there is room or if the array is of unknown size) initialize
|
---|
117 | // the elements of the array.
|
---|
118 | if x, ok := s[0].AssignmentExpression.Operand.Value().(cc.WideStringValue); ok {
|
---|
119 | p.w("%s%s", tidyComment("", s[0]), tag)
|
---|
120 | str := []rune(cc.StringID(x).String())
|
---|
121 | slen := uintptr(len(str)) + 1
|
---|
122 | alen := t.Len()
|
---|
123 | switch {
|
---|
124 | case alen < slen-1:
|
---|
125 | panic(todo("", p.pos(s[0])))
|
---|
126 | case alen < slen:
|
---|
127 | p.w("*(*%s)(unsafe.Pointer(%s))", p.typ(s[0], t), p.wideStringLiteral(x, 0))
|
---|
128 | default: // alen >= slen
|
---|
129 | p.w("*(*%s)(unsafe.Pointer(%s))", p.typ(s[0], t), p.wideStringLiteral(x, int(alen-slen)))
|
---|
130 | }
|
---|
131 | return
|
---|
132 | }
|
---|
133 | }
|
---|
134 | }
|
---|
135 |
|
---|
136 | // 16: Otherwise, the initializer for an object that has aggregate or union
|
---|
137 | // type shall be a brace-enclosed list of initializers for the elements or
|
---|
138 | // named members.
|
---|
139 | switch k {
|
---|
140 | case cc.Array:
|
---|
141 | p.initializerArray(tag, off, f, s, t, sc, tld, lm, tm)
|
---|
142 | case cc.Struct:
|
---|
143 | p.initializerStruct(tag, off, f, s, t, sc, tld, lm, tm)
|
---|
144 | case cc.Union:
|
---|
145 | p.initializerUnion(tag, off, f, s, t, sc, tld, lm, tm)
|
---|
146 | default:
|
---|
147 | panic(todo("%v: internal error: %v alias %v %v", s[0].Position(), t, t.Alias(), len(s)))
|
---|
148 | }
|
---|
149 | }
|
---|
150 |
|
---|
151 | func (p *project) initializerArray(tag string, off uintptr, f *function, s []*cc.Initializer, t cc.Type, sc cc.StorageClass, tld *tld, lm, tm map[*cc.Initializer][]cc.StringID) {
|
---|
152 | if len(s) == 0 {
|
---|
153 | p.w("%s%s{}", tag, p.typ(nil, t))
|
---|
154 | return
|
---|
155 | }
|
---|
156 |
|
---|
157 | et := t.Elem()
|
---|
158 | esz := et.Size()
|
---|
159 | s0 := s[0]
|
---|
160 | p.w("%s%s%s{", initComment(s0, lm), tag, p.typ(s0, t))
|
---|
161 | var a [][]*cc.Initializer
|
---|
162 | for len(s) != 0 {
|
---|
163 | s2, parts, _ := p.initializerArrayElement(off, s, esz)
|
---|
164 | s = s2
|
---|
165 | a = append(a, parts)
|
---|
166 | }
|
---|
167 | mustIndex := uintptr(len(a)) != t.Len()
|
---|
168 | var parts []*cc.Initializer
|
---|
169 | for _, parts = range a {
|
---|
170 | var comma *cc.Token
|
---|
171 | comma = parts[len(parts)-1].TrailingComma()
|
---|
172 | elemOff := (parts[0].Offset - off) / esz * esz
|
---|
173 | tag = ""
|
---|
174 | if mustIndex {
|
---|
175 | tag = fmt.Sprintf("%d:", elemOff/esz)
|
---|
176 | }
|
---|
177 | p.initializerInner(tag, off+elemOff, f, parts, et, sc, tld, nil, lm, tm)
|
---|
178 | p.preCommaSep(comma)
|
---|
179 | p.w(",")
|
---|
180 | }
|
---|
181 | p.w("%s}", initComment(parts[len(parts)-1], tm))
|
---|
182 | }
|
---|
183 |
|
---|
184 | func initComment(n *cc.Initializer, m map[*cc.Initializer][]cc.StringID) string {
|
---|
185 | a := m[n]
|
---|
186 | if len(a) == 0 {
|
---|
187 | return ""
|
---|
188 | }
|
---|
189 |
|
---|
190 | m[n] = a[1:]
|
---|
191 | return tidyCommentString(a[0].String())
|
---|
192 | }
|
---|
193 |
|
---|
194 | func (p *project) initializerArrayElement(off uintptr, s []*cc.Initializer, elemSize uintptr) (r []*cc.Initializer, parts []*cc.Initializer, isZero bool) {
|
---|
195 | r = s
|
---|
196 | isZero = true
|
---|
197 | valueOff := s[0].Offset - off
|
---|
198 | elemOff := valueOff - valueOff%elemSize
|
---|
199 | nextOff := elemOff + elemSize
|
---|
200 | for len(s) != 0 {
|
---|
201 | if v := s[0]; v.Offset-off < nextOff {
|
---|
202 | s = s[1:]
|
---|
203 | parts = append(parts, v)
|
---|
204 | if !v.AssignmentExpression.Operand.IsZero() {
|
---|
205 | isZero = false
|
---|
206 | }
|
---|
207 | continue
|
---|
208 | }
|
---|
209 |
|
---|
210 | break
|
---|
211 | }
|
---|
212 | return r[len(parts):], parts, isZero
|
---|
213 | }
|
---|
214 |
|
---|
215 | func (p *project) initializerStruct(tag string, off uintptr, f *function, s []*cc.Initializer, t cc.Type, sc cc.StorageClass, tld *tld, lm, tm map[*cc.Initializer][]cc.StringID) {
|
---|
216 | if len(s) == 0 {
|
---|
217 | p.w("%s%s{}", tag, p.typ(nil, t))
|
---|
218 | return
|
---|
219 | }
|
---|
220 |
|
---|
221 | if t.HasFlexibleMember() {
|
---|
222 | p.err(s[0], "flexible array members not supported")
|
---|
223 | return
|
---|
224 | }
|
---|
225 |
|
---|
226 | p.w("%s%s%s{", initComment(s[0], lm), tag, p.typ(s[0], t))
|
---|
227 | var parts []*cc.Initializer
|
---|
228 | var isZero bool
|
---|
229 | var fld cc.Field
|
---|
230 | for len(s) != 0 {
|
---|
231 | var comma *cc.Token
|
---|
232 | s, fld, parts, isZero = p.structInitializerParts(off, s, t)
|
---|
233 | if isZero {
|
---|
234 | continue
|
---|
235 | }
|
---|
236 |
|
---|
237 | if fld.Type().IsIncomplete() {
|
---|
238 | panic(todo(""))
|
---|
239 | }
|
---|
240 |
|
---|
241 | comma = parts[len(parts)-1].TrailingComma()
|
---|
242 | tag = fmt.Sprintf("%s:", p.fieldName2(parts[0], fld))
|
---|
243 | ft := fld.Type()
|
---|
244 | switch {
|
---|
245 | case fld.IsBitField():
|
---|
246 | bft := p.bitFileType(parts[0], fld.BitFieldBlockWidth())
|
---|
247 | off0 := fld.Offset()
|
---|
248 | first := true
|
---|
249 | for _, v := range parts {
|
---|
250 | if v.AssignmentExpression.Operand.IsZero() {
|
---|
251 | continue
|
---|
252 | }
|
---|
253 |
|
---|
254 | if !first {
|
---|
255 | p.w("|")
|
---|
256 | }
|
---|
257 | first = false
|
---|
258 | bitFld := v.Field
|
---|
259 | p.w("%s%s", tidyComment("", v.AssignmentExpression), tag)
|
---|
260 | tag = ""
|
---|
261 | p.assignmentExpression(f, v.AssignmentExpression, bft, exprValue, 0)
|
---|
262 | p.w("&%#x", uint64(1)<<uint64(bitFld.BitFieldWidth())-1)
|
---|
263 | if o := bitFld.BitFieldOffset() + 8*int((bitFld.Offset()-off0)); o != 0 {
|
---|
264 | p.w("<<%d", o)
|
---|
265 | }
|
---|
266 | }
|
---|
267 | default:
|
---|
268 | p.initializerInner(tag, off+fld.Offset(), f, parts, ft, sc, tld, fld, lm, tm)
|
---|
269 | }
|
---|
270 | p.preCommaSep(comma)
|
---|
271 | p.w(",")
|
---|
272 | }
|
---|
273 | p.w("%s}", initComment(parts[len(parts)-1], tm))
|
---|
274 | }
|
---|
275 |
|
---|
276 | func (p *project) preCommaSep(comma *cc.Token) {
|
---|
277 | if comma == nil {
|
---|
278 | return
|
---|
279 | }
|
---|
280 |
|
---|
281 | p.w("%s", strings.TrimSpace(comma.Sep.String()))
|
---|
282 | }
|
---|
283 |
|
---|
284 | func (p *project) structInitializerParts(off uintptr, s []*cc.Initializer, t cc.Type) (r []*cc.Initializer, fld cc.Field, parts []*cc.Initializer, isZero bool) {
|
---|
285 | if len(s) == 0 {
|
---|
286 | return nil, nil, nil, true
|
---|
287 | }
|
---|
288 |
|
---|
289 | part := s[0]
|
---|
290 | isZero = part.AssignmentExpression.Operand.IsZero()
|
---|
291 | parts = append(parts, part)
|
---|
292 | s = s[1:]
|
---|
293 | fld, _, fNext := p.containingStructField(part, off, t)
|
---|
294 | for len(s) != 0 {
|
---|
295 | part = s[0]
|
---|
296 | vOff := part.Offset
|
---|
297 | if vOff >= fNext {
|
---|
298 | break
|
---|
299 | }
|
---|
300 |
|
---|
301 | isZero = isZero && part.AssignmentExpression.Operand.IsZero()
|
---|
302 | parts = append(parts, part)
|
---|
303 | s = s[1:]
|
---|
304 | }
|
---|
305 | return s, fld, parts, isZero
|
---|
306 | }
|
---|
307 |
|
---|
308 | func (p *project) containingStructField(part *cc.Initializer, off uintptr, t cc.Type) (f cc.Field, fOff, fNext uintptr) {
|
---|
309 | nf := t.NumField()
|
---|
310 | vOff := part.Offset
|
---|
311 | for i := []int{0}; i[0] < nf; i[0]++ {
|
---|
312 | f = t.FieldByIndex(i)
|
---|
313 | if f.IsBitField() && f.Name() == 0 { // Anonymous bit fields cannot be initialized.
|
---|
314 | continue
|
---|
315 | }
|
---|
316 |
|
---|
317 | fOff = off + f.Offset()
|
---|
318 | switch {
|
---|
319 | case f.IsBitField():
|
---|
320 | fNext = fOff + uintptr(f.BitFieldBlockWidth())>>3
|
---|
321 | default:
|
---|
322 | fNext = fOff + f.Type().Size()
|
---|
323 | }
|
---|
324 | if vOff >= fOff && vOff < fNext {
|
---|
325 | return f, fOff, fNext
|
---|
326 | }
|
---|
327 | }
|
---|
328 |
|
---|
329 | panic(todo("%v: internal error", p.pos(part)))
|
---|
330 | }
|
---|
331 |
|
---|
332 | func (p *project) initializerUnion(tag string, off uintptr, f *function, s []*cc.Initializer, t cc.Type, sc cc.StorageClass, tld *tld, lm, tm map[*cc.Initializer][]cc.StringID) {
|
---|
333 | if len(s) == 0 {
|
---|
334 | p.w("%s%s{}", tag, p.typ(nil, t))
|
---|
335 | return
|
---|
336 | }
|
---|
337 |
|
---|
338 | if t.HasFlexibleMember() {
|
---|
339 | p.err(s[0], "flexible array members not supported")
|
---|
340 | return
|
---|
341 | }
|
---|
342 |
|
---|
343 | parts, isZero := p.initializerUnionField(off, s, t)
|
---|
344 | if len(parts) == 0 || isZero {
|
---|
345 | p.w("%s%s%s{", initComment(s[0], lm), tag, p.typ(s[0], t))
|
---|
346 | p.w("%s}", initComment(parts[len(parts)-1], tm))
|
---|
347 | return
|
---|
348 | }
|
---|
349 |
|
---|
350 | p.w("%sfunc() (r %s) {", tag, p.typ(parts[0], t))
|
---|
351 | for _, part := range parts {
|
---|
352 | var ft cc.Type
|
---|
353 | fld := part.Field
|
---|
354 | if fld != nil && fld.IsBitField() {
|
---|
355 | }
|
---|
356 |
|
---|
357 | if ft == nil {
|
---|
358 | ft = part.Type()
|
---|
359 | }
|
---|
360 | if ft.Kind() == cc.Array {
|
---|
361 | et := ft.Elem()
|
---|
362 | switch {
|
---|
363 | case isCharType(et):
|
---|
364 | switch x := part.AssignmentExpression.Operand.Value().(type) {
|
---|
365 | case cc.StringValue:
|
---|
366 | str := cc.StringID(x).String()
|
---|
367 | slen := uintptr(len(str)) + 1
|
---|
368 | alen := ft.Len()
|
---|
369 | switch {
|
---|
370 | case alen < slen-1:
|
---|
371 | p.w("copy(((*[%d]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&r))+%d)))[:], (*[%d]byte)(unsafe.Pointer(%s))[:])\n", alen, part.Offset-off, alen, p.stringLiteralString(str[:alen]))
|
---|
372 | case alen < slen:
|
---|
373 | p.w("copy(((*[%d]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&r))+%d)))[:], (*[%d]byte)(unsafe.Pointer(%s))[:])\n", alen, part.Offset-off, alen, p.stringLiteralString(str))
|
---|
374 | default: // alen >= slen
|
---|
375 | p.w("copy(((*[%d]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&r))+%d)))[:], (*[%d]byte)(unsafe.Pointer(%s))[:])\n", alen, part.Offset-off, alen, p.stringLiteralString(str+strings.Repeat("\x00", int(alen-slen))))
|
---|
376 | }
|
---|
377 | continue
|
---|
378 | default:
|
---|
379 | panic(todo("%v: %v <- %T", p.pos(part), et, x))
|
---|
380 | }
|
---|
381 | case p.isWCharType(et):
|
---|
382 | panic(todo(""))
|
---|
383 | }
|
---|
384 | ft = et
|
---|
385 | }
|
---|
386 | switch {
|
---|
387 | case fld != nil && fld.IsBitField():
|
---|
388 | bft := p.bitFileType(part, fld.BitFieldBlockWidth())
|
---|
389 | p.w("*(*%s)(unsafe.Pointer(uintptr(unsafe.Pointer(&r))+%d)) |= ", p.typ(part, bft), part.Offset-off)
|
---|
390 | p.assignmentExpression(f, part.AssignmentExpression, bft, exprValue, 0)
|
---|
391 | p.w("&%#x", uint64(1)<<uint64(fld.BitFieldWidth())-1)
|
---|
392 | if o := fld.BitFieldOffset(); o != 0 {
|
---|
393 | p.w("<<%d", o)
|
---|
394 | }
|
---|
395 | default:
|
---|
396 | p.w("*(*%s)(unsafe.Pointer(uintptr(unsafe.Pointer(&r))+%d)) = ", p.typ(part, ft), part.Offset-off)
|
---|
397 | p.assignmentExpression(f, part.AssignmentExpression, ft, exprValue, 0)
|
---|
398 | }
|
---|
399 | p.w("\n")
|
---|
400 | }
|
---|
401 | p.w("return r\n")
|
---|
402 | p.w("}()")
|
---|
403 | }
|
---|
404 |
|
---|
405 | func (p *project) initializerUnionField(off uintptr, s []*cc.Initializer, t cc.Type) (parts []*cc.Initializer, isZero bool) {
|
---|
406 | isZero = true
|
---|
407 | nextOff := off + t.Size()
|
---|
408 | for len(s) != 0 {
|
---|
409 | if v := s[0]; v.Offset < nextOff {
|
---|
410 | s = s[1:]
|
---|
411 | parts = append(parts, v)
|
---|
412 | isZero = isZero && v.AssignmentExpression.Operand.IsZero()
|
---|
413 | continue
|
---|
414 | }
|
---|
415 |
|
---|
416 | break
|
---|
417 | }
|
---|
418 | return parts, isZero
|
---|
419 | }
|
---|
420 |
|
---|
421 | func compatibleStructOrUnion(t1, t2 cc.Type) bool {
|
---|
422 | switch t1.Kind() {
|
---|
423 | case cc.Struct:
|
---|
424 | if t2.Kind() != cc.Struct {
|
---|
425 | return false
|
---|
426 | }
|
---|
427 | case cc.Union:
|
---|
428 | if t2.Kind() != cc.Union {
|
---|
429 | return false
|
---|
430 | }
|
---|
431 | default:
|
---|
432 | return false
|
---|
433 | }
|
---|
434 |
|
---|
435 | if tag := t1.Tag(); tag != 0 && t2.Tag() != tag {
|
---|
436 | return false
|
---|
437 | }
|
---|
438 |
|
---|
439 | nf := t1.NumField()
|
---|
440 | if t2.NumField() != nf {
|
---|
441 | return false
|
---|
442 | }
|
---|
443 |
|
---|
444 | for i := []int{0}; i[0] < nf; i[0]++ {
|
---|
445 | f1 := t1.FieldByIndex(i)
|
---|
446 | f2 := t2.FieldByIndex(i)
|
---|
447 | nm := f1.Name()
|
---|
448 | if f2.Name() != nm {
|
---|
449 | return false
|
---|
450 | }
|
---|
451 |
|
---|
452 | ft1 := f1.Type()
|
---|
453 | ft2 := f2.Type()
|
---|
454 | if ft1.Size() != ft2.Size() ||
|
---|
455 | f1.IsBitField() != f2.IsBitField() ||
|
---|
456 | f1.BitFieldOffset() != f2.BitFieldOffset() ||
|
---|
457 | f1.BitFieldWidth() != f2.BitFieldWidth() {
|
---|
458 | return false
|
---|
459 | }
|
---|
460 |
|
---|
461 | if !compatibleType(ft1, ft2) {
|
---|
462 | return false
|
---|
463 | }
|
---|
464 | }
|
---|
465 | return true
|
---|
466 | }
|
---|
467 |
|
---|
468 | func compatibleType(t1, t2 cc.Type) bool {
|
---|
469 | if t1.Kind() != t2.Kind() {
|
---|
470 | return false
|
---|
471 | }
|
---|
472 |
|
---|
473 | switch t1.Kind() {
|
---|
474 | case cc.Array:
|
---|
475 | if t1.Len() != t2.Len() || !compatibleType(t1.Elem(), t2.Elem()) {
|
---|
476 | return false
|
---|
477 | }
|
---|
478 | case cc.Struct, cc.Union:
|
---|
479 | if !compatibleStructOrUnion(t1, t2) {
|
---|
480 | return false
|
---|
481 | }
|
---|
482 | }
|
---|
483 | return true
|
---|
484 | }
|
---|
485 |
|
---|
486 | func (p *project) bitFileType(n cc.Node, bits int) cc.Type {
|
---|
487 | switch bits {
|
---|
488 | case 8:
|
---|
489 | return p.task.cfg.ABI.Type(cc.UChar)
|
---|
490 | case 16:
|
---|
491 | return p.task.cfg.ABI.Type(cc.UShort)
|
---|
492 | case 32:
|
---|
493 | return p.task.cfg.ABI.Type(cc.UInt)
|
---|
494 | case 64:
|
---|
495 | return p.task.cfg.ABI.Type(cc.ULongLong)
|
---|
496 | default:
|
---|
497 | panic(todo("%v: internal error: %v", n.Position(), bits))
|
---|
498 | }
|
---|
499 | }
|
---|
500 |
|
---|
501 | func (p *project) isWCharType(t cc.Type) bool {
|
---|
502 | if t.IsAliasType() {
|
---|
503 | if id := t.AliasDeclarator().Name(); id == idWcharT ||
|
---|
504 | p.task.goos == "windows" && id == idWinWchar {
|
---|
505 | return true
|
---|
506 | }
|
---|
507 | }
|
---|
508 |
|
---|
509 | return false
|
---|
510 | }
|
---|
511 |
|
---|
512 | func isCharType(t cc.Type) bool {
|
---|
513 | switch t.Kind() {
|
---|
514 | case cc.Char, cc.SChar, cc.UChar:
|
---|
515 | return true
|
---|
516 | }
|
---|
517 |
|
---|
518 | return false
|
---|
519 | }
|
---|
520 |
|
---|
521 | func (p *project) initializerFlatten(n *cc.Initializer, lm, tm map[*cc.Initializer][]cc.StringID) (s []*cc.Initializer) {
|
---|
522 | switch n.Case {
|
---|
523 | case cc.InitializerExpr: // AssignmentExpression
|
---|
524 | return append(s, n)
|
---|
525 | case cc.InitializerInitList: // '{' InitializerList ',' '}'
|
---|
526 | first := true
|
---|
527 | for list := n.InitializerList; list != nil; list = list.InitializerList {
|
---|
528 | in := list.Initializer
|
---|
529 | k := in
|
---|
530 | if in.Case != cc.InitializerExpr {
|
---|
531 | k = nil
|
---|
532 | }
|
---|
533 | if first {
|
---|
534 | lm[k] = append(lm[k], append(lm[nil], n.Token.Sep)...)
|
---|
535 | if k != nil {
|
---|
536 | delete(lm, nil)
|
---|
537 | }
|
---|
538 | first = false
|
---|
539 | }
|
---|
540 | if list.InitializerList == nil {
|
---|
541 | tm[k] = append([]cc.StringID{n.Token3.Sep}, append(tm[nil], tm[k]...)...)
|
---|
542 | tm[k] = append(tm[k], append(tm[nil], n.Token3.Sep)...)
|
---|
543 | if k != nil {
|
---|
544 | delete(tm, nil)
|
---|
545 | }
|
---|
546 | }
|
---|
547 | s = append(s, p.initializerFlatten(in, lm, tm)...)
|
---|
548 | }
|
---|
549 | return s
|
---|
550 | default:
|
---|
551 | panic(todo("%v: internal error: %v", n.Position(), n.Case))
|
---|
552 | }
|
---|
553 | }
|
---|