gen_nim.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. #-------------------------------------------------------------------------------
  2. # Generate Nim bindings
  3. #
  4. # Nim coding style:
  5. # - type identifiers are PascalCase, everything else is camelCase
  6. # - reference: https://nim-lang.org/docs/nep1.html
  7. #-------------------------------------------------------------------------------
  8. import gen_ir
  9. import gen_util as util
  10. import os, shutil, sys
  11. module_names = {
  12. 'slog_': 'log',
  13. 'sg_': 'gfx',
  14. 'sapp_': 'app',
  15. 'stm_': 'time',
  16. 'saudio_': 'audio',
  17. 'sgl_': 'gl',
  18. 'sdtx_': 'debugtext',
  19. 'sshape_': 'shape',
  20. 'sglue_': 'glue',
  21. }
  22. c_source_paths = {
  23. 'slog_': 'sokol-nim/src/sokol/c/sokol_log.c',
  24. 'sg_': 'sokol-nim/src/sokol/c/sokol_gfx.c',
  25. 'sapp_': 'sokol-nim/src/sokol/c/sokol_app.c',
  26. 'stm_': 'sokol-nim/src/sokol/c/sokol_time.c',
  27. 'saudio_': 'sokol-nim/src/sokol/c/sokol_audio.c',
  28. 'sgl_': 'sokol-nim/src/sokol/c/sokol_gl.c',
  29. 'sdtx_': 'sokol-nim/src/sokol/c/sokol_debugtext.c',
  30. 'sshape_': 'sokol-nim/src/sokol/c/sokol_shape.c',
  31. 'sglue_': 'sokol-nim/src/sokol/c/sokol_glue.c',
  32. }
  33. c_callbacks = [
  34. 'slog_func',
  35. ]
  36. ignores = [
  37. 'sdtx_printf',
  38. 'sdtx_vprintf',
  39. ]
  40. overrides = {
  41. 'sgl_error': 'sgl_get_error',
  42. 'sgl_deg': 'sgl_as_degrees',
  43. 'sgl_rad': 'sgl_as_radians',
  44. 'SGL_NO_ERROR': 'SGL_ERROR_NO_ERROR',
  45. 'SG_BUFFERTYPE_VERTEXBUFFER': 'SG_BUFFERTYPE_VERTEX_BUFFER',
  46. 'SG_BUFFERTYPE_INDEXBUFFER': 'SG_BUFFERTYPE_INDEX_BUFFER',
  47. 'SG_ACTION_DONTCARE': 'SG_ACTION_DONT_CARE',
  48. 'ptr': 'addr', # range ptr
  49. 'func': 'fn',
  50. 'slog_func': 'fn',
  51. }
  52. enumPrefixOverrides = {
  53. # sokol_gfx.h
  54. 'LOADACTION': 'loadAction',
  55. 'STOREACTION': 'storeAction',
  56. 'PIXELFORMAT': 'pixelFormat',
  57. 'RESOURCESTATE': 'resourceState',
  58. 'BUFFERTYPE': 'bufferType',
  59. 'INDEXTYPE': 'indexType',
  60. 'IMAGETYPE': 'imageType',
  61. 'SAMPLERTYPE': 'samplerType',
  62. 'CUBEFACE': 'cubeFace',
  63. 'SHADERSTAGE': 'shaderStage',
  64. 'PRIMITIVETYPE': 'primitiveType',
  65. 'BORDERCOLOR': 'borderColor',
  66. 'VERTEXFORMAT': 'vertexFormat',
  67. 'VERTEXSTEP': 'vertexStep',
  68. 'UNIFORMTYPE': 'uniformType',
  69. 'UNIFORMLAYOUT': 'uniformLayout',
  70. 'CULLMODE': 'cullMode',
  71. 'FACEWINDING': 'faceWinding',
  72. 'COMPAREFUNC': 'compareFunc',
  73. 'STENCILOP': 'stencilOp',
  74. 'BLENDFACTOR': 'blendFactor',
  75. 'BLENDOP': 'blendOp',
  76. 'COLORMASK': 'colorMask',
  77. # sokol_app.h
  78. 'EVENTTYPE': 'eventType',
  79. 'KEYCODE': 'keyCode',
  80. 'MOUSEBUTTON': 'mouseButton',
  81. }
  82. prim_types = {
  83. 'int': 'int32',
  84. 'bool': 'bool',
  85. 'char': 'char',
  86. 'int8_t': 'int8',
  87. 'uint8_t': 'uint8',
  88. 'int16_t': 'int16',
  89. 'uint16_t': 'uint16',
  90. 'int32_t': 'int32',
  91. 'uint32_t': 'uint32',
  92. 'int64_t': 'int64',
  93. 'uint64_t': 'uint64',
  94. 'float': 'float32',
  95. 'double': 'float64',
  96. 'uintptr_t': 'uint',
  97. 'intptr_t': 'int',
  98. 'size_t': 'int', # not a bug, Nim's sizeof() returns int
  99. }
  100. prim_defaults = {
  101. 'int': '0',
  102. 'bool': 'false',
  103. 'int8_t': '0',
  104. 'uint8_t': '0',
  105. 'int16_t': '0',
  106. 'uint16_t': '0',
  107. 'int32_t': '0',
  108. 'uint32_t': '0',
  109. 'int64_t': '0',
  110. 'uint64_t': '0',
  111. 'float': '0.0f',
  112. 'double': '0.0',
  113. 'uintptr_t': '0',
  114. 'intptr_t': '0',
  115. 'size_t': '0'
  116. }
  117. common_prim_types = """
  118. array
  119. untyped typed void
  120. bool byte char
  121. int int8 int16 int32 int64
  122. uint uint8 uint16 uint32 uint64
  123. float float32 float64
  124. string
  125. cchar cint csize_t
  126. cfloat cdouble
  127. cstring
  128. pointer
  129. """.split()
  130. keywords = """
  131. addr and as asm
  132. bind block break
  133. case cast concept const continue converter
  134. defer discard distinct div do
  135. elif else end enum except export
  136. finally for from func
  137. if import in include interface is isnot iterator
  138. let
  139. macro method mixin mod
  140. nil not notin
  141. object of or out
  142. proc ptr
  143. raise ref return
  144. shl shr static
  145. template try tuple type
  146. using
  147. var
  148. when while
  149. xor
  150. yield
  151. """.split() + common_prim_types
  152. struct_types = []
  153. enum_types = []
  154. out_lines = ''
  155. def reset_globals():
  156. global struct_types
  157. global enum_types
  158. global out_lines
  159. struct_types = []
  160. enum_types = []
  161. out_lines = ''
  162. def l(s):
  163. global out_lines
  164. out_lines += s + '\n'
  165. def as_nim_prim_type(s):
  166. return prim_types[s]
  167. # prefix_bla_blub(_t) => (dep.)BlaBlub
  168. def as_nim_type_name(s, prefix):
  169. parts = s.lower().split('_')
  170. dep = parts[0] + '_'
  171. outp = ''
  172. if not s.startswith(prefix) and dep in module_names:
  173. outp = module_names[dep] + '.'
  174. for part in parts[1:]:
  175. # ignore '_t' type postfix
  176. if (part != 't'):
  177. outp += part.capitalize()
  178. return outp
  179. def check_override(name, default=None):
  180. if name in overrides:
  181. return overrides[name]
  182. elif default is None:
  183. return name
  184. else:
  185. return default
  186. def check_ignore(name):
  187. return name in ignores
  188. def is_power_of_two(val):
  189. return val == 0 or val & (val - 1) == 0
  190. def wrap_keywords(s):
  191. if s in keywords:
  192. return f'`{s}`'
  193. else:
  194. return s
  195. # prefix_bla_blub => blaBlub
  196. def as_camel_case(s, prefix, wrap=True):
  197. outp = s.lower()
  198. if outp.startswith(prefix):
  199. outp = outp[len(prefix):]
  200. parts = outp.lstrip('_').split('_')
  201. outp = parts[0]
  202. for part in parts[1:]:
  203. outp += part.capitalize()
  204. if wrap:
  205. outp = wrap_keywords(outp)
  206. return outp
  207. # PREFIX_ENUM_BLA_BLO => blaBlo
  208. def as_enum_item_name(s, wrap=True):
  209. outp = s.lstrip('_')
  210. parts = outp.split('_')[1:]
  211. if parts[0] in enumPrefixOverrides:
  212. parts[0] = enumPrefixOverrides[parts[0]]
  213. else:
  214. parts[0] = parts[0].lower()
  215. outp = parts[0]
  216. for part in parts[1:]:
  217. outp += part.capitalize()
  218. if wrap:
  219. outp = wrap_keywords(outp)
  220. return outp
  221. def is_prim_type(s):
  222. return s in prim_types
  223. def is_struct_type(s):
  224. return s in struct_types
  225. def is_enum_type(s):
  226. return s in enum_types
  227. def is_const_prim_ptr(s):
  228. for prim_type in prim_types:
  229. if s == f"const {prim_type} *":
  230. return True
  231. return False
  232. def is_prim_ptr(s):
  233. for prim_type in prim_types:
  234. if s == f"{prim_type} *":
  235. return True
  236. return False
  237. def is_const_struct_ptr(s):
  238. for struct_type in struct_types:
  239. if s == f"const {struct_type} *":
  240. return True
  241. return False
  242. def type_default_value(s):
  243. return prim_defaults[s]
  244. def funcptr_args(field_type, prefix):
  245. tokens = field_type[field_type.index('(*)')+4:-1].split(',')
  246. s = ""
  247. n = 0
  248. for token in tokens:
  249. n += 1
  250. arg_ctype = token.strip()
  251. if s != "":
  252. s += ", "
  253. arg_nimtype = as_nim_type(arg_ctype, prefix)
  254. if arg_nimtype == "":
  255. return "" # fun(void)
  256. s += f"a{n}:{arg_nimtype}"
  257. if s == "a1:void":
  258. s = ""
  259. return s
  260. def funcptr_result(field_type, prefix):
  261. ctype = field_type[:field_type.index('(*)')].strip()
  262. return as_nim_type(ctype, prefix)
  263. def as_nim_type(ctype, prefix, struct_ptr_as_value=False):
  264. if ctype == "void":
  265. return ""
  266. elif is_prim_type(ctype):
  267. return as_nim_prim_type(ctype)
  268. elif is_struct_type(ctype):
  269. return as_nim_type_name(ctype, prefix)
  270. elif is_enum_type(ctype):
  271. return as_nim_type_name(ctype, prefix)
  272. elif util.is_string_ptr(ctype):
  273. return "cstring"
  274. elif util.is_void_ptr(ctype) or util.is_const_void_ptr(ctype):
  275. return "pointer"
  276. elif is_const_struct_ptr(ctype):
  277. nim_type = as_nim_type(util.extract_ptr_type(ctype), prefix)
  278. if struct_ptr_as_value:
  279. return f"{nim_type}"
  280. else:
  281. return f"ptr {nim_type}"
  282. elif is_prim_ptr(ctype) or is_const_prim_ptr(ctype):
  283. return f"ptr {as_nim_type(util.extract_ptr_type(ctype), prefix)}"
  284. elif util.is_func_ptr(ctype):
  285. args = funcptr_args(ctype, prefix)
  286. res = funcptr_result(ctype, prefix)
  287. if res != "":
  288. res = ":" + res
  289. return f"proc({args}){res} {{.cdecl.}}"
  290. elif util.is_1d_array_type(ctype):
  291. array_ctype = util.extract_array_type(ctype)
  292. array_sizes = util.extract_array_sizes(ctype)
  293. return f'array[{array_sizes[0]}, {as_nim_type(array_ctype, prefix)}]'
  294. elif util.is_2d_array_type(ctype):
  295. array_ctype = util.extract_array_type(ctype)
  296. array_sizes = util.extract_array_sizes(ctype)
  297. return f'array[{array_sizes[0]}, array[{array_sizes[1]}, {as_nim_type(array_ctype, prefix)}]]'
  298. else:
  299. sys.exit(f"ERROR as_nim_type: {ctype}")
  300. def as_nim_struct_name(struct_decl, prefix):
  301. struct_name = check_override(struct_decl['name'])
  302. nim_type = f'{as_nim_type_name(struct_name, prefix)}'
  303. return nim_type
  304. def as_nim_field_name(field_decl, prefix, check_private=True):
  305. field_name = as_camel_case(check_override(field_decl['name']), prefix)
  306. if check_private:
  307. is_private = field_decl['name'].startswith('_')
  308. if not is_private:
  309. field_name += "*"
  310. return field_name
  311. def as_nim_field_type(struct_decl, field_decl, prefix):
  312. return as_nim_type(check_override(f"{struct_decl['name']}.{field_decl['name']}", default=field_decl['type']), prefix)
  313. def gen_struct(decl, prefix):
  314. l(f"type {as_nim_struct_name(decl, prefix)}* = object")
  315. for field in decl['fields']:
  316. l(f" {as_nim_field_name(field, prefix)}:{as_nim_field_type(decl, field, prefix)}")
  317. l("")
  318. def gen_consts(decl, prefix):
  319. l("const")
  320. for item in decl['items']:
  321. item_name = check_override(item['name'])
  322. l(f" {as_camel_case(item_name, prefix)}* = {item['value']}")
  323. l("")
  324. def gen_enum(decl, prefix):
  325. item_names_by_value = {}
  326. value = -1
  327. has_explicit_values = False
  328. for item in decl['items']:
  329. item_name = check_override(item['name'])
  330. if item_name.endswith("_NUM") or item_name.endswith("_FORCE_U32"):
  331. continue
  332. else:
  333. if 'value' in item:
  334. has_explicit_values = True
  335. value = int(item['value'])
  336. else:
  337. value += 1
  338. item_names_by_value[value] = as_enum_item_name(item_name)
  339. enum_name_nim = as_nim_type_name(decl['name'], prefix)
  340. l('type')
  341. l(f" {enum_name_nim}* {{.size:sizeof(int32).}} = enum")
  342. if has_explicit_values:
  343. # Nim requires explicit enum values to be declared in ascending order
  344. for value in sorted(item_names_by_value):
  345. name = item_names_by_value[value]
  346. l(f" {name} = {value},")
  347. else:
  348. for name in item_names_by_value.values():
  349. l(f" {name},")
  350. l("")
  351. # returns C prototype compatible function args (with pointers)
  352. def funcdecl_args_c(decl, prefix):
  353. s = ""
  354. func_name = decl['name']
  355. for param_decl in decl['params']:
  356. if s != "":
  357. s += ", "
  358. arg_name = param_decl['name']
  359. arg_type = check_override(f'{func_name}.{arg_name}', default=param_decl['type'])
  360. s += f"{as_camel_case(arg_name, prefix)}:{as_nim_type(arg_type, prefix)}"
  361. return s
  362. # returns Nim function args (pass structs by value)
  363. def funcdecl_args_nim(decl, prefix):
  364. s = ""
  365. func_name = decl['name']
  366. for param_decl in decl['params']:
  367. if s != "":
  368. s += ", "
  369. arg_name = param_decl['name']
  370. arg_type = check_override(f'{func_name}.{arg_name}', default=param_decl['type'])
  371. s += f"{as_camel_case(arg_name, prefix)}:{as_nim_type(arg_type, prefix, struct_ptr_as_value=True)}"
  372. return s
  373. def funcdecl_result(decl, prefix):
  374. func_name = decl['name']
  375. decl_type = decl['type']
  376. result_type = check_override(f'{func_name}.RESULT', default=decl_type[:decl_type.index('(')].strip())
  377. nim_res_type = as_nim_type(result_type, prefix)
  378. if nim_res_type == "":
  379. nim_res_type = "void"
  380. return nim_res_type
  381. def gen_func_nim(decl, prefix):
  382. c_func_name = decl['name']
  383. nim_func_name = as_camel_case(check_override(c_func_name), prefix, wrap=False)
  384. nim_res_type = funcdecl_result(decl, prefix)
  385. if c_func_name in c_callbacks:
  386. l(f"proc {nim_func_name}*({funcdecl_args_c(decl, prefix)}):{nim_res_type} {{.cdecl, importc:\"{c_func_name}\".}}")
  387. else:
  388. l(f"proc c_{nim_func_name}({funcdecl_args_c(decl, prefix)}):{nim_res_type} {{.cdecl, importc:\"{c_func_name}\".}}")
  389. l(f"proc {wrap_keywords(nim_func_name)}*({funcdecl_args_nim(decl, prefix)}):{nim_res_type} =")
  390. s = f" c_{nim_func_name}("
  391. for i, param_decl in enumerate(decl['params']):
  392. if i > 0:
  393. s += ", "
  394. arg_name = param_decl['name']
  395. arg_type = param_decl['type']
  396. if is_const_struct_ptr(arg_type):
  397. s += f"addr({arg_name})"
  398. else:
  399. s += arg_name
  400. s += ")"
  401. l(s)
  402. l("")
  403. def gen_array_converters(decl, prefix):
  404. for field in decl['fields']:
  405. if util.is_array_type(field['type']):
  406. array_type = util.extract_array_type(field['type'])
  407. array_sizes = util.extract_array_sizes(field['type'])
  408. struct_name = as_nim_struct_name(decl, prefix)
  409. field_name = as_nim_field_name(field, prefix, check_private=False)
  410. array_base_type = as_nim_type(array_type, prefix)
  411. if util.is_1d_array_type(field['type']):
  412. n = array_sizes[0]
  413. l(f'converter to{struct_name}{field_name}*[N:static[int]](items: array[N, {array_base_type}]): array[{n}, {array_base_type}] =')
  414. l(f' static: assert(N <= {n})')
  415. l(f' for index,item in items.pairs: result[index]=item')
  416. l('')
  417. elif util.is_2d_array_type(field['type']):
  418. x = array_sizes[1]
  419. y = array_sizes[0]
  420. l(f'converter to{struct_name}{field_name}*[Y:static[int], X:static[int]](items: array[Y, array[X, {array_base_type}]]): array[{y}, array[{x}, {array_base_type}]] =')
  421. l(f' static: assert(X <= {x})')
  422. l(f' static: assert(Y <= {y})')
  423. l(f' for indexY,itemY in items.pairs:')
  424. l(f' for indexX, itemX in itemY.pairs:')
  425. l(f' result[indexY][indexX] = itemX')
  426. l('')
  427. else:
  428. sys.exit('Unsupported converter array dimension (> 2)!')
  429. def pre_parse(inp):
  430. global struct_types
  431. global enum_types
  432. for decl in inp['decls']:
  433. kind = decl['kind']
  434. if kind == 'struct':
  435. struct_types.append(decl['name'])
  436. elif kind == 'enum':
  437. enum_name = decl['name']
  438. enum_types.append(enum_name)
  439. def gen_imports(inp, dep_prefixes):
  440. for dep_prefix in dep_prefixes:
  441. dep_module_name = module_names[dep_prefix]
  442. l(f'import {dep_module_name}')
  443. l('')
  444. def gen_extra(inp):
  445. if inp['prefix'] in ['sg_']:
  446. # FIXME: remove when sokol-shdc has been integrated!
  447. l('when defined emscripten:')
  448. l(' const gl* = true')
  449. l(' const d3d11* = false')
  450. l(' const metal* = false')
  451. l(' const emscripten* = true')
  452. l('elif defined gl:')
  453. l(' const gl* = true')
  454. l(' const d3d11* = false')
  455. l(' const metal* = false')
  456. l(' const emscripten* = false')
  457. l('elif defined windows:')
  458. l(' const gl* = false')
  459. l(' const d3d11* = true')
  460. l(' const metal* = false')
  461. l(' const emscripten* = false')
  462. l('elif defined macosx:')
  463. l(' const gl* = false')
  464. l(' const d3d11* = false')
  465. l(' const metal* = true')
  466. l(' const emscripten* = false')
  467. l('elif defined linux:')
  468. l(' const gl* = true')
  469. l(' const d3d11* = false')
  470. l(' const metal* = false')
  471. l(' const emscripten* = false')
  472. l('else:')
  473. l(' error("unsupported platform")')
  474. l('')
  475. if inp['prefix'] in ['sg_', 'sapp_']:
  476. l('when defined emscripten:')
  477. l(' {.passl:"-lGL -ldl".}')
  478. l(' {.passc:"-DSOKOL_GLES3".}')
  479. l(' {.passL: "-s MIN_WEBGL_VERSION=2 -s MAX_WEBGL_VERSION=2".}')
  480. l('elif defined windows:')
  481. l(' when not defined vcc:')
  482. l(' {.passl:"-lkernel32 -luser32 -lshell32 -lgdi32".}')
  483. l(' when defined gl:')
  484. l(' {.passc:"-DSOKOL_GLCORE".}')
  485. l(' else:')
  486. l(' {.passc:"-DSOKOL_D3D11".}')
  487. l(' when not defined vcc:')
  488. l(' {.passl:"-ld3d11 -ldxgi".}')
  489. l('elif defined macosx:')
  490. l(' {.passc:"-x objective-c".}')
  491. l(' {.passl:"-framework Cocoa -framework QuartzCore".}')
  492. l(' when defined gl:')
  493. l(' {.passc:"-DSOKOL_GLCORE".}')
  494. l(' {.passl:"-framework OpenGL".}')
  495. l(' else:')
  496. l(' {.passc:"-DSOKOL_METAL".}')
  497. l(' {.passl:"-framework Metal -framework MetalKit".}')
  498. l('elif defined linux:')
  499. l(' {.passc:"-DSOKOL_GLCORE".}')
  500. l(' {.passl:"-lX11 -lXi -lXcursor -lGL -lm -ldl -lpthread".}')
  501. l('else:')
  502. l(' error("unsupported platform")')
  503. l('')
  504. if inp['prefix'] in ['saudio_']:
  505. l('when defined windows:')
  506. l(' when not defined vcc:')
  507. l(' {.passl:"-lkernel32 -lole32".}')
  508. l('elif defined macosx:')
  509. l(' {.passl:"-framework AudioToolbox".}')
  510. l('elif defined linux:')
  511. l(' when not defined emscripten:')
  512. l(' {.passl:"-lasound -lm -lpthread".}')
  513. l('else:')
  514. l(' error("unsupported platform")')
  515. l('')
  516. if inp['prefix'] in ['sg_']:
  517. l('## Convert a 4-element tuple of numbers to a gfx.Color')
  518. l('converter toColor*[R:SomeNumber,G:SomeNumber,B:SomeNumber,A:SomeNumber](rgba: tuple [r:R,g:G,b:B,a:A]):Color =')
  519. l(' Color(r:rgba.r.float32, g:rgba.g.float32, b:rgba.b.float32, a:rgba.a.float32)')
  520. l('')
  521. l('## Convert a 3-element tuple of numbers to a gfx.Color')
  522. l('converter toColor*[R:SomeNumber,G:SomeNumber,B:SomeNumber](rgba: tuple [r:R,g:G,b:B]):Color =')
  523. l(' Color(r:rgba.r.float32, g:rgba.g.float32, b:rgba.b.float32, a:1.float32)')
  524. l('')
  525. # NOTE: this simplistic to_Range() converter has various issues, some of them dangerous:
  526. # - doesn't work as expected for slice types
  527. # - it's very easy to create a range that points to invalid memory
  528. # (so far observed for stack-allocated structs <= 16 bytes)
  529. #if inp['prefix'] in ['sg_', 'sdtx_', 'sshape_']:
  530. # l('# helper function to convert "anything" into a Range')
  531. # l('converter to_Range*[T](source: T): Range =')
  532. # l(' Range(addr: source.addr, size: source.sizeof.uint)')
  533. # l('')
  534. c_source_path = '/'.join(c_source_paths[inp['prefix']].split('/')[3:])
  535. l('{.passc:"-DSOKOL_NIM_IMPL".}')
  536. l('when defined(release):')
  537. l(' {.passc:"-DNDEBUG".}')
  538. l(f'{{.compile:"{c_source_path}".}}')
  539. def gen_module(inp, dep_prefixes):
  540. l('## machine generated, do not edit')
  541. l('')
  542. gen_imports(inp, dep_prefixes)
  543. pre_parse(inp)
  544. prefix = inp['prefix']
  545. for decl in inp['decls']:
  546. if not decl['is_dep']:
  547. kind = decl['kind']
  548. if kind == 'consts':
  549. gen_consts(decl, prefix)
  550. elif not check_ignore(decl['name']):
  551. if kind == 'struct':
  552. gen_struct(decl, prefix)
  553. gen_array_converters(decl, prefix)
  554. elif kind == 'enum':
  555. gen_enum(decl, prefix)
  556. elif kind == 'func':
  557. gen_func_nim(decl, prefix)
  558. gen_extra(inp)
  559. def prepare():
  560. print('=== Generating Nim bindings:')
  561. if not os.path.isdir('sokol-nim/src/sokol'):
  562. os.makedirs('sokol-nim/src/sokol')
  563. if not os.path.isdir('sokol-nim/src/sokol/c'):
  564. os.makedirs('sokol-nim/src/sokol/c')
  565. def gen(c_header_path, c_prefix, dep_c_prefixes):
  566. if not c_prefix in module_names:
  567. print(f' >> warning: skipping generation for {c_prefix} prefix...')
  568. return
  569. global out_lines
  570. module_name = module_names[c_prefix]
  571. c_source_path = c_source_paths[c_prefix]
  572. print(f' {c_header_path} => {module_name}')
  573. reset_globals()
  574. shutil.copyfile(c_header_path, f'sokol-nim/src/sokol/c/{os.path.basename(c_header_path)}')
  575. ir = gen_ir.gen(c_header_path, c_source_path, module_name, c_prefix, dep_c_prefixes)
  576. gen_module(ir, dep_c_prefixes)
  577. output_path = f"sokol-nim/src/sokol/{ir['module']}.nim"
  578. with open(output_path, 'w', newline='\n') as f_outp:
  579. f_outp.write(out_lines)