diff options
| author | Andre Weissflog <floooh@gmail.com> | 2022-11-03 18:41:41 +0100 |
|---|---|---|
| committer | Andre Weissflog <floooh@gmail.com> | 2022-11-03 18:41:41 +0100 |
| commit | 471f125e0aaa0b5c1201c754812c14cbb8b98ff1 (patch) | |
| tree | e80e328852e9a34c158c72e9e96263c75c82e6b5 | |
| parent | 818d12e9970fd47e4ded16666bb5585717d22842 (diff) | |
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
| -rw-r--r-- | bindgen/gen_nim.py | 72 | ||||
| -rw-r--r-- | bindgen/gen_odin.py | 68 | ||||
| -rw-r--r-- | bindgen/gen_util.py | 57 | ||||
| -rw-r--r-- | bindgen/gen_zig.py | 113 |
4 files changed, 123 insertions, 187 deletions
diff --git a/bindgen/gen_nim.py b/bindgen/gen_nim.py index e66b46f2..06e5b641 100644 --- a/bindgen/gen_nim.py +++ b/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}]] =') diff --git a/bindgen/gen_odin.py b/bindgen/gen_odin.py index 00f6f083..65703815 100644 --- a/bindgen/gen_odin.py +++ b/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) - - - diff --git a/bindgen/gen_util.py b/bindgen/gen_util.py new file mode 100644 index 00000000..a76f4b2b --- /dev/null +++ b/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 diff --git a/bindgen/gen_zig.py b/bindgen/gen_zig.py index 84a95147..aff1a65a 100644 --- a/bindgen/gen_zig.py +++ b/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 |