diff options
| author | Andre Weissflog <floooh@gmail.com> | 2022-07-17 11:37:06 +0200 |
|---|---|---|
| committer | Andre Weissflog <floooh@gmail.com> | 2022-07-17 11:37:06 +0200 |
| commit | d4b7879cb81010103cb3484f60eb9ed6aaac916b (patch) | |
| tree | 69fa1f8a37697caa29e4cb17340d538f1b0a2ed4 /bindgen | |
| parent | f9427e5fbddbeb30271409817f7cd97acc0dbfab (diff) | |
gen_odin.py: generate structs
Diffstat (limited to 'bindgen')
| -rw-r--r-- | bindgen/gen_odin.py | 155 |
1 files changed, 87 insertions, 68 deletions
diff --git a/bindgen/gen_odin.py b/bindgen/gen_odin.py index 9a06bb66..22b1d169 100644 --- a/bindgen/gen_odin.py +++ b/bindgen/gen_odin.py @@ -228,61 +228,54 @@ def extract_ptr_type(s): else: return tokens[0] -def as_c_arg_type(arg_type, prefix): - if arg_type == "void": +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}") + if type == "void": return "" - elif is_prim_type(arg_type): - return as_prim_type(arg_type) - elif is_struct_type(arg_type): - return as_struct_or_enum_type(arg_type, prefix) - elif is_enum_type(arg_type): - return as_struct_or_enum_type(arg_type, prefix) - elif is_void_ptr(arg_type): + elif is_prim_type(type): + if sub_type == 'odin_arg': + # for Odin args, maps C int (32-bit) to Odin int (pointer-sized), + # and the C bool type to Odin's bool type + if type == 'int': + return 'int' + elif type == 'bool': + return 'bool' + return as_prim_type(type) + elif is_struct_type(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): return "rawptr" - elif is_const_void_ptr(arg_type): + elif is_const_void_ptr(type): return "rawptr" - elif is_string_ptr(arg_type): + elif is_string_ptr(type): return "cstring" - elif is_const_struct_ptr(arg_type): - return f"^{as_struct_or_enum_type(extract_ptr_type(arg_type), prefix)}" - elif is_prim_ptr(arg_type): - return f"^{as_prim_type(extract_ptr_type(arg_type))}" - elif is_const_prim_ptr(arg_type): - return f"^{as_prim_type(extract_ptr_type(arg_type))}" - else: - sys.exit(f"Error as_c_arg_type(): {arg_type}") - -def as_odin_arg_type(arg_type, prefix): - if arg_type == "void": - return "" - elif is_prim_type(arg_type): - # for args and return values we'll map the C int type (32-bit) to Odin's pointer-sized int type, - # and the C bool type to Odin's 'unsized' bool type - if arg_type == 'int': - return 'int' - elif arg_type == 'bool': - return 'bool' + 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)}" else: - return as_prim_type(arg_type) - elif is_struct_type(arg_type): - return as_struct_or_enum_type(arg_type, prefix) - elif is_enum_type(arg_type): - return as_struct_or_enum_type(arg_type, prefix) - elif is_void_ptr(arg_type): - return "rawptr" - elif is_const_void_ptr(arg_type): - return "rawptr" - elif is_string_ptr(arg_type): - return "cstring" - elif is_const_struct_ptr(arg_type): - # not a bug, pass structs by value - return f"{as_struct_or_enum_type(extract_ptr_type(arg_type), prefix)}" - elif is_prim_ptr(arg_type): - return f"^{as_prim_type(extract_ptr_type(arg_type))}" - elif is_const_prim_ptr(arg_type): - return f"^{as_prim_type(extract_ptr_type(arg_type))}" + return f"^{as_struct_or_enum_type(extract_ptr_type(type), prefix)}" + elif is_prim_ptr(type): + return f"^{as_prim_type(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"[{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) + return f"[{array_sizes[0]}][{array_sizes[1]}]{map_type(array_type, prefix, sub_type)}" + elif 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}' else: - sys.exit(f"Error as_odin_arg_type(): {arg_type}") + sys.exit(f"Error map_type(): unknown type '{type}'") def funcdecl_args_c(decl, prefix): s = '' @@ -292,7 +285,7 @@ def funcdecl_args_c(decl, prefix): s += ', ' param_name = param_decl['name'] param_type = check_override(f'{func_name}.{param_name}', default=param_decl['type']) - s += f"{param_name}: {as_c_arg_type(param_type, prefix)}" + s += f"{param_name}: {map_type(param_type, prefix, 'c_arg')}" return s def funcdecl_args_odin(decl, prefix): @@ -303,20 +296,40 @@ def funcdecl_args_odin(decl, prefix): s += ', ' param_name = param_decl['name'] param_type = check_override(f'{func_name}.{param_name}', default=param_decl['type']) - s += f"{param_name}: {as_odin_arg_type(param_type, prefix)}" + s += f"{param_name}: {map_type(param_type, prefix, 'odin_arg')}" + return s + +def funcptr_args_c(field_type, prefix): + tokens = field_type[field_type.index('(*)')+4:-1].split(',') + s = '' + arg_index = 0; + for token in tokens: + arg_type = token.strip() + if s != '': + s += ', ' + c_arg = map_type(arg_type, prefix, 'c_arg') + if c_arg == '': + return '' + else: + s += f'a{arg_index}: {c_arg}' + arg_index += 1 return s +def funcptr_result_c(field_type, prefix): + res_type = field_type[:field_type.index('(*)')].strip() + return map_type(res_type, prefix, 'c_arg') + def funcdecl_result_c(decl, prefix): func_name = decl['name'] decl_type = decl['type'] res_c_type = decl_type[:decl_type.index('(')].strip() - return as_c_arg_type(check_override(f'{func_name}.RESULT', default=res_c_type), prefix) + return map_type(check_override(f'{func_name}.RESULT', default=res_c_type), prefix, 'c_arg') def funcdecl_result_odin(decl, prefix): func_name = decl['name'] decl_type = decl['type'] res_c_type = decl_type[:decl_type.index('(')].strip() - return as_odin_arg_type(check_override(f'{func_name}.RESULT', default=res_c_type), prefix) + return map_type(check_override(f'{func_name}.RESULT', default=res_c_type), prefix, 'odin_arg') def gen_c_imports(inp): l(f'// FIXME: foreign import...\n') @@ -326,9 +339,9 @@ def gen_c_imports(inp): for decl in inp['decls']: if decl['kind'] == 'func' and not decl['is_dep'] and not check_ignore(decl['name']): args = funcdecl_args_c(decl, prefix) - ret_type = funcdecl_result_c(decl, prefix) - ret_str = '' if ret_type == '' else f'-> {ret_type}' - l(f" {decl['name']} :: proc({args}) {ret_str} ---") + res_type = funcdecl_result_c(decl, prefix) + res_str = '' if res_type == '' else f'-> {res_type}' + l(f" {decl['name']} :: proc({args}) {res_str} ---") l('}') def gen_consts(decl, prefix): @@ -337,8 +350,14 @@ def gen_consts(decl, prefix): l(f"{as_snake_case(item_name, prefix)} :: {item['value']};") def gen_struct(decl, prefix): - # FIXME - l(f'// FIXME: struct {decl["name"]}') + c_struct_name = check_override(decl['name']) + struct_name = as_struct_or_enum_type(c_struct_name, prefix) + l(f'{struct_name} :: struct {{') + for field in decl['fields']: + field_name = check_override(field['name']) + field_type = map_type(check_override(f'{struct_name}.{field_name}', default=field['type']), prefix, 'struct_field') + l(f' {field_name} : {field_type},') + l('};') def gen_enum(decl, prefix): enum_name = check_override(decl['name']) @@ -355,20 +374,20 @@ def gen_enum(decl, prefix): def gen_func(decl, prefix): c_func_name = decl['name'] args = funcdecl_args_odin(decl, prefix) - ret_type = funcdecl_result_odin(decl, prefix) - ret_str = '' if ret_type == '' else f'-> {ret_type}' - if ret_type != funcdecl_result_c(decl, prefix): + res_type = funcdecl_result_odin(decl, prefix) + res_str = '' if res_type == '' else f'-> {res_type}' + if res_type != funcdecl_result_c(decl, prefix): # cast needed for return type - ret_cast = f'cast({ret_type})' + res_cast = f'cast({res_type})' else: - ret_cast = '' - l(f"{as_snake_case(decl['name'], prefix)} :: proc({args}) {ret_str} {{") + res_cast = '' + l(f"{as_snake_case(decl['name'], prefix)} :: proc({args}) {res_str} {{") s = ' ' - if ret_type == '': + if res_type == '': # void result s += f"{c_func_name}(" else: - s += f"return {ret_cast}{c_func_name}(" + s += f"return {res_cast}{c_func_name}(" for i, param_decl in enumerate(decl['params']): if i > 0: s += ', ' @@ -377,8 +396,8 @@ def gen_func(decl, prefix): if is_const_struct_ptr(arg_type): s += f"&{arg_name}" else: - odin_arg_type = as_odin_arg_type(arg_type, prefix) - c_arg_type = as_c_arg_type(arg_type, prefix) + odin_arg_type = map_type(arg_type, prefix, 'odin_arg') + c_arg_type = map_type(arg_type, prefix, 'c_arg') if odin_arg_type != c_arg_type: cast = f'cast({c_arg_type})' else: |