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
|
import macros, os, sets, strutils
import nimterop/[cimport]
static:
# Skip casting on lower nim compilers because
# the VM does not support it
when (NimMajor, NimMinor, NimPatch) < (1, 0, 0):
cSkipSymbol @["CASTEXPR"]
const
path = currentSourcePath.parentDir() / "include" / "tast2.h"
when defined(NOHEADER):
cDefine("NOHEADER")
const
flags = " -H"
pHeader: seq[string] = @[]
pHeaderImp: seq[string] = @[]
else:
const
flags = ""
pHeader = @["header:" & path.replace("\\", "/")]
pHeaderImp = @["importc"] & pHeader
const
pHeaderImpBy = @["bycopy"] & pHeaderImp
pHeaderBy = @["bycopy"] & pHeader
pHeaderInc = @["incompleteStruct"] & pHeader
cOverride:
const
A* = 2
type
A1* = A0
cImport(path, flags="-f:ast2 -ENK_,SDL_ -GVICE=SLICE -TMyInt=cint" & flags)
proc getPragmas(n: NimNode): HashSet[string] =
# Find all pragmas in AST, return as "name" or "name:value" in set
for i in 0 ..< n.len:
if n[i].kind == nnkPragma:
for j in 0 ..< n[i].len:
if n[i][j].kind == nnkIdent:
result.incl $n[i][j]
elif n[i][j].kind == nnkExprColonExpr:
result.incl $n[i][j][0] & ":" & $n[i][j][1]
else:
result.incl n[i].getPragmas()
proc getRecList(n: NimNode): NimNode =
# Find nnkRecList in AST
for i in 0 ..< n.len:
if n[i].kind == nnkRecList:
return n[i]
elif n[i].len != 0:
let
rl = getRecList(n[i])
if not rl.isNil:
return rl
macro checkPragmas(t: typed, pragmas: static[seq[string]], istype: static[bool] = true,
origname: static[string] = ""): untyped =
# Verify that type has expected pragmas defined
# `istype` is true when typedef X
var
ast = t.getImpl()
prag = ast.getPragmas()
exprag = pragmas.toHashSet()
when not defined(NOHEADER):
if not istype:
if "union" in exprag:
exprag.incl "importc:union " & $t
else:
exprag.incl "importc:struct " & $t
elif origname.len != 0:
exprag.incl "importc:" & $origname
doAssert symmetricDifference(prag, exprag).len == 0,
"\nWrong number of pragmas in " & $t & "\n" & $prag & " vs " & $exprag
macro testFields(t: typed, fields: static[string] = "") =
# Verify that type has expected fields
var
ast = t.getImpl()
rl = ast.getRecList()
fsplit = fields.split("!")
names = fsplit[0].split("|")
types =
if fsplit.len > 1:
fsplit[1].split("|")
else:
@[]
if not rl.isNil:
for i in 0 ..< rl.len:
let
name = ($rl[i][0]).strip(chars = {'*'})
typ = ($(rl[i][1].repr())).replace("\n", "").replace(" ", "").replace("typeof", "type")
n = names.find(name)
assert n != -1, $t & "." & name & " invalid"
assert types[n].replace("typeof", "type") == typ,
"typeof(" & $t & ":" & name & ") != " & types[n].replace("typeof", "type") & ", is " & typ
assert A == 2
assert B == 1.0
assert C == 0x10
assert D == "hello"
assert E == 'c'
assert not defined(NOTSUPPORTEDSTR)
assert UEXPR == (1234.uint shl 1)
assert ULEXPR == (1234.uint32 shl 2)
assert ULLEXPR == (1234.uint64 shl 3)
assert LEXPR == (1234.int32 shl 4)
assert LLEXPR == (1234.int64 shl 5)
assert AVAL == 100
assert BVAL == 200
assert EQ1 == (AVAL <= BVAL)
assert EQ2 == (AVAL >= BVAL)
assert EQ3 == (AVAL > BVAL)
assert EQ4 == (AVAL < BVAL)
assert EQ5 == (AVAL != BVAL)
assert EQ6 == (AVAL == BVAL)
assert SIZEOF == 1
assert COERCE == 645635670332'u64
assert COERCE2 == 645635670332'i64
assert INT_FAST16_MIN == -9223372036854775807'i64 - 1
assert BINEXPR == 5
assert BOOL == true
assert MATHEXPR == -99
assert ANDEXPR == 96
when (NimMajor, NimMinor, NimPatch) >= (1, 0, 0):
assert CASTEXPR == 34.chr
assert TRICKYSTR == "N\x1C\nfoo\x00\'\"\c\v\a\b\e\f\t\\\\?bar"
assert NULLCHAR == '\0'
assert OCTCHAR == '\n'
assert HEXCHAR.int == 0xFE
assert SHL1 == (1.uint shl 1)
assert SHL2 == (1.uint shl 2)
assert SHL3 == (1.uint shl 3)
assert typeof(POINTEREXPR) is (ptr cint)
assert typeof(POINTERPOINTERPOINTEREXPR) is (ptr ptr ptr cint)
assert ALLSHL == (SHL1 or SHL2 or SHL3)
assert A0 is object
testFields(A0, "f1!cint")
checkPragmas(A0, pHeaderBy, istype = false)
var a0: A0
a0.f1 = 1
assert A1 is A0
testFields(A1, "f1!cint")
var a1: A1
a1.f1 = 2
assert A2 is object
testFields(A2)
checkPragmas(A2, pHeaderInc, istype = false)
when defined(NOHEADER):
# typedef struct X; is invalid
var a2: A2
assert A3 is object
testFields(A3)
checkPragmas(A3, pHeaderInc, istype = false)
var a3: A3
assert A4 is object
testFields(A4, "f1!cfloat")
checkPragmas(A4, pHeaderImpBy)
var a4: A4
a4.f1 = 4.1
assert A4p is ptr A4
testFields(A4p, "f1!cfloat")
checkPragmas(A4p, pHeaderImp)
var a4p: A4p
a4p = addr a4
assert A5 is cint
checkPragmas(A5, pHeaderImp)
const a5: A5 = 5
assert A6 is ptr cint
checkPragmas(A6, pHeaderImp)
var
a6: A6
a6i = 6
a6 = cast[A6](addr a6i)
assert A7 is ptr ptr A0
checkPragmas(A7, pHeaderImp)
var
a7: A7
a7a = addr a0
a7 = addr a7a
assert A8 is pointer
checkPragmas(A8, pHeaderImp)
var a8: A8
a8 = nil
assert A9p is array[3, cstring]
checkPragmas(A9p, pHeaderImp)
var a9p: A9p
a9p[1] = nil
a9p[2] = "hello".cstring
assert A9 is array[4, cchar]
checkPragmas(A9, pHeaderImp)
var a9: A9
a9[2] = 'c'
assert A10 is array[3, array[6, cstring]]
checkPragmas(A10, pHeaderImp)
var a10: A10
a10[2][5] = "12345".cstring
assert A11 is ptr array[3, cstring]
checkPragmas(A11, pHeaderImp)
var a11: A11
a11 = addr a9p
assert A111 is array[12, ptr A1]
checkPragmas(A111, pHeaderImp)
var a111: A111
a111[11] = addr a0
assert A12 is proc(a1: cint, b: cint, c: ptr cint, a4: ptr cint, count: array[4, ptr cint], `func`: proc(a1: cint, a2: cint): cint {.cdecl.}): ptr ptr cint {.cdecl.}
checkPragmas(A12, pHeaderImp & "cdecl")
var a12: A12
assert A121 is proc(a1: cfloat, b: cfloat, c: ptr cfloat, a4: ptr cfloat, count: array[4, ptr cfloat], `func`: proc(a1: cfloat, a2: cfloat): cfloat {.cdecl.}): ptr ptr cint {.cdecl.}
checkPragmas(A121, pHeaderImp & "cdecl")
var a121: A121
assert A122 is proc(a1: cchar, b: cchar, c: cstring, a4: cstring, count: array[4, cstring], `func`: proc(a1: cchar, a2: cchar): cchar {.cdecl.}): ptr ptr cint {.cdecl.}
checkPragmas(A122, pHeaderImp & "cdecl")
var a122: A122
assert A13 is proc(a1: cint, a2: cint, `func`: proc() {.cdecl.}): cint {.cdecl.}
checkPragmas(A13, pHeaderImp & "cdecl")
var a13: A13
assert A14 is object
testFields(A14, "a1!cchar")
checkPragmas(A14, pHeaderBy, istype = false)
var a14: A14
a14.a1 = 'a'
assert A15 is object
testFields(A15, "a1|a2!cstring|array[1, ptr cint]")
checkPragmas(A15, pHeaderBy, istype = false)
var
a15: A15
a15i = 15.cint
a15.a1 = "hello".cstring
a15.a2[0] = addr a15i
assert A16 is object
testFields(A16, "f1!cchar")
checkPragmas(A16, pHeaderBy, istype = false)
var a16: A16
a16.f1 = 's'
assert A17 is object
testFields(A17, "a1|a2!cstring|array[1, ptr cint]")
checkPragmas(A17, pHeaderBy, istype = false)
var a17: A17
a17.a1 = "hello".cstring
a17.a2[0] = addr a15i
assert A18 is A17
checkPragmas(A18, pHeaderImp)
var a18: A18
assert A18p is ptr A17
checkPragmas(A18p, pHeaderImp)
var a18p: A18p
a18p = addr a18
assert A19 is object
testFields(A19, "a1|a2!cstring|array[1, ptr cint]")
checkPragmas(A19, pHeaderImpBy)
var a19: A19
a19.a1 = "hello".cstring
a19.a2[0] = addr a15i
assert A19p is ptr A19
checkPragmas(A19p, pHeaderImp)
var a19p: A19p
a19p = addr a19
assert A20 is object
testFields(A20, "a1!cchar")
checkPragmas(A20, pHeaderBy, istype = false)
var a20: A20
a20.a1 = 'a'
assert A21 is A20
checkPragmas(A21, pHeaderImp)
var a21: A21
a21 = a20
assert A21p is ptr A20
checkPragmas(A21p, pHeaderImp)
var a21p: A21p
a21p = addr a20
assert A22 is object
testFields(A22, "f1|f2!ptr ptr cint|array[123 + type(123)(132), ptr cint]")
checkPragmas(A22, pHeaderBy, istype = false)
var a22: A22
a22.f1 = addr a15.a2[0]
assert U1 is object
assert sizeof(U1) == sizeof(cfloat)
checkPragmas(U1, pHeaderBy & @["union"], istype = false)
var u1: U1
u1.f1 = 5
assert U2 is object
assert sizeof(U2) == 256 * sizeof(cint)
checkPragmas(U2, pHeaderBy & @["union"], istype = false)
var u2: U2
u2.f1 = addr a15.a2[0]
assert PANEL_WINDOW == 1
assert PANEL_GROUP == 2
assert PANEL_POPUP == 4
assert PANEL_CONTEXTUAL == 16
assert PANEL_COMBO == 32
assert PANEL_MENU == 64
assert PANEL_TOOLTIP == 128
assert PANEL_SET_NONBLOCK == 240
assert PANEL_SET_POPUP == 244
assert PANEL_SET_SUB == 246
assert cmGray == 1000000
assert pfGray16 == 1000011
assert pfYUV422P8 == pfYUV420P8 + 1
assert pfRGB27 == cmRGB.VSPresetFormat + 11
assert pfCompatYUY2 == pfCompatBGR32 + 1
assert pcre_malloc is proc(a1: uint): pointer {.cdecl, varargs.}
checkPragmas(pcre_malloc, @["importc", "cdecl", "varargs"] & pHeader)
assert pcre_free is proc(a1: pointer) {.cdecl.}
checkPragmas(pcre_free, @["importc", "cdecl"] & pHeader)
assert pcre_stack_malloc is proc(a1: uint): pointer {.cdecl.}
checkPragmas(pcre_stack_malloc, @["importc", "cdecl"] & pHeader)
assert DuplexTransferImageViewMethod is
proc (a1: ptr ImageView; a2: ptr ImageView; a3: ptr ImageView; a4: uint;
a5: cint; a6: pointer): MagickBooleanType {.cdecl.}
assert GetImageViewMethod is
proc (a1: ptr ImageView; a2: uint; a3: cint; a4: pointer): MagickBooleanType {.cdecl.}
assert SetImageViewMethod is
proc (a1: ptr ImageView; a2: uint; a3: cint; a4: pointer): MagickBooleanType {.cdecl.}
assert TransferImageViewMethod is
proc (a1: ptr ImageView; a2: ptr ImageView; a3: uint; a4: cint; a5: pointer): MagickBooleanType {.cdecl.}
assert UpdateImageViewMethod is
proc (a1: ptr ImageView; a2: uint; a3: cint; a4: pointer): MagickBooleanType {.cdecl.}
# Issue #156, math.h
assert absfunptr1 is proc(a1: proc(a1: ptr A0): cint {.cdecl.}): pointer {.cdecl.}
assert absfunptr2 is proc(a1: ptr proc(a1: ptr A1): cint {.cdecl.}): ptr pointer {.cdecl.}
assert absfunptr3 is proc(a1: proc(a1: ptr A2): ptr cint {.cdecl.}) {.cdecl.}
assert absfunptr4 is proc(a1: ptr proc(a1: ptr A3): ptr cint {.cdecl.}): pointer {.cdecl.}
assert absfunptr5 is proc(a1: proc(a1: ptr A4): cint {.cdecl.}) {.cdecl.}
assert sqlite3_bind_blob is
proc(a1: ptr A1, a2: cint, a3: pointer, n: cint, a5: proc(a1: pointer) {.cdecl.}): cint {.cdecl.}
# Issue #174 - type name[] => UncheckedArray[type]
assert ucArrFunc1 is proc(text: UncheckedArray[cint]): cint {.cdecl.}
assert ucArrFunc2 is
proc(text: UncheckedArray[array[5, cint]], `func`: proc(text: UncheckedArray[cint]): cint {.cdecl.}): cint {.cdecl.}
assert ucArrType1 is UncheckedArray[array[5, cint]]
checkPragmas(ucArrType1, pHeaderImp)
assert ucArrType2 is object
testFields(ucArrType2, "f1|f2!array[5, array[5, cfloat]]|UncheckedArray[array[5, ptr cint]]")
checkPragmas(ucArrType2, pHeaderBy, istype = false)
assert fieldfuncfunc is object
testFields(fieldfuncfunc,
"func1!proc (f1: cint; sfunc1: proc (f1: cint; ssfunc1: proc (f1: cint): ptr cint {.cdecl, varargs.}): ptr cint {.cdecl.}): ptr cint {.cdecl.}")
assert func2 is proc (f1: cint; sfunc2: proc (f1: cint; ssfunc2: proc (f1: cint): ptr cint {.cdecl.}): ptr cint {.cdecl.}): ptr cint {.cdecl.}
# Test --replace VICE=SLICE
assert BASS_DESLICEINFO is object
testFields(BASS_DESLICEINFO, "name|driver|flags!cstring|cstring|cint")
checkPragmas(BASS_DESLICEINFO, pHeaderBy, origname = "BASS_DEVICEINFO")
# Issue #183
assert GPU_Target is object
testFields(GPU_Target, "w|h|x|y|z!cint|ptr cint|cstring|cchar|ptr cstring")
checkPragmas(GPU_Target, pHeaderBy, istype = false)
# Issue #185
assert AudioCVT is object
testFields(AudioCVT, "needed!cint")
checkPragmas(AudioCVT, pHeaderBy, origname = "struct SDL_AudioCVT")
# Issue #172
assert SomeType is object
testFields(SomeType, "x!ptr cstring")
checkPragmas(SomeType, pHeaderImpBy)
# Nested #137
assert NT1 is object
testFields(NT1, "f1!cint")
checkPragmas(NT1, pHeaderBy, istype = false)
assert Type_tast2h1 is object
testFields(Type_tast2h1, "f1!cint")
checkPragmas(Type_tast2h1, pHeaderBy, istype = false)
assert NU1 is object
testFields(NU1, "f1!cfloat")
checkPragmas(NU1, pHeaderBy & @["union"], istype = false)
assert NEV1 == 0
assert NEV2 == 1
assert NEV3 == 2
assert Type_tast2h2 is object
testFields(Type_tast2h2, "f1|f2|f3!cint|NU1|Enum_tast2h1")
checkPragmas(Type_tast2h2, pHeaderBy, istype = false)
assert NT3 is object
testFields(NT3, "f1!Type_tast2h2")
checkPragmas(NT3, pHeaderBy, istype = false)
assert Type_tast2h3 is object
testFields(Type_tast2h3, "f1!cint")
checkPragmas(Type_tast2h3, pHeaderBy, istype = false)
assert NU2 is object
testFields(NU2, "f1!cint")
checkPragmas(NU2, pHeaderBy & @["union"], istype = false)
assert Union_tast2h1 is object
testFields(Union_tast2h1, "f1!cint")
checkPragmas(Union_tast2h1, pHeaderBy & @["union"], istype = false)
assert NEV4 == 8
assert NEV5 == 9
assert NEV6 == 64
assert NEV7 == 65
assert nested is object
testFields(nested, "f1|f2|f3|f4|f5|f6|f7|f8!NT1|Type_tast2h1|NT3|Type_tast2h3|NU2|Union_tast2h1|NE1|Enum_tast2h2")
checkPragmas(nested, pHeaderImpBy)
when not defined(NOHEADER):
assert sitest1(5) == 10
assert sitest1(10) == 20
when declared(MyInt):
assert false, "MyInt is defined!"
testFields(TestMyInt, "f1!cint")
checkPragmas(TestMyInt, pHeaderBy, isType = false)
|