Kaynağa Gözat

update nim bindgen

* follow nim code style
* avoid keyword clashes
* remove redundant functions
* use nim bitfields for some consts
* generate bindings for sokol_glue.h
Gustav Olsson 3 yıl önce
ebeveyn
işleme
ea8a628c2e
3 değiştirilmiş dosya ile 192 ekleme ve 232 silme
  1. 1 0
      bindgen/gen_all.py
  2. 188 232
      bindgen/gen_nim.py
  3. 3 0
      bindgen/gen_zig.py

+ 1 - 0
bindgen/gen_all.py

@@ -3,6 +3,7 @@ import os, gen_nim, gen_zig
 tasks = [
     [ '../sokol_gfx.h',            'sg_',       [] ],
     [ '../sokol_app.h',            'sapp_',     [] ],
+    [ '../sokol_glue.h',           'sapp_sg',   ['sg_'] ],
     [ '../sokol_time.h',           'stm_',      [] ],
     [ '../sokol_audio.h',          'saudio_',   [] ],
     [ '../util/sokol_gl.h',        'sgl_',      ['sg_'] ],

+ 188 - 232
bindgen/gen_nim.py

@@ -2,8 +2,8 @@
 #   Read output of gen_json.py and generate Zig language bindings.
 #
 #   Nim coding style:
-#   - types and constants are PascalCase
-#   - functions, parameters, and fields are camelCase
+#   - type identifiers are PascalCase, everything else is camelCase
+#   - reference: https://nim-lang.org/docs/nep1.html
 #-------------------------------------------------------------------------------
 import gen_ir
 import json, re, os, shutil
@@ -11,6 +11,7 @@ import json, re, os, shutil
 module_names = {
     'sg_':      'gfx',
     'sapp_':    'app',
+    'sapp_sg':  'glue',
     'stm_':     'time',
     'saudio_':  'audio',
     'sgl_':     'gl',
@@ -19,13 +20,14 @@ module_names = {
 }
 
 c_source_paths = {
-    'sg_':      'sokol-nim/src/sokol/c/sokol_gfx.c',
-    'sapp_':    'sokol-nim/src/sokol/c/sokol_app.c',
-    'stm_':     'sokol-nim/src/sokol/c/sokol_time.c',
-    'saudio_':  'sokol-nim/src/sokol/c/sokol_audio.c',
-    'sgl_':     'sokol-nim/src/sokol/c/sokol_gl.c',
-    'sdtx_':    'sokol-nim/src/sokol/c/sokol_debugtext.c',
-    'sshape_':  'sokol-nim/src/sokol/c/sokol_shape.c',
+    'sg_':      'sokol-nim/src/sokol/gen/sokol_gfx.c',
+    'sapp_':    'sokol-nim/src/sokol/gen/sokol_app.c',
+    'sapp_sg':  'sokol-nim/src/sokol/gen/sokol_glue.c',
+    'stm_':     'sokol-nim/src/sokol/gen/sokol_time.c',
+    'saudio_':  'sokol-nim/src/sokol/gen/sokol_audio.c',
+    'sgl_':     'sokol-nim/src/sokol/gen/sokol_gl.c',
+    'sdtx_':    'sokol-nim/src/sokol/gen/sokol_debugtext.c',
+    'sshape_':  'sokol-nim/src/sokol/gen/sokol_shape.c',
 }
 
 func_name_ignores = [
@@ -39,15 +41,29 @@ func_name_overrides = {
     'sgl_rad': 'sgl_as_radians',
 }
 
+# consts that should be converted to Nim enum bitfields, values mimic C type declarations
+const_bitfield_overrides = {
+    'SAPP_MODIFIER_': 'sapp_event_modifier',
+}
+
 struct_field_type_overrides = {
-    'sg_context_desc.color_format': 'int',
-    'sg_context_desc.depth_format': 'int',
+    'sapp_event.modifiers': 'sapp_event_modifiers', # note the extra 's' at the end
+    'sapp_allocator.alloc': 'void * (*)(size_t, void *)',
+    'sapp_allocator.free': 'void (*)(void *, void *)',
+    'sg_allocator.alloc': 'void * (*)(size_t, void *)',
+    'sg_allocator.free': 'void (*)(void *, void *)',
+    'sgl_allocator_t.alloc': 'void * (*)(size_t, void *)',
+    'sgl_allocator_t.free': 'void (*)(void *, void *)',
+    'sdtx_allocator_t.alloc': 'void * (*)(size_t, void *)',
+    'sdtx_allocator_t.free': 'void (*)(void *, void *)',
+    'saudio_allocator.alloc': 'void * (*)(size_t, void *)',
+    'saudio_allocator.free': 'void (*)(void *, void *)',
 }
 
 prim_types = {
-    'int':          'int32',
+    'int':          'cint',
     'bool':         'bool',
-    'char':         'char',
+    'char':         'cchar',
     'int8_t':       'int8',
     'uint8_t':      'uint8',
     'int16_t':      'int16',
@@ -56,11 +72,11 @@ prim_types = {
     'uint32_t':     'uint32',
     'int64_t':      'int64',
     'uint64_t':     'uint64',
-    'float':        'float32',
-    'double':       'float64',
+    'float':        'cfloat',
+    'double':       'cdouble',
     'uintptr_t':    'uint',
     'intptr_t':     'int',
-    'size_t':       'int',
+    'size_t':       'csize_t',
 }
 
 prim_defaults = {
@@ -74,13 +90,49 @@ prim_defaults = {
     'uint32_t':     '0',
     'int64_t':      '0',
     'uint64_t':     '0',
-    'float':        '0.0',
+    'float':        '0.0f',
     'double':       '0.0',
     'uintptr_t':    '0',
     'intptr_t':     '0',
     'size_t':       '0'
 }
 
+common_prim_types = """
+untyped typed void
+bool byte char
+int int8 int16 int32 int64
+uint uint8 uint16 uint32 uint64
+float float32 float64
+string
+cchar cint csize_t
+cfloat cdouble
+cstring
+pointer
+""".split()
+
+keywords = """
+addr and as asm
+bind block break
+case cast concept const continue converter
+defer discard distinct div do
+elif else end enum except export
+finally for from func
+if import in include interface is isnot iterator
+let
+macro method mixin mod
+nil not notin
+object of or out
+proc ptr
+raise ref return
+shl shr static
+template try tuple type
+using
+var
+when while
+xor
+yield
+""".split() + common_prim_types
+
 struct_types = []
 enum_types = []
 enum_items = {}
@@ -96,8 +148,7 @@ def reset_globals():
     enum_items = {}
     out_lines = ''
 
-re_1d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]$")
-re_2d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]\[\d*\]$")
+re_array = re.compile("([a-z_\d\s\*]+)\s*\[(\d+)\]")
 
 def l(s):
     global out_lines
@@ -107,27 +158,12 @@ def as_nim_prim_type(s):
     return prim_types[s]
 
 # prefix_bla_blub(_t) => (dep.)BlaBlub
-def as_nim_struct_type(s, prefix):
+def as_nim_type_name(s, prefix):
     parts = s.lower().split('_')
-    outp = '' if s.startswith(prefix) else f'{parts[0]}.'
-    for part in parts[1:]:
-        if (part != 't'):
-            outp += part.capitalize()
-    return outp
-
-# prefix_bla_blub(_t) => (dep.)BlaBlub
-def as_nim_enum_type(s, prefix):
-    parts = s.lower().split('_')
-    outp = '' if s.startswith(prefix) else f'{parts[0]}.'
-    for part in parts[1:]:
-        if (part != 't'):
-            outp += part.capitalize()
-    return outp
-
-# prefix_bla_blub(_t) => (dep.)BlaBlub
-def as_nim_const_type(s, prefix):
-    parts = s.lower().split('_')
-    outp = '' if s.startswith(prefix) else f'{parts[0]}.'
+    dep = parts[0] + '_'
+    outp = ''
+    if not s.startswith(prefix) and dep in module_names:
+        outp = module_names[dep] + '.'
     for part in parts[1:]:
         if (part != 't'):
             outp += part.capitalize()
@@ -149,15 +185,28 @@ def check_func_name_override(func_name):
     else:
         return func_name
 
+def is_power_of_two(val):
+    return val == 0 or val & (val - 1) == 0
+
+def check_consts_bitfield_override(decl):
+    for override in const_bitfield_overrides:
+        if all(override in item['name'] for item in decl['items']):
+            if any(not is_power_of_two(int(item['value'])) for item in decl['items']):
+                print(f"warning: bitfield override '{override}' encountered non-power-of-two value")
+            return const_bitfield_overrides[override]
+    return None
+
 def trim_prefix(s, prefix):
     outp = s;
     if outp.lower().startswith(prefix.lower()):
         outp = outp[len(prefix):]
     return outp
 
-# PREFIX_BLA_BLUB to bla_blub
-def as_snake_case(s, prefix = ""):
-    return trim_prefix(s, prefix).lower()
+def wrap_keywords(s):
+    if s in keywords:
+        return f'`{s}`'
+    else:
+        return s
 
 # prefix_bla_blub => blaBlub
 def as_camel_case(s, prefix = ""):
@@ -165,7 +214,7 @@ def as_camel_case(s, prefix = ""):
     outp = parts[0]
     for part in parts[1:]:
         outp += part.capitalize()
-    return outp
+    return wrap_keywords(outp)
 
 # prefix_bla_blub => BlaBlub
 def as_pascal_case(s, prefix):
@@ -173,20 +222,20 @@ def as_pascal_case(s, prefix):
     outp = ""
     for part in parts:
         outp += part.capitalize()
-    return outp
+    return wrap_keywords(outp)
 
-# PREFIX_ENUM_BLA => Bla, _PREFIX_ENUM_BLA => Bla
+# PREFIX_ENUM_BLA_BLO => Bla, _PREFIX_ENUM_BLA_BLO => blaBlo
 def as_enum_item_name(s):
     outp = s
     if outp.startswith('_'):
         outp = outp[1:]
     parts = outp.lower().split('_')[2:]
-    outp = ""
-    for part in parts:
+    outp = parts[0]
+    for part in parts[1:]:
         outp += part.capitalize()
     if outp[0].isdigit():
-        outp = 'N' + outp
-    return outp
+        outp = 'n' + outp
+    return wrap_keywords(outp)
 
 def enum_default_item(enum_name):
     return enum_items[enum_name][0]
@@ -230,20 +279,17 @@ def is_const_struct_ptr(s):
 def is_func_ptr(s):
     return '(*)' in s
 
-def is_1d_array_type(s):
-    return re_1d_array.match(s)
-
-def is_2d_array_type(s):
-    return re_2d_array.match(s)
+def is_array_type(s):
+    return re_array.match(s) is not None
 
 def type_default_value(s):
     return prim_defaults[s]
 
 def extract_array_type(s):
-    return s[:s.index('[')].strip()
+    return s[:s.find('[')].strip() + s[s.find(']')+1:].strip()
 
 def extract_array_nums(s):
-    return s[s.index('['):].replace('[', ' ').replace(']', ' ').split()
+    return s[s.find('[')+1:s.find(']')].strip()
 
 def extract_ptr_type(s):
     tokens = s.split()
@@ -252,239 +298,141 @@ def extract_ptr_type(s):
     else:
         return tokens[0]
 
-def as_extern_c_arg_type(arg_type, prefix):
-    if arg_type == "void":
-        return "void"
-    elif is_prim_type(arg_type):
-        return as_nim_prim_type(arg_type)
-    elif is_struct_type(arg_type):
-        return as_nim_struct_type(arg_type, prefix)
-    elif is_enum_type(arg_type):
-        return as_nim_enum_type(arg_type, prefix)
-    elif is_void_ptr(arg_type):
-        return "pointer"
-    elif is_const_void_ptr(arg_type):
-        return "pointer"
-    elif is_string_ptr(arg_type):
+def as_nim_type(ctype, prefix):
+    if ctype == "void":
+        return ""
+    elif is_prim_type(ctype):
+        return as_nim_prim_type(ctype)
+    elif is_struct_type(ctype):
+        return as_nim_type_name(ctype, prefix)
+    elif is_enum_type(ctype):
+        return as_nim_type_name(ctype, prefix)
+    elif is_string_ptr(ctype):
         return "cstring"
-    elif is_const_struct_ptr(arg_type):
-        return f"ptr {as_nim_struct_type(extract_ptr_type(arg_type), prefix)}"
-    elif is_prim_ptr(arg_type):
-        return f"[*c] {as_nim_prim_type(extract_ptr_type(arg_type))}"
-    elif is_const_prim_ptr(arg_type):
-        return f"ptr {as_nim_prim_type(extract_ptr_type(arg_type))}"
-    else:
-        return '??? (as_extern_c_arg_type)'
-
-def as_nim_arg_type(arg_prefix, arg_type, prefix):
-    # NOTE: if arg_prefix is None, the result is used as return value
-    pre = "" if arg_prefix is None else arg_prefix
-    if arg_type == "void":
-        if arg_prefix is None:
-            return "void"
-        else:
-            return ""
-    elif is_prim_type(arg_type):
-        return pre + as_nim_prim_type(arg_type)
-    elif is_struct_type(arg_type):
-        return pre + as_nim_struct_type(arg_type, prefix)
-    elif is_enum_type(arg_type):
-        return pre + as_nim_enum_type(arg_type, prefix)
-    elif is_void_ptr(arg_type):
-        return pre + "pointer"
-    elif is_const_void_ptr(arg_type):
-        return pre + "pointer"
-    elif is_string_ptr(arg_type):
-        return pre + "cstring"
-    elif is_const_struct_ptr(arg_type):
-        return pre + f"ptr {as_nim_struct_type(extract_ptr_type(arg_type), prefix)}"
-    elif is_prim_ptr(arg_type):
-        return pre + f"ptr {as_nim_prim_type(extract_ptr_type(arg_type))}"
-    elif is_const_prim_ptr(arg_type):
-        return pre + f"ptr {as_nim_prim_type(extract_ptr_type(arg_type))}"
+    elif is_void_ptr(ctype) or is_const_void_ptr(ctype):
+        return "pointer"
+    elif is_const_struct_ptr(ctype):
+        return f"ptr {as_nim_type(extract_ptr_type(ctype), prefix)}"
+    elif is_prim_ptr(ctype) or is_const_prim_ptr(ctype):
+        return f"ptr {as_nim_type(extract_ptr_type(ctype), prefix)}"
+    elif is_func_ptr(ctype):
+        args = funcptr_args(ctype, prefix)
+        res = funcptr_res(ctype, prefix)
+        if res != "":
+            res = ":" + res
+        return f"proc({args}){res} {{.cdecl.}}"
+    elif is_array_type(ctype):
+        array_ctype = extract_array_type(ctype)
+        array_nums = extract_array_nums(ctype)
+        return f"array[{array_nums}, {as_nim_type(array_ctype, prefix)}]"
     else:
-        return arg_prefix + "??? (as_nim_arg_type)"
+        l(f"// FIXME: {ctype};")
 
-# get C-style arguments of a function pointer as string
-def funcptr_args_c(field_type, prefix):
+def funcptr_args(field_type, prefix):
     tokens = field_type[field_type.index('(*)')+4:-1].split(',')
     s = ""
     n = 0
     for token in tokens:
         n += 1
-        arg_type = token.strip()
+        arg_ctype = token.strip()
         if s != "":
             s += ", "
-        c_arg = f"a{n}:" + as_extern_c_arg_type(arg_type, prefix)
-        if (c_arg == "void"):
-            return ""
-        else:
-            s += c_arg
+        arg_nimtype = as_nim_type(arg_ctype, prefix)
+        if arg_nimtype == "":
+            return "" # fun(void)
+        s += f"a{n}:{arg_nimtype}"
     if s == "a1:void":
         s = ""
     return s
 
-# get C-style result of a function pointer as string
-def funcptr_res_c(field_type):
-    res_type = field_type[:field_type.index('(*)')].strip()
-    if res_type == 'void':
-        return ''
-    elif is_const_void_ptr(res_type):
-        return ':pointer'
-    else:
-        return '???'
+def funcptr_res(field_type, prefix):
+    ctype = field_type[:field_type.index('(*)')].strip()
+    return as_nim_type(ctype, prefix)
 
-def funcdecl_args_c(decl, prefix):
-    s = ""
-    for param_decl in decl['params']:
-        if s != "":
-            s += ", "
-        arg_type = param_decl['type']
-        s += as_extern_c_arg_type(arg_type, prefix)
-    return s
-
-def funcdecl_args_nim(decl, prefix):
+def funcdecl_args(decl, prefix):
     s = ""
     for param_decl in decl['params']:
         if s != "":
             s += ", "
         arg_name = param_decl['name']
         arg_type = param_decl['type']
-        s += f"{as_nim_arg_type(f'{arg_name}:', arg_type, prefix)}"
+        s += f"{arg_name}:{as_nim_type(arg_type, prefix)}"
     return s
 
-def funcdecl_res_c(decl, prefix):
-    decl_type = decl['type']
-    res_type = decl_type[:decl_type.index('(')].strip()
-    return as_extern_c_arg_type(res_type, prefix)
-
-def funcdecl_res_nim(decl, prefix):
+def funcdecl_res(decl, prefix):
     decl_type = decl['type']
     res_type = decl_type[:decl_type.index('(')].strip()
-    nim_res_type = as_nim_arg_type(None, res_type, prefix)
+    nim_res_type = as_nim_type(res_type, prefix)
     if nim_res_type == "":
         nim_res_type = "void"
     return nim_res_type
 
 def gen_struct(decl, prefix, use_raw_name=False):
     struct_name = decl['name']
-    nim_type = struct_name if use_raw_name else as_nim_struct_type(struct_name, prefix)
+    nim_type = struct_name if use_raw_name else as_nim_type_name(struct_name, prefix)
     l(f"type {nim_type}* = object")
-    isPublic = True
+    is_public = True
     for field in decl['fields']:
         field_name = field['name']
         if field_name == "__pad":
             # FIXME: these should be guarded by SOKOL_ZIG_BINDINGS, but aren't?
             continue
-        isPublic = not field_name.startswith("_")
+        is_public = not field_name.startswith("_")
         field_name = as_camel_case(field_name, "_")
-        if field_name == "ptr":
-            field_name = "source"
-        if field_name == "ref":
-            field_name = "`ref`"
-        if field_name == "type":
-            field_name = "`type`"
-        if isPublic:
+        if is_public:
             field_name += "*"
-        field_type = field['type']
-        field_type = check_struct_field_type_override(struct_name, field_name, field_type)
-        if is_prim_type(field_type):
-            l(f"  {field_name}:{as_nim_prim_type(field_type)}")
-        elif is_struct_type(field_type):
-            l(f"  {field_name}:{as_nim_struct_type(field_type, prefix)}")
-        elif is_enum_type(field_type):
-            l(f"  {field_name}:{as_nim_enum_type(field_type, prefix)}")
-        elif is_string_ptr(field_type):
-            l(f"  {field_name}:cstring")
-        elif is_const_void_ptr(field_type):
-            l(f"  {field_name}:pointer")
-        elif is_void_ptr(field_type):
-            l(f"  {field_name}:pointer")
-        elif is_const_prim_ptr(field_type):
-            l(f"  {field_name}:ptr {as_nim_prim_type(extract_ptr_type(field_type))}")
-        elif is_func_ptr(field_type):
-            l(f"  {field_name}:proc({funcptr_args_c(field_type, prefix)}){funcptr_res_c(field_type)} {{.cdecl.}}")
-        elif is_1d_array_type(field_type):
-            array_type = extract_array_type(field_type)
-            array_nums = extract_array_nums(field_type)
-            if is_prim_type(array_type) or is_struct_type(array_type):
-                if is_prim_type(array_type):
-                    nim_type = as_nim_prim_type(array_type)
-                elif is_struct_type(array_type):
-                    nim_type = as_nim_struct_type(array_type, prefix)
-                elif is_enum_type(array_type):
-                    nim_type = as_nim_enum_type(array_type, prefix)
-                else:
-                    nim_type = '??? (array type)'
-                t0 = f"array[{array_nums[0]}, {nim_type}]"
-                t0_slice = f"[]const {nim_type}"
-                t1 = f"[_]{nim_type}"
-                l(f"  {field_name}:{t0}")
-            elif is_const_void_ptr(array_type):
-                l(f"  {field_name}:array[{array_nums[0]}, pointer]")
-            else:
-                l(f"//    FIXME: ??? array {field_name}:{field_type} => {array_type} [{array_nums[0]}]")
-        elif is_2d_array_type(field_type):
-            array_type = extract_array_type(field_type)
-            array_nums = extract_array_nums(field_type)
-            if is_prim_type(array_type):
-                nim_type = as_nim_prim_type(array_type)
-                def_val = type_default_value(array_type)
-            elif is_struct_type(array_type):
-                nim_type = as_nim_struct_type(array_type, prefix)
-                def_val = ".{ }"
-            else:
-                nim_type = "???"
-                def_val = "???"
-            t0 = f"array[{array_nums[0]}, array[{array_nums[1]}, {nim_type}]]"
-            l(f"  {field_name}:{t0}")
-        else:
-            l(f"// FIXME: {field_name}:{field_type};")
+        field_type = check_struct_field_type_override(decl['name'], field['name'], field['type'])
+        l(f"  {field_name}:{as_nim_type(field_type, prefix)}")
     l("")
 
 def gen_consts(decl, prefix):
     l("const")
     for item in decl['items']:
-        l(f"  {trim_prefix(item['name'], prefix)}* = {item['value']}")
+        l(f"  {as_camel_case(trim_prefix(item['name'], prefix), prefix)}* = {item['value']}")
     l("")
 
-def gen_enum(decl, prefix):
+def gen_enum(decl, prefix, bitfield=None):
     item_names_by_value = {}
     value = -1
-    hasForceU32 = False
-    hasExplicitValues = False
+    has_force_u32 = False
+    has_explicit_values = False
     for item in decl['items']:
         itemName = item['name']
         if itemName.endswith("_FORCE_U32"):
-            hasForceU32 = True
+            has_force_u32 = True
         elif itemName.endswith("_NUM"):
             continue
         else:
             if 'value' in item:
-                hasExplicitValues = True
+                has_explicit_values = True
                 value = int(item['value'])
             else:
                 value += 1
             item_names_by_value[value] = as_enum_item_name(item['name']);
-    if hasForceU32:
-        l(f"type {as_nim_enum_type(decl['name'], prefix)}* {{.pure, size:4.}} = enum")
+    enum_name = bitfield if bitfield is not None else decl['name']
+    enum_name_nim = as_nim_type_name(enum_name, prefix)
+    l('type')
+    if has_force_u32:
+        l(f"  {enum_name_nim}* {{.pure, size:sizeof(cint).}} = enum")
     else:
-        l(f"type {as_nim_enum_type(decl['name'], prefix)}* {{.pure.}} = enum")
-    if hasExplicitValues:
+        l(f"  {enum_name_nim}* {{.pure.}} = enum")
+    if has_explicit_values:
         # Nim requires explicit enum values to be declared in ascending order
         for value in sorted(item_names_by_value):
             name = item_names_by_value[value]
-            l(f"  {name} = {value},")
+            l(f"    {name} = {value},")
     else:
         for name in item_names_by_value.values():
-            l(f"  {name},")
+            l(f"    {name},")
+    if bitfield is not None:
+        l(f"  {enum_name_nim}s = set[{enum_name_nim}]")
     l("")
 
 def gen_func_nim(decl, prefix):
     c_func_name = decl['name']
     nim_func_name = as_camel_case(decl['name'], prefix)
-    nim_res_type = funcdecl_res_nim(decl, prefix)
-    l(f"proc {nim_func_name}*({funcdecl_args_nim(decl, prefix)}):{funcdecl_res_nim(decl, prefix)} {{.cdecl, importc:\"{decl['name']}\".}}")
+    nim_res_type = funcdecl_res(decl, prefix)
+    l(f"proc {nim_func_name}*({funcdecl_args(decl, prefix)}):{funcdecl_res(decl, prefix)} {{.cdecl, importc:\"{decl['name']}\".}}")
     l("")
 
 def pre_parse(inp):
@@ -500,6 +448,9 @@ def pre_parse(inp):
             enum_items[enum_name] = []
             for item in decl['items']:
                 enum_items[enum_name].append(as_enum_item_name(item['name']))
+    for bitfield in const_bitfield_overrides.values():
+        enum_types.append(bitfield)
+        enum_types.append(bitfield + 's')
 
 def gen_imports(inp, dep_prefixes):
     for dep_prefix in dep_prefixes:
@@ -517,7 +468,11 @@ def gen_module(inp, dep_prefixes):
         if not decl['is_dep']:
             kind = decl['kind']
             if kind == 'consts':
-                gen_consts(decl, prefix)
+                bitfield = check_consts_bitfield_override(decl)
+                if bitfield is not None:
+                    gen_enum(decl, prefix, bitfield=bitfield)
+                else:
+                    gen_consts(decl, prefix)
             elif kind == 'enum':
                 gen_enum(decl, prefix)
             elif kind == 'struct':
@@ -530,33 +485,34 @@ def prepare():
     print('Generating nim bindings:')
     if not os.path.isdir('sokol-nim/src/sokol'):
         os.makedirs('sokol-nim/src/sokol')
-    if not os.path.isdir('sokol-nim/src/sokol/c'):
-        os.makedirs('sokol-nim/src/sokol/c')
+    if not os.path.isdir('sokol-nim/src/sokol/gen'):
+        os.makedirs('sokol-nim/src/sokol/gen')
 
 def gen(c_header_path, c_prefix, dep_c_prefixes):
+    if not c_prefix in module_names:
+        print(f'warning: skipping generation for {c_prefix} prefix...')
+        return
     global out_lines
     module_name = module_names[c_prefix]
     c_source_path = c_source_paths[c_prefix]
     print(f'  {c_header_path} => {module_name}')
     reset_globals()
-    shutil.copyfile(c_header_path, f'sokol-nim/src/sokol/c/{os.path.basename(c_header_path)}')
+    shutil.copyfile(c_header_path, f'sokol-nim/src/sokol/gen/{os.path.basename(c_header_path)}')
     ir = gen_ir.gen(c_header_path, c_source_path, module_name, c_prefix, dep_c_prefixes)
     gen_module(ir, dep_c_prefixes)
     output_path = f"sokol-nim/src/sokol/{ir['module']}.nim"
 
     ## some changes for readability
-    out_lines = out_lines.replace("PixelformatInfo", "PixelFormatInfo")
-    out_lines = out_lines.replace(" Dontcare,", " DontCare,")
-    out_lines = out_lines.replace(" Vertexbuffer,", " VertexBuffer,")
-    out_lines = out_lines.replace(" Indexbuffer,", " IndexBuffer,")
-    out_lines = out_lines.replace(" N2d,", " Plane,")
-    out_lines = out_lines.replace(" N3d,", " Volume,")
-    out_lines = out_lines.replace(" Vs,", " Vertex,")
-    out_lines = out_lines.replace(" Fs,", " Fragment,")
+    out_lines = out_lines.replace("pixelformatInfo", "pixelFormatInfo")
+    out_lines = out_lines.replace(" dontcare,", " dontCare,")
+    out_lines = out_lines.replace(" vertexbuffer,", " vertexBuffer,")
+    out_lines = out_lines.replace(" indexbuffer,", " indexBuffer,")
+    out_lines = out_lines.replace(" n2d,", " plane,")
+    out_lines = out_lines.replace(" n3d,", " volume,")
 
     ## include extensions in generated code
     l("# Nim-specific API extensions")
-    l(f"include nim/{ir['module']}")
+    l(f"include extra/{ir['module']}")
 
     with open(output_path, 'w', newline='\n') as f_outp:
         f_outp.write(out_lines)

+ 3 - 0
bindgen/gen_zig.py

@@ -564,6 +564,9 @@ def prepare():
         os.makedirs('sokol-zig/src/sokol/c')
 
 def gen(c_header_path, c_prefix, dep_c_prefixes):
+    if not c_prefix in module_names:
+        print(f'warning: skipping generation for {c_prefix} prefix...')
+        return
     module_name = module_names[c_prefix]
     c_source_path = c_source_paths[c_prefix]
     print(f'  {c_header_path} => {module_name}')