This repository has been archived by the owner on Apr 23, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
param.go
586 lines (529 loc) · 17.8 KB
/
param.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
package main
import (
"fmt"
"log"
"strconv"
"strings"
"unicode"
)
func (self *Param) GetGoName() string {
goName := self.Name
if isGoReservedWord(goName) {
goName += "_"
}
return goName
}
func (self *Param) CollectInfo(isReturn bool, fn *Function) {
// name
self.GoName = self.GetGoName()
if isReturn {
self.GoName = "return__"
}
// type info
if self.Array != nil { // array type
self.IsArray = true
self.CType = self.Array.CType
self.CTypeName = self.Array.Name // for spec only
self.ElementCType = self.Array.Type.CType
self.ElementCTypeName = self.Array.Type.Name // for spec only
self.ElementGoType = cTypeToGoType(self.ElementCType)
if self.Array.Length != "" { // length param
n, err := strconv.Atoi(self.Array.Length)
checkError(err)
self.LenParamName = fn.Params[n].GetGoName()
}
if self.Array.ZeroTerminated == "1" {
self.IsZeroTerminated = true
}
} else if self.Type != nil { // non-array type
self.CType = self.Type.CType
self.CTypeName = self.Type.Name // for spec only
}
self.GoType = cTypeToGoType(self.CType) // go type in function signature
if self.GoType == "" {
log.Fatal("ctype is not converted to gotype " + self.CType)
}
// skip void type
if self.CTypeName == "none" || self.CType == "void" || self.GoType == "C.void" {
self.IsVoid = true
return
}
// check direction
if self.Direction == "out" { // out param
if !strings.HasSuffix(self.CType, "*") || !strings.HasPrefix(self.GoType, "*") {
log.Fatal("non-pointer out param " + self.CType)
}
// convert to non-pointer type
self.CType = self.CType[:len(self.CType)-1]
self.GoType = self.GoType[1:]
} else if self.Direction == "" { // in param
self.Direction = "in"
}
if isReturn {
self.Direction = "out"
}
// type spec, for type mapping
spec := self.Direction
if self.GoType != "" {
spec += " GoType " + self.GoType
}
if self.CTypeName != "" {
spec += " TypeName " + self.CTypeName
}
if self.IsArray {
spec += " IsArray"
}
if self.ElementGoType != "" {
spec += " ElemType " + self.ElementGoType
}
if self.ElementCTypeName != "" {
spec += " ElemName " + self.ElementCTypeName
}
if self.LenParamName != "" {
spec += " HasLenParam"
}
if self.IsZeroTerminated {
spec += " ZeroTerminated"
}
self.TypeSpec = spec
// type mapping
self.MappedType = self.MapType()
// cgo
if self.Direction == "in" {
self.InParamMarshal() // convert go value to c value
} else if self.Direction == "out" {
self.OutParamMarshal() // convert c value to go value
}
}
var TypeMapping = make(map[string]string)
func (self *Param) MapType() (ret string) {
// query type mapping dict
var ok bool
if ret, ok = TypeMapping[self.TypeSpec]; ok {
return
}
// skip complex types
t := self.GoType
for t[0] == '*' {
t = t[1:]
}
if strings.HasPrefix(t, "C.") && unicode.IsUpper(rune(t[2])) {
ret = self.GoType
return
}
switch self.TypeSpec {
// bool
case "in GoType C.gboolean TypeName gboolean",
"out GoType C.gboolean TypeName gboolean":
ret = "bool"
// numeric
case "in GoType C.gchar TypeName gchar",
"out GoType C.gchar TypeName gchar":
ret = "byte"
case "in GoType C.gint TypeName gint",
"in GoType C.int TypeName gint",
"out GoType C.int TypeName gint",
"out GoType C.pid_t TypeName gint",
"out GoType C.gint TypeName gint":
ret = "int"
case "in GoType C.guint TypeName guint",
"in GoType C.uid_t TypeName guint",
"out GoType C.uid_t TypeName guint",
"out GoType C.guint TypeName guint":
ret = "uint"
case "out GoType C.gunichar TypeName gunichar",
"in GoType C.gunichar TypeName gunichar":
ret = "rune"
case "in GoType C.gint8 TypeName gint8":
ret = "int8"
case "in GoType C.guint8 TypeName guint8",
"out GoType C.guchar TypeName guint8",
"in GoType C.guchar TypeName guint8",
"out GoType C.guint8 TypeName guint8":
ret = "uint8"
case "in GoType C.gint16 TypeName gint16",
"out GoType C.gint16 TypeName gint16":
ret = "int16"
case "out GoType C.guint16 TypeName guint16",
"in GoType C.guint16 TypeName guint16":
ret = "uint16"
case "out GoType C.gint32 TypeName gint32",
"in GoType C.gint32 TypeName gint32":
ret = "int32"
case "in GoType C.guint32 TypeName guint32",
"out GoType C.guint32 TypeName guint32":
ret = "uint32"
case "in GoType C.glong TypeName glong",
"out GoType C.glong TypeName glong",
"in GoType C.gsize TypeName gsize",
"in GoType C.gssize TypeName gssize",
"in GoType C.gint64 TypeName gint64",
"out GoType C.gint64 TypeName gint64",
"out GoType C.gssize TypeName gssize",
"in GoType C.goffset TypeName gint64",
"out GoType C.goffset TypeName gint64",
"out GoType C.gsize TypeName gsize":
ret = "int64"
case "in GoType C.gulong TypeName gulong",
"out GoType C.gulong TypeName gulong",
"out GoType C.guint64 TypeName guint64",
"in GoType C.guint64 TypeName guint64":
ret = "uint64"
case "in GoType C.gfloat TypeName gfloat",
"out GoType C.gfloat TypeName gfloat":
ret = "float32"
case "in GoType C.gdouble TypeName gdouble",
"in GoType C.double TypeName gdouble",
"out GoType C.double TypeName gdouble",
"in GoType C.double TypeName long double",
"out GoType C.gdouble TypeName gdouble":
ret = "float64"
// string
case "in GoType *C.gchar TypeName utf8",
"in GoType *C.char TypeName utf8",
"in GoType *C.gchar TypeName filename",
"out GoType *C.char TypeName utf8",
"out GoType *C.gchar TypeName filename",
"in GoType *C.char TypeName filename",
"out GoType *C.guchar IsArray ElemType *C.guchar ElemName guint8 HasLenParam",
"in GoType *C.gchar IsArray ElemName gchar HasLenParam",
"out GoType *C.gchar TypeName utf8":
ret = "string"
// untyped pointer
case "in GoType C.gpointer TypeName gpointer",
"in GoType C.gconstpointer TypeName gpointer",
"in GoType unsafe.Pointer TypeName gpointer",
"out GoType C.gpointer TypeName gpointer":
ret = "unsafe.Pointer"
// string slice
case "in GoType **C.gchar IsArray ElemType *C.gchar ElemName utf8",
"in GoType **C.gchar IsArray ElemName utf8",
"out GoType **C.gchar IsArray ElemType **C.gchar ElemName utf8 HasLenParam ZeroTerminated",
"in GoType **C.guchar TypeName guint8",
"in GoType **C.char IsArray ElemType *C.char ElemName utf8",
"in GoType **C.char IsArray ElemName utf8",
"out GoType **C.gchar IsArray ElemName utf8 HasLenParam",
"in GoType **C.char IsArray ElemType *C.char ElemName utf8 HasLenParam",
"in GoType **C.gchar TypeName utf8":
ret = "[]string"
// numeric slice
case "in GoType *C.gint IsArray ElemType C.gint ElemName gint",
"out GoType *C.gint IsArray ElemType *C.gint ElemName gint HasLenParam",
"out GoType *C.gint IsArray ElemType C.gint ElemName gint HasLenParam",
"in GoType *C.gint IsArray ElemType C.gint ElemName gint HasLenParam":
ret = "[]int"
case "out GoType *C.guint IsArray ElemType C.guint ElemName guint HasLenParam":
ret = "[]uint"
case "in GoType *C.guint8 IsArray ElemName guint8":
ret = "[]uint8"
// bytes
case "out GoType *C.guint8 IsArray ElemType C.guint8 ElemName guint8 HasLenParam",
"in GoType *C.guint8 IsArray ElemType C.guint8 ElemName guint8 HasLenParam",
"out GoType *C.guchar IsArray ElemType C.guchar ElemName guint8 HasLenParam",
"in GoType *C.gchar IsArray ElemType C.gchar ElemName utf8 HasLenParam",
"out GoType *C.gchar IsArray ElemName guint8 HasLenParam",
"in GoType *C.guchar IsArray ElemName guint8 HasLenParam",
"out GoType *C.guchar IsArray ElemName guint8 HasLenParam",
"in GoType *C.guchar IsArray ElemType C.guchar ElemName guint8 HasLenParam",
"out GoType unsafe.Pointer IsArray ElemName guint8 HasLenParam",
"in GoType *C.guchar IsArray ElemType C.guchar ElemName guint8",
"in GoType unsafe.Pointer IsArray ElemName guint8 HasLenParam",
"in GoType *C.gchar IsArray ElemName guint8 HasLenParam":
ret = "[]byte"
// pointer to fundamental types
case "in GoType *C.gint TypeName gint",
"in GoType *C.guint16 TypeName guint16",
"in GoType *C.gsize TypeName gsize",
"in GoType *C.int TypeName gint":
ret = self.GoType
// not enough info FIXME patch it. in param may be easy
case "out GoType *C.gint IsArray ElemType C.gint ElemName gint",
"out GoType **C.gchar IsArray ElemName utf8",
"out GoType *C.gchar* const IsArray ElemName utf8",
"out GoType *C.guint8 TypeName guint8",
"out GoType *C.guint IsArray ElemType *C.guint ElemName guint",
"out GoType *C.gunichar2 TypeName guint16",
"out GoType *C.gunichar TypeName gunichar",
"in GoType *C.gunichar2 TypeName guint16",
"in GoType *C.gunichar TypeName gunichar",
"out GoType *C.char* const IsArray ElemName utf8",
"in GoType *C.guchar TypeName guint8",
"out GoType **C.gchar IsArray ElemType **C.gchar ElemName utf8",
"out GoType *C.gchar IsArray ElemName guint8",
"in GoType *C.gpointer TypeName gpointer",
"out GoType *C.char IsArray ElemName guint8",
"out GoType **C.char IsArray ElemName utf8",
"in GoType **C.char TypeName utf8",
"out GoType *C.guchar TypeName guint8",
"out GoType *C.guchar IsArray ElemType C.guchar ElemName guint8",
"in GoType ***C.gchar TypeName utf8",
"in GoType *C.glong TypeName glong":
ret = self.GoType
// inout to in param
case "in GoType ***C.char IsArray ElemType **C.char ElemName utf8 HasLenParam",
"in GoType ***C.gchar IsArray ElemType **C.gchar ElemName utf8 HasLenParam":
ret = self.GoType
// cairo TODO
case "in GoType *C.cairo_surface_t TypeName cairo.Surface",
"out GoType *C.cairo_region_t TypeName cairo.Region",
"in GoType *C.cairo_t TypeName cairo.Context",
"out GoType *C.cairo_surface_t TypeName cairo.Surface",
"out GoType *C.cairo_t TypeName cairo.Context",
"in GoType *C.cairo_region_t TypeName cairo.Region":
ret = self.GoType
default:
p("FIXME type mapping %s @ %s -> %s\n", self.Name, self.Function.CIdentifier, self.TypeSpec)
ret = self.GoType
}
return
}
var InParamMapping = make(map[string]func(*Param))
func (self *Param) InParamMarshal() {
if self.GoType == self.MappedType { // not mapped
self.CgoParam = self.GoName
} else { // do type cast
spec := fmt.Sprintf("%s -> %s", self.MappedType, self.GoType)
// query mapping
if f, ok := InParamMapping[spec]; ok {
f(self)
return
}
ff := func(s string) string {
return replace(s, map[string]string{
"name": self.GoName,
})
}
// check xml defined
if e, ok := self.Generator.InParamMarshals[spec]; ok {
if e.Param != "" {
self.CgoParam = ff(e.Param)
}
if e.Before != "" {
self.CgoBeforeStmt += ff(e.Before)
}
if e.After != "" {
self.CgoAfterStmt += ff(e.After)
}
return
}
// helpers
sliceToPointer := func(p string) {
self.CgoBeforeStmt = ff("__header__$$name := (*reflect.SliceHeader)(unsafe.Pointer(&$$name))")
self.CgoParam = fs("(%s)(unsafe.Pointer(__header__%s.Data))", p, self.GoName)
}
switch spec {
// bool
case "bool -> C.gboolean":
self.CgoBeforeStmt = ff("__cgo__$$name := C.gboolean(0); if $$name { __cgo__$$name = C.gboolean(1)};")
self.CgoParam = ff("__cgo__$$name")
// char
case "byte -> C.char":
self.CgoParam = ff("C.char($$name)")
case "byte -> C.gchar":
self.CgoParam = ff("C.gchar($$name)")
case "rune -> C.gunichar":
self.CgoParam = ff("C.gunichar($$name)")
// string
case "string -> *C.char":
self.CgoBeforeStmt = ff("__cgo__$$name := C.CString($$name);")
self.CgoParam = ff("__cgo__$$name")
self.CgoAfterStmt += ff("C.free(unsafe.Pointer(__cgo__$$name));")
case "string -> *C.gchar":
self.CgoBeforeStmt = ff("__cgo__$$name := (*C.gchar)(unsafe.Pointer(C.CString($$name)));")
self.CgoParam = ff("__cgo__$$name")
self.CgoAfterStmt += ff("C.free(unsafe.Pointer(__cgo__$$name));")
// int
case "int -> C.gint":
self.CgoParam = ff("C.gint($$name)")
case "int -> C.int":
self.CgoParam = ff("C.int($$name)")
case "uint -> C.guint":
self.CgoParam = ff("C.guint($$name)")
case "uint -> C.uid_t":
self.CgoParam = ff("C.uid_t($$name)")
case "int8 -> C.gint8":
self.CgoParam = ff("C.gint8($$name)")
case "uint8 -> C.guint8":
self.CgoParam = ff("C.guint8($$name)")
case "uint8 -> C.guchar":
self.CgoParam = ff("C.guchar($$name)")
case "int16 -> C.gint16":
self.CgoParam = ff("C.gint16($$name)")
case "uint16 -> C.guint16":
self.CgoParam = ff("C.guint16($$name)")
case "int32 -> C.gint32":
self.CgoParam = ff("C.gint32($$name)")
case "uint32 -> C.guint32":
self.CgoParam = ff("C.guint32($$name)")
case "int64 -> C.gint64":
self.CgoParam = ff("C.gint64($$name)")
case "uint64 -> C.guint64":
self.CgoParam = ff("C.guint64($$name)")
case "uint64 -> C.gulong":
self.CgoParam = ff("C.gulong($$name)")
case "int64 -> C.glong":
self.CgoParam = ff("C.glong($$name)")
case "int64 -> C.gsize":
self.CgoParam = ff("C.gsize($$name)")
case "int64 -> C.gssize":
self.CgoParam = ff("C.gssize($$name)")
case "int64 -> C.gulong":
self.CgoParam = ff("C.gulong($$name)")
case "int64 -> C.goffset":
self.CgoParam = ff("C.goffset($$name)")
// float
case "float32 -> C.gfloat":
self.CgoParam = ff("C.gfloat($$name)")
case "float64 -> C.double":
self.CgoParam = ff("C.double($$name)")
case "float64 -> C.gdouble":
self.CgoParam = ff("C.gdouble($$name)")
// slice FIXME convert go string to c string first
case "[]byte -> *C.gchar":
sliceToPointer("*C.gchar")
case "[]byte -> *C.guchar":
sliceToPointer("*C.guchar")
case "[]byte -> *C.guint8":
sliceToPointer("*C.guint8")
case "[]string -> **C.gchar":
sliceToPointer("**C.gchar")
case "[]string -> **C.guchar":
sliceToPointer("**C.guchar")
case "[]string -> **C.char":
sliceToPointer("**C.char")
case "[]int -> *C.gint":
sliceToPointer("*C.gint")
case "[]uint8 -> *C.guint8":
sliceToPointer("*C.guint8")
case "[]byte -> unsafe.Pointer":
sliceToPointer("unsafe.Pointer")
// untyped pointer
case "unsafe.Pointer -> C.gpointer":
self.CgoParam = ff("(C.gpointer)($$name)")
case "unsafe.Pointer -> C.gconstpointer":
self.CgoParam = ff("(C.gconstpointer)($$name)")
default:
p("FIXME in param -> %s\n", spec)
}
}
}
var OutParamMapping = make(map[string]func(*Param))
func (self *Param) OutParamMarshal() {
if self.GoType == self.MappedType { // not mapped
self.CgoParam = "&" + self.GoName
} else { // mapped
self.CgoBeforeStmt = fs("var __cgo__%s %s", self.GoName, self.GoType)
self.CgoParam = "&__cgo__" + self.GoName
spec := fs("%s -> %s", self.GoType, self.MappedType)
if f, ok := OutParamMapping[spec]; ok {
f(self)
return
}
ff := func(s string) string {
return replace(s, map[string]string{
"name": self.GoName,
"len": self.LenParamName,
})
}
// check xml defined
if e, ok := self.Generator.OutParamMarshals[spec]; ok {
if e.Param != "" {
self.CgoParam = ff(e.Param)
}
if e.Before != "" {
self.CgoBeforeStmt += ff(e.Before)
}
if e.After != "" {
self.CgoAfterStmt += ff(e.After)
}
return
}
// helpers
pointerAndLenToSlice := `defer func() {
__header__$$name := (*reflect.SliceHeader)(unsafe.Pointer(&$$name))
__header__$$name.Len = int($$len)
__header__$$name.Cap = int($$len)
__header__$$name.Data = uintptr(unsafe.Pointer(__cgo__$$name))
}();`
switch spec {
// bool
case "C.gboolean -> bool":
self.CgoAfterStmt += ff("$$name = __cgo__$$name == C.gboolean(1);")
// byte
case "C.gchar -> byte":
self.CgoAfterStmt += ff("$$name = byte(__cgo__$$name);")
case "C.gunichar -> rune":
self.CgoAfterStmt += ff("$$name = rune(__cgo__$$name);")
// string
case "*C.gchar -> string",
"*C.guchar -> string":
self.CgoAfterStmt += ff("$$name = C.GoString((*C.char)(unsafe.Pointer(__cgo__$$name)));")
case "*C.char -> string":
self.CgoAfterStmt += ff("$$name = C.GoString(__cgo__$$name);")
// numeric
case "C.gint -> int",
"C.pid_t -> int",
"C.int -> int":
self.CgoAfterStmt += ff("$$name = int(__cgo__$$name);")
case "C.guint -> uint",
"C.uid_t -> uint":
self.CgoAfterStmt += ff("$$name = uint(__cgo__$$name);")
case "C.guint8 -> uint8",
"C.guchar -> uint8":
self.CgoAfterStmt += ff("$$name = uint8(__cgo__$$name);")
case "C.gint16 -> int16":
self.CgoAfterStmt += ff("$$name = int16(__cgo__$$name);")
case "C.guint16 -> uint16":
self.CgoAfterStmt += ff("$$name = uint16(__cgo__$$name);")
case "C.gint32 -> int32":
self.CgoAfterStmt += ff("$$name = int32(__cgo__$$name);")
case "C.guint32 -> uint32":
self.CgoAfterStmt += ff("$$name = uint32(__cgo__$$name);")
case "C.gsize -> int64",
"C.gint64 -> int64",
"C.gssize -> int64",
"C.goffset -> int64",
"C.glong -> int64":
self.CgoAfterStmt += ff("$$name = int64(__cgo__$$name);")
case "C.guint64 -> uint64",
"C.gulong -> uint64":
self.CgoAfterStmt += ff("$$name = uint64(__cgo__$$name);")
case "C.gfloat -> float32":
self.CgoAfterStmt += ff("$$name = float32(__cgo__$$name);")
case "C.double -> float64",
"C.gdouble -> float64":
self.CgoAfterStmt += ff("$$name = float64(__cgo__$$name);")
// bytes
case "*C.gchar -> []byte",
"*C.guchar -> []byte",
"*C.guint8 -> []byte",
"unsafe.Pointer -> []byte":
if self.LenParamName != "" { // len param
// defer is needed because length param may be later.
self.CgoAfterStmt += ff(`defer func() { $$name = C.GoBytes(unsafe.Pointer(__cgo__$$name), C.int($$len)) }();`)
} else {
p("no len param\n")
}
// string slice
case "**C.gchar -> []string":
self.CgoAfterStmt += ff(`var __slice__$$name []*C.gchar
__header__$$name := (*reflect.SliceHeader)(unsafe.Pointer(&__slice__$$name))
__header__$$name.Len = 4294967296
__header__$$name.Cap = 4294967296
__header__$$name.Data = uintptr(unsafe.Pointer(__cgo__$$name))
for _, p := range __slice__$$name {
if p == nil { break }
$$name = append($$name, C.GoString((*C.char)(unsafe.Pointer(p))))
};`)
// uint slice
case "*C.guint -> []uint",
"*C.gint -> []int":
self.CgoAfterStmt += ff(pointerAndLenToSlice)
// untyped pointer
case "C.gpointer -> unsafe.Pointer":
self.CgoAfterStmt += ff("$$name = unsafe.Pointer(__cgo__$$name);")
default:
p("FIXME out param -> %s\n", spec)
}
}
}