aboutsummaryrefslogtreecommitdiff
path: root/tests/tast2.nim
blob: f2816eb0e3722760db756f2b42da2f164c0fc921 (plain)
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
import macros, os, sets, strutils

import nimterop/[cimport]

static:
  cDebug()

const
  path = currentSourcePath.parentDir() / "include" / "tast2.h"

when defined(HEADER):
  cDefine("HEADER")
  const
    flags = " -H"
    pHeader = @["header:" & path.replace("\\", "/")]
    pHeaderImp = @["importc"] & pHeader
else:
  const
    flags = ""
    pHeader: seq[string] = @[]
    pHeaderImp: seq[string] = @[]

const
  pHeaderImpBy = @["bycopy"] & pHeaderImp
  pHeaderBy = @["bycopy"] & pHeader
  pHeaderInc = @["incompleteStruct"] & pHeader

cOverride:
  const
    A* = 2

  type
    A1* = A0

cImport(path, flags="-f:ast2 -ENK_" & 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): 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 defined(HEADER):
    if not istype:
      if "union" in exprag:
        exprag.incl "importc:union " & $t
      else:
        exprag.incl "importc:struct " & $t
  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())
        n = names.find(name)
      assert n != -1, $t & "." & name & " invalid"
      assert types[n] == typ,
        "typeof(" & $t & ":" & name & ") != " & types[n] & ", is " & typ

assert A == 2
assert B == 1.0
assert C == 0x10
assert D == "hello"
assert E == 'c'

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 not defined(HEADER):
  # 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 + 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.}
checkPragmas(pcre_malloc, @["importc", "cdecl"] & 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)