Ver Fonte

Fix language bindings:

- clang-14 ast-dump has changed for array types, fix works both for new and old format
- start moving common helper functions into gen_util.py
Andre Weissflog há 2 anos atrás
pai
commit
471f125e0a
4 ficheiros alterados com 123 adições e 187 exclusões
  1. 18 54
      bindgen/gen_nim.py
  2. 16 52
      bindgen/gen_odin.py
  3. 57 0
      bindgen/gen_util.py
  4. 32 81
      bindgen/gen_zig.py

+ 18 - 54
bindgen/gen_nim.py

@@ -6,7 +6,8 @@
 #   - reference: https://nim-lang.org/docs/nep1.html
 #-------------------------------------------------------------------------------
 import gen_ir
-import re, os, shutil, sys
+import gen_util as util
+import os, shutil, sys
 
 module_names = {
     'sg_':      'gfx',
@@ -151,9 +152,6 @@ xor
 yield
 """.split() + common_prim_types
 
-re_1d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]$")
-re_2d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]\[\d*\]$")
-
 struct_types = []
 enum_types = []
 out_lines = ''
@@ -243,15 +241,6 @@ def is_struct_type(s):
 def is_enum_type(s):
     return s in enum_types
 
-def is_string_ptr(s):
-    return s == "const char *"
-
-def is_const_void_ptr(s):
-    return s == "const void *"
-
-def is_void_ptr(s):
-    return s == "void *"
-
 def is_const_prim_ptr(s):
     for prim_type in prim_types:
         if s == f"const {prim_type} *":
@@ -270,34 +259,9 @@ def is_const_struct_ptr(s):
             return True
     return False
 
-def is_func_ptr(s):
-    return '(*)' in s
-
-def is_1d_array_type(s):
-    return re_1d_array.match(s) is not None
-
-def is_2d_array_type(s):
-    return re_2d_array.match(s) is not None
-
-def is_array_type(s):
-    return is_1d_array_type(s) or is_2d_array_type(s)
-
 def type_default_value(s):
     return prim_defaults[s]
 
-def extract_array_type(s):
-    return s[:s.index('[')].strip()
-
-def extract_array_sizes(s):
-    return s[s.index('['):].replace('[', ' ').replace(']', ' ').split()
-
-def extract_ptr_type(s):
-    tokens = s.split()
-    if tokens[0] == 'const':
-        return tokens[1]
-    else:
-        return tokens[0]
-
 def funcptr_args(field_type, prefix):
     tokens = field_type[field_type.index('(*)')+4:-1].split(',')
     s = ""
@@ -328,31 +292,31 @@ def as_nim_type(ctype, prefix, struct_ptr_as_value=False):
         return as_nim_type_name(ctype, prefix)
     elif is_enum_type(ctype):
         return as_nim_type_name(ctype, prefix)
-    elif is_string_ptr(ctype):
+    elif util.is_string_ptr(ctype):
         return "cstring"
-    elif is_void_ptr(ctype) or is_const_void_ptr(ctype):
+    elif util.is_void_ptr(ctype) or util.is_const_void_ptr(ctype):
         return "pointer"
     elif is_const_struct_ptr(ctype):
-        nim_type = as_nim_type(extract_ptr_type(ctype), prefix)
+        nim_type = as_nim_type(util.extract_ptr_type(ctype), prefix)
         if struct_ptr_as_value:
             return f"{nim_type}"
         else:
             return f"ptr {nim_type}"
     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):
+        return f"ptr {as_nim_type(util.extract_ptr_type(ctype), prefix)}"
+    elif util.is_func_ptr(ctype):
         args = funcptr_args(ctype, prefix)
         res = funcptr_result(ctype, prefix)
         if res != "":
             res = ":" + res
         return f"proc({args}){res} {{.cdecl.}}"
-    elif is_1d_array_type(ctype):
-        array_ctype = extract_array_type(ctype)
-        array_sizes = extract_array_sizes(ctype)
+    elif util.is_1d_array_type(ctype):
+        array_ctype = util.extract_array_type(ctype)
+        array_sizes = util.extract_array_sizes(ctype)
         return f'array[{array_sizes[0]}, {as_nim_type(array_ctype, prefix)}]'
-    elif is_2d_array_type(ctype):
-        array_ctype = extract_array_type(ctype)
-        array_sizes = extract_array_sizes(ctype)
+    elif util.is_2d_array_type(ctype):
+        array_ctype = util.extract_array_type(ctype)
+        array_sizes = util.extract_array_sizes(ctype)
         return f'array[{array_sizes[0]}, array[{array_sizes[1]}, {as_nim_type(array_ctype, prefix)}]]'
     else:
         sys.exit(f"ERROR as_nim_type: {ctype}")
@@ -468,19 +432,19 @@ def gen_func_nim(decl, prefix):
 
 def gen_array_converters(decl, prefix):
     for field in decl['fields']:
-        if is_array_type(field['type']):
-            array_type = extract_array_type(field['type'])
-            array_sizes = extract_array_sizes(field['type'])
+        if util.is_array_type(field['type']):
+            array_type = util.extract_array_type(field['type'])
+            array_sizes = util.extract_array_sizes(field['type'])
             struct_name = as_nim_struct_name(decl, prefix)
             field_name = as_nim_field_name(field, prefix, check_private=False)
             array_base_type = as_nim_type(array_type, prefix)
-            if is_1d_array_type(field['type']):
+            if util.is_1d_array_type(field['type']):
                 n = array_sizes[0]
                 l(f'converter to{struct_name}{field_name}*[N:static[int]](items: array[N, {array_base_type}]): array[{n}, {array_base_type}] =')
                 l(f'  static: assert(N < {n})')
                 l(f'  for index,item in items.pairs: result[index]=item')
                 l('')
-            elif is_2d_array_type(field['type']):
+            elif util.is_2d_array_type(field['type']):
                 x = array_sizes[1]
                 y = array_sizes[0]
                 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}]] =')

+ 16 - 52
bindgen/gen_odin.py

@@ -4,7 +4,8 @@
 #   Generate Odin bindings.
 #-------------------------------------------------------------------------------
 import gen_ir
-import re, os, shutil, sys
+import gen_util as util
+import os, shutil, sys
 
 bindings_root = 'sokol-odin'
 c_root = f'{bindings_root}/c'
@@ -128,9 +129,6 @@ prim_defaults = {
     'size_t':       '0'
 }
 
-re_1d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]$")
-re_2d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]\[\d*\]$")
-
 struct_types = []
 enum_types = []
 enum_items = {}
@@ -218,15 +216,6 @@ def is_struct_type(s):
 def is_enum_type(s):
     return s in enum_types
 
-def is_string_ptr(s):
-    return s == "const char *"
-
-def is_const_void_ptr(s):
-    return s == "const void *"
-
-def is_void_ptr(s):
-    return s == "void *"
-
 def is_const_prim_ptr(s):
     for prim_type in prim_types:
         if s == f"const {prim_type} *":
@@ -245,31 +234,9 @@ def is_const_struct_ptr(s):
             return True
     return False
 
-def is_func_ptr(s):
-    return '(*)' in s
-
-def is_1d_array_type(s):
-    return re_1d_array.match(s) is not None
-
-def is_2d_array_type(s):
-    return re_2d_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()
-
-def extract_array_sizes(s):
-    return s[s.index('['):].replace('[', ' ').replace(']', ' ').split()
-
-def extract_ptr_type(s):
-    tokens = s.split()
-    if tokens[0] == 'const':
-        return tokens[1]
-    else:
-        return tokens[0]
-
 def map_type(type, prefix, sub_type):
     if sub_type not in ['c_arg', 'odin_arg', 'struct_field']:
         sys.exit(f"Error: map_type(): unknown sub_type '{sub_type}")
@@ -288,31 +255,31 @@ def map_type(type, prefix, sub_type):
         return as_struct_or_enum_type(type, prefix)
     elif is_enum_type(type):
         return as_struct_or_enum_type(type, prefix)
-    elif is_void_ptr(type):
+    elif util.is_void_ptr(type):
         return "rawptr"
-    elif is_const_void_ptr(type):
+    elif util.is_const_void_ptr(type):
         return "rawptr"
-    elif is_string_ptr(type):
+    elif util.is_string_ptr(type):
         return "cstring"
     elif is_const_struct_ptr(type):
         # pass Odin struct args by value, not by pointer
         if sub_type == 'odin_arg':
-            return f"{as_struct_or_enum_type(extract_ptr_type(type), prefix)}"
+            return f"{as_struct_or_enum_type(util.extract_ptr_type(type), prefix)}"
         else:
-            return f"^{as_struct_or_enum_type(extract_ptr_type(type), prefix)}"
+            return f"^{as_struct_or_enum_type(util.extract_ptr_type(type), prefix)}"
     elif is_prim_ptr(type):
-        return f"^{as_prim_type(extract_ptr_type(type))}"
+        return f"^{as_prim_type(util.extract_ptr_type(type))}"
     elif is_const_prim_ptr(type):
-        return f"^{as_prim_type(extract_ptr_type(type))}"
-    elif is_1d_array_type(type):
-        array_type = extract_array_type(type)
-        array_sizes = extract_array_sizes(type)
+        return f"^{as_prim_type(util.extract_ptr_type(type))}"
+    elif util.is_1d_array_type(type):
+        array_type = util.extract_array_type(type)
+        array_sizes = util.extract_array_sizes(type)
         return f"[{array_sizes[0]}]{map_type(array_type, prefix, sub_type)}"
-    elif is_2d_array_type(type):
-        array_type = extract_array_type(type)
-        array_sizes = extract_array_sizes(type)
+    elif util.is_2d_array_type(type):
+        array_type = util.extract_array_type(type)
+        array_sizes = util.extract_array_sizes(type)
         return f"[{array_sizes[0]}][{array_sizes[1]}]{map_type(array_type, prefix, sub_type)}"
-    elif is_func_ptr(type):
+    elif util.is_func_ptr(type):
         res_type = funcptr_result_c(type, prefix)
         res_str = '' if res_type == '' else f' -> {res_type}'
         return f'proc "c" ({funcptr_args_c(type, prefix)}){res_str}'
@@ -532,6 +499,3 @@ def gen(c_header_path, c_prefix, dep_c_prefixes):
     gen_module(ir, c_prefix, dep_c_prefixes)
     with open(f"{module_root}/{ir['module']}/{ir['module']}.odin", 'w', newline='\n') as f_outp:
         f_outp.write(out_lines)
-
-
-

+ 57 - 0
bindgen/gen_util.py

@@ -0,0 +1,57 @@
+# common utility functions for all bindings generators
+import re
+
+re_1d_array = re.compile("^(?:const )?\w*\s*\*?\[\d*\]$")
+re_2d_array = re.compile("^(?:const )?\w*\s*\*?\[\d*\]\[\d*\]$")
+
+def is_1d_array_type(s):
+    return re_1d_array.match(s) is not None
+
+def is_2d_array_type(s):
+    return re_2d_array.match(s) is not None
+
+def is_array_type(s):
+    return is_1d_array_type(s) or is_2d_array_type(s)
+
+def extract_array_type(s):
+    return s[:s.index('[')].strip()
+
+def extract_array_sizes(s):
+    return s[s.index('['):].replace('[', ' ').replace(']', ' ').split()
+
+def is_string_ptr(s):
+    return s == "const char *"
+
+def is_const_void_ptr(s):
+    return s == "const void *"
+
+def is_void_ptr(s):
+    return s == "void *"
+
+def is_func_ptr(s):
+    return '(*)' in s
+
+def extract_ptr_type(s):
+    tokens = s.split()
+    if tokens[0] == 'const':
+        return tokens[1]
+    else:
+        return tokens[0]
+
+# PREFIX_BLA_BLUB to bla_blub
+def as_lower_snake_case(s, prefix):
+    outp = s.lower()
+    if outp.startswith(prefix):
+        outp = outp[len(prefix):]
+    return outp
+
+# prefix_bla_blub => blaBlub, PREFIX_BLA_BLUB => blaBlub
+def as_lower_camel_case(s, prefix):
+    outp = s.lower()
+    if outp.startswith(prefix):
+        outp = outp[len(prefix):]
+    parts = outp.split('_')
+    outp = parts[0]
+    for part in parts[1:]:
+        outp += part.capitalize()
+    return outp

+ 32 - 81
bindgen/gen_zig.py

@@ -7,7 +7,9 @@
 #   - otherwise snake_case
 #-------------------------------------------------------------------------------
 import gen_ir
-import re, os, shutil, sys
+import os, shutil, sys
+
+import gen_util as util
 
 module_names = {
     'sg_':      'gfx',
@@ -90,8 +92,6 @@ prim_defaults = {
     'size_t':       '0'
 }
 
-re_1d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]$")
-re_2d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]\[\d*\]$")
 
 struct_types = []
 enum_types = []
@@ -145,24 +145,6 @@ def check_override(name, default=None):
 def check_ignore(name):
     return name in ignores
 
-# PREFIX_BLA_BLUB to bla_blub
-def as_snake_case(s, prefix):
-    outp = s.lower()
-    if outp.startswith(prefix):
-        outp = outp[len(prefix):]
-    return outp
-
-# prefix_bla_blub => blaBlub
-def as_camel_case(s, prefix):
-    outp = s.lower()
-    if outp.startswith(prefix):
-        outp = outp[len(prefix):]
-    parts = outp.split('_')
-    outp = parts[0]
-    for part in parts[1:]:
-        outp += part.capitalize()
-    return outp
-
 # PREFIX_ENUM_BLA => Bla, _PREFIX_ENUM_BLA => Bla
 def as_enum_item_name(s):
     outp = s.lstrip('_')
@@ -184,15 +166,6 @@ def is_struct_type(s):
 def is_enum_type(s):
     return s in enum_types
 
-def is_string_ptr(s):
-    return s == "const char *"
-
-def is_const_void_ptr(s):
-    return s == "const void *"
-
-def is_void_ptr(s):
-    return s == "void *"
-
 def is_const_prim_ptr(s):
     for prim_type in prim_types:
         if s == f"const {prim_type} *":
@@ -211,31 +184,9 @@ def is_const_struct_ptr(s):
             return True
     return False
 
-def is_func_ptr(s):
-    return '(*)' in s
-
-def is_1d_array_type(s):
-    return re_1d_array.match(s) is not None
-
-def is_2d_array_type(s):
-    return re_2d_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()
-
-def extract_array_sizes(s):
-    return s[s.index('['):].replace('[', ' ').replace(']', ' ').split()
-
-def extract_ptr_type(s):
-    tokens = s.split()
-    if tokens[0] == 'const':
-        return tokens[1]
-    else:
-        return tokens[0]
-
 def as_c_arg_type(arg_type, prefix):
     if arg_type == "void":
         return "void"
@@ -245,18 +196,18 @@ def as_c_arg_type(arg_type, prefix):
         return as_zig_struct_type(arg_type, prefix)
     elif is_enum_type(arg_type):
         return as_zig_enum_type(arg_type, prefix)
-    elif is_void_ptr(arg_type):
+    elif util.is_void_ptr(arg_type):
         return "?*anyopaque"
-    elif is_const_void_ptr(arg_type):
+    elif util.is_const_void_ptr(arg_type):
         return "?*const anyopaque"
-    elif is_string_ptr(arg_type):
+    elif util.is_string_ptr(arg_type):
         return "[*c]const u8"
     elif is_const_struct_ptr(arg_type):
-        return f"[*c]const {as_zig_struct_type(extract_ptr_type(arg_type), prefix)}"
+        return f"[*c]const {as_zig_struct_type(util.extract_ptr_type(arg_type), prefix)}"
     elif is_prim_ptr(arg_type):
-        return f"[*c] {as_zig_prim_type(extract_ptr_type(arg_type))}"
+        return f"[*c] {as_zig_prim_type(util.extract_ptr_type(arg_type))}"
     elif is_const_prim_ptr(arg_type):
-        return f"[*c]const {as_zig_prim_type(extract_ptr_type(arg_type))}"
+        return f"[*c]const {as_zig_prim_type(util.extract_ptr_type(arg_type))}"
     else:
         sys.exit(f"Error as_c_arg_type(): {arg_type}")
 
@@ -274,19 +225,19 @@ def as_zig_arg_type(arg_prefix, arg_type, prefix):
         return pre + as_zig_struct_type(arg_type, prefix)
     elif is_enum_type(arg_type):
         return pre + as_zig_enum_type(arg_type, prefix)
-    elif is_void_ptr(arg_type):
+    elif util.is_void_ptr(arg_type):
         return pre + "?*anyopaque"
-    elif is_const_void_ptr(arg_type):
+    elif util.is_const_void_ptr(arg_type):
         return pre + "?*const anyopaque"
-    elif is_string_ptr(arg_type):
+    elif util.is_string_ptr(arg_type):
         return pre + "[:0]const u8"
     elif is_const_struct_ptr(arg_type):
         # not a bug, pass const structs by value
-        return pre + f"{as_zig_struct_type(extract_ptr_type(arg_type), prefix)}"
+        return pre + f"{as_zig_struct_type(util.extract_ptr_type(arg_type), prefix)}"
     elif is_prim_ptr(arg_type):
-        return pre + f"* {as_zig_prim_type(extract_ptr_type(arg_type))}"
+        return pre + f"* {as_zig_prim_type(util.extract_ptr_type(arg_type))}"
     elif is_const_prim_ptr(arg_type):
-        return pre + f"*const {as_zig_prim_type(extract_ptr_type(arg_type))}"
+        return pre + f"*const {as_zig_prim_type(util.extract_ptr_type(arg_type))}"
     else:
         sys.exit(f"ERROR as_zig_arg_type(): {arg_type}")
 
@@ -313,9 +264,9 @@ def funcptr_result_c(field_type):
     res_type = field_type[:field_type.index('(*)')].strip()
     if res_type == 'void':
         return 'void'
-    elif is_const_void_ptr(res_type):
+    elif util.is_const_void_ptr(res_type):
         return '?*const anyopaque'
-    elif is_void_ptr(res_type):
+    elif util.is_void_ptr(res_type):
         return '?*anyopaque'
     else:
         sys.exit(f"ERROR funcptr_result_c(): {field_type}")
@@ -368,19 +319,19 @@ def gen_struct(decl, prefix):
             l(f"    {field_name}: {as_zig_struct_type(field_type, prefix)} = .{{ }},")
         elif is_enum_type(field_type):
             l(f"    {field_name}: {as_zig_enum_type(field_type, prefix)} = .{enum_default_item(field_type)},")
-        elif is_string_ptr(field_type):
+        elif util.is_string_ptr(field_type):
             l(f"    {field_name}: [*c]const u8 = null,")
-        elif is_const_void_ptr(field_type):
+        elif util.is_const_void_ptr(field_type):
             l(f"    {field_name}: ?*const anyopaque = null,")
-        elif is_void_ptr(field_type):
+        elif util.is_void_ptr(field_type):
             l(f"    {field_name}: ?*anyopaque = null,")
         elif is_const_prim_ptr(field_type):
-            l(f"    {field_name}: ?[*]const {as_zig_prim_type(extract_ptr_type(field_type))} = null,")
-        elif is_func_ptr(field_type):
+            l(f"    {field_name}: ?[*]const {as_zig_prim_type(util.extract_ptr_type(field_type))} = null,")
+        elif util.is_func_ptr(field_type):
             l(f"    {field_name}: ?fn({funcptr_args_c(field_type, prefix)}) callconv(.C) {funcptr_result_c(field_type)} = null,")
-        elif is_1d_array_type(field_type):
-            array_type = extract_array_type(field_type)
-            array_sizes = extract_array_sizes(field_type)
+        elif util.is_1d_array_type(field_type):
+            array_type = util.extract_array_type(field_type)
+            array_sizes = util.extract_array_sizes(field_type)
             if is_prim_type(array_type) or is_struct_type(array_type):
                 if is_prim_type(array_type):
                     zig_type = as_zig_prim_type(array_type)
@@ -396,13 +347,13 @@ def gen_struct(decl, prefix):
                 t0 = f"[{array_sizes[0]}]{zig_type}"
                 t1 = f"[_]{zig_type}"
                 l(f"    {field_name}: {t0} = {t1}{{{def_val}}} ** {array_sizes[0]},")
-            elif is_const_void_ptr(array_type):
+            elif util.is_const_void_ptr(array_type):
                 l(f"    {field_name}: [{array_sizes[0]}]?*const anyopaque = [_]?*const anyopaque {{ null }} ** {array_sizes[0]},")
             else:
                 sys.exit(f"ERROR gen_struct: array {field_name}: {field_type} => {array_type} [{array_sizes[0]}]")
-        elif is_2d_array_type(field_type):
-            array_type = extract_array_type(field_type)
-            array_sizes = extract_array_sizes(field_type)
+        elif util.is_2d_array_type(field_type):
+            array_type = util.extract_array_type(field_type)
+            array_sizes = util.extract_array_sizes(field_type)
             if is_prim_type(array_type):
                 zig_type = as_zig_prim_type(array_type)
                 def_val = type_default_value(array_type)
@@ -420,7 +371,7 @@ def gen_struct(decl, prefix):
 def gen_consts(decl, prefix):
     for item in decl['items']:
         item_name = check_override(item['name'])
-        l(f"pub const {as_snake_case(item_name, prefix)} = {item['value']};")
+        l(f"pub const {util.as_lower_snake_case(item_name, prefix)} = {item['value']};")
 
 def gen_enum(decl, prefix):
     enum_name = check_override(decl['name'])
@@ -439,7 +390,7 @@ def gen_func_c(decl, prefix):
 
 def gen_func_zig(decl, prefix):
     c_func_name = decl['name']
-    zig_func_name = as_camel_case(check_override(decl['name']), prefix)
+    zig_func_name = util.as_lower_camel_case(check_override(decl['name']), prefix)
     zig_res_type = funcdecl_result_zig(decl, prefix)
     l(f"pub fn {zig_func_name}({funcdecl_args_zig(decl, prefix)}) {zig_res_type} {{")
     if is_zig_string(zig_res_type):
@@ -456,7 +407,7 @@ def gen_func_zig(decl, prefix):
         arg_type = param_decl['type']
         if is_const_struct_ptr(arg_type):
             s += f"&{arg_name}"
-        elif is_string_ptr(arg_type):
+        elif util.is_string_ptr(arg_type):
             s += f"@ptrCast([*c]const u8,{arg_name})"
         else:
             s += arg_name