X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=genbindings.py;h=854717462a4bf478bf05fefbe47f1aebeab6d789;hb=refs%2Fheads%2F2021-03-license;hp=fa75b0fb44e5e8d646fd2630281c78ec6915a01f;hpb=ba97d8dee5ef43b8b61c9a61e30789cdf8eb9c5e;p=ldk-java diff --git a/genbindings.py b/genbindings.py index fa75b0fb..85471746 100755 --- a/genbindings.py +++ b/genbindings.py @@ -14,8 +14,12 @@ else: sys.exit(1) target = None -if sys.argv[6] == "java": +if sys.argv[6] == "java" or sys.argv[6] == "android": + import java_strings from java_strings import Consts + target = java_strings.Target.JAVA + if sys.argv[6] == "android": + target = java_strings.Target.ANDROID elif sys.argv[6] == "typescript": import typescript_strings from typescript_strings import Consts @@ -84,6 +88,7 @@ def java_c_types(fn_arg, ret_arr_len): fn_arg = fn_arg[7:] if fn_arg.startswith("enum "): fn_arg = fn_arg[5:] + nonnull_ptr = "NONNULL_PTR" in fn_arg fn_arg = fn_arg.replace("NONNULL_PTR", "") is_ptr = False @@ -168,11 +173,13 @@ def java_c_types(fn_arg, ret_arr_len): res.pass_by_ref = True if res.is_native_primitive or res.passed_as_ptr: return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=res.java_ty + "[]", java_hu_ty=res.java_hu_ty + "[]", - java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr, is_const=is_const, + java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr, + nonnull_ptr=nonnull_ptr, is_const=is_const, var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False) else: return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=res.java_ty + "[]", java_hu_ty=res.java_hu_ty + "[]", - java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr, is_const=is_const, + java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr, + nonnull_ptr=nonnull_ptr, is_const=is_const, var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False) is_primitive = False @@ -201,7 +208,7 @@ def java_c_types(fn_arg, ret_arr_len): elif fn_arg.startswith("uint16_t"): mapped_type = consts.c_type_map['uint16_t'] java_ty = mapped_type[0] - c_ty = "jshort" + c_ty = "int16_t" fn_ty_arg = "S" fn_arg = fn_arg[8:].strip() is_primitive = True @@ -214,13 +221,15 @@ def java_c_types(fn_arg, ret_arr_len): is_primitive = True elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"): # TODO: uintptr_t is arch-dependent :( - mapped_type = consts.c_type_map['long'] + mapped_type = consts.c_type_map['uint64_t'] java_ty = mapped_type[0] - c_ty = "int64_t" fn_ty_arg = "J" if fn_arg.startswith("uint64_t"): + c_ty = "int64_t" fn_arg = fn_arg[8:].strip() else: + c_ty = "int64_t" + rust_obj = "uintptr_t" fn_arg = fn_arg[9:].strip() is_primitive = True elif is_const and fn_arg.startswith("char *"): @@ -302,7 +311,6 @@ def java_c_types(fn_arg, ret_arr_len): c_ty = consts.ptr_c_ty java_ty = consts.ptr_native_ty fn_ty_arg = "J" - is_primitive = False var_is_arr = var_is_arr_regex.match(fn_arg) if var_is_arr is not None or ret_arr_len is not None: @@ -317,27 +325,25 @@ def java_c_types(fn_arg, ret_arr_len): if var_is_arr is not None: if var_is_arr.group(1) == "": return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const, - passed_as_ptr=False, is_ptr=False, var_name="arg", arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False) + passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", + arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False) return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const, - passed_as_ptr=False, is_ptr=False, var_name=var_is_arr.group(1), arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False) + passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), + arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False) if java_hu_ty is None: java_hu_ty = java_ty return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg=fn_ty_arg, c_ty=c_ty, passed_as_ptr=is_ptr or take_by_ptr, - is_const=is_const, is_ptr=is_ptr, var_name=fn_arg, arr_len=arr_len, arr_access=arr_access, is_native_primitive=is_primitive) + is_const=is_const, is_ptr=is_ptr, nonnull_ptr=nonnull_ptr, var_name=fn_arg, arr_len=arr_len, arr_access=arr_access, is_native_primitive=is_primitive) fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$") fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$") reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$") clone_fns = set() constructor_fns = {} -c_array_class_caches = set() - from gen_type_mapping import TypeMappingGenerator -type_mapping_generator = TypeMappingGenerator(java_c_types, consts, c_array_class_caches, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types) - - +type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types) with open(sys.argv[1]) as in_h: for line in in_h: @@ -347,7 +353,7 @@ with open(sys.argv[1]) as in_h: clone_fns.add(reg_fn.group(2)) else: rty = java_c_types(reg_fn.group(1), None) - if rty is not None and rty.rust_obj is not None and reg_fn.group(2) == rty.java_hu_ty + "_new": + if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new": constructor_fns[rty.rust_obj] = reg_fn.group(3) continue arr_fn = fn_ret_arr_regex.match(line) @@ -363,178 +369,83 @@ write_c("static inline struct LDKThirtyTwoBytes ThirtyTwoBytes_clone(const struc java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order -with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: - def map_fn(line, re_match, ret_arr_len, c_call_string): - out_java.write("\t// " + line) - out_java.write("\tpublic static native ") - write_c(consts.c_fn_ty_pfx) - - is_free = re_match.group(2).endswith("_free") - struct_meth = re_match.group(2).split("_")[0] +with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util: + util.write(consts.util_fn_pfx) - ret_info = type_mapping_generator.map_type(re_match.group(1), True, ret_arr_len, False, False) - write_c(ret_info.c_ty) - out_java.write(ret_info.java_ty) +with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: + # Map a top-level function + def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment): + method_return_type = re_match.group(1) + method_name = re_match.group(2) + method_comma_separated_arguments = re_match.group(3) + method_arguments = method_comma_separated_arguments.split(',') - if ret_info.ret_conv is not None: - ret_conv_pfx, ret_conv_sfx = ret_info.ret_conv + is_free = method_name.endswith("_free") + struct_meth = method_name.split("_")[0] - out_java.write(" " + re_match.group(2) + "(") - write_c(" " + consts.c_fn_name_pfx + re_match.group(2).replace('_', '_1') + "(" + consts.c_fn_args_pfx) + return_type_info = type_mapping_generator.map_type(method_return_type, True, ret_arr_len, False, False) - arg_names = [] + argument_types = [] default_constructor_args = {} takes_self = False args_known = True - for idx, arg in enumerate(re_match.group(3).split(',')): - if idx != 0: - out_java.write(", ") - if arg != "void": - write_c(", ") - arg_conv_info = type_mapping_generator.map_type(arg, False, None, is_free, True) - if arg_conv_info.c_ty != "void": - write_c(arg_conv_info.c_ty + " " + arg_conv_info.arg_name) - out_java.write(arg_conv_info.java_ty + " " + arg_conv_info.arg_name) - if idx == 0 and arg_conv_info.java_hu_ty == struct_meth: + + for argument_index, argument in enumerate(method_arguments): + argument_conversion_info = type_mapping_generator.map_type(argument, False, None, is_free, True) + if argument_index == 0 and argument_conversion_info.java_hu_ty == struct_meth: takes_self = True - if arg_conv_info.arg_conv is not None and "Warning" in arg_conv_info.arg_conv: - if arg_conv_info.rust_obj in constructor_fns: + if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv: + if argument_conversion_info.rust_obj in constructor_fns: assert not is_free - for explode_arg in constructor_fns[arg_conv_info.rust_obj].split(','): + for explode_arg in constructor_fns[argument_conversion_info.rust_obj].split(','): explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True) if explode_arg_conv.c_ty == "void": # We actually want to handle this case, but for now its only used in NetGraphMsgHandler::new() # which ends up resulting in a redundant constructor - both without arguments for the NetworkGraph. args_known = False pass - if not arg_conv_info.arg_name in default_constructor_args: - default_constructor_args[arg_conv_info.arg_name] = [] - default_constructor_args[arg_conv_info.arg_name].append(explode_arg_conv) - arg_names.append(arg_conv_info) + if not argument_conversion_info.arg_name in default_constructor_args: + default_constructor_args[argument_conversion_info.arg_name] = [] + default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv) + argument_types.append(argument_conversion_info) + + out_java.write("\t// " + line) + (out_java_delta, out_c_delta, out_java_struct_delta) = \ + consts.map_function(argument_types, c_call_string, method_name, return_type_info, struct_meth, default_constructor_args, takes_self, args_known, type_mapping_generator, doc_comment) + out_java.write(out_java_delta) + + if is_free: + assert len(argument_types) == 1 + assert return_type_info.c_ty == "void" + write_c(consts.c_fn_ty_pfx + "void " + consts.c_fn_name_define_pfx(method_name, True) + argument_types[0].c_ty + " " + argument_types[0].ty_info.var_name + ") {\n") + if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs: + write_c("\tif ((" + argument_types[0].ty_info.var_name + " & 1) != 0) return;\n") + + for info in argument_types: + if info.arg_conv is not None: + write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n") + assert c_call_string is None + write_c("\t" + method_name + "(") + if argument_types[0].arg_conv_name is not None: + write_c(argument_types[0].arg_conv_name) + write_c(");") + for info in argument_types: + if info.arg_conv_cleanup is not None: + write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t")) + write_c("\n}\n\n") + else: + write_c(out_c_delta) out_java_struct = None if ("LDK" + struct_meth in opaque_structs or "LDK" + struct_meth in trait_structs) and not is_free: out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a") - if not args_known: - out_java_struct.write("\t// Skipped " + re_match.group(2) + "\n") - out_java_struct.close() - out_java_struct = None - else: - meth_n = re_match.group(2)[len(struct_meth) + 1:] - if not takes_self: - out_java_struct.write("\tpublic static " + ret_info.java_hu_ty + " constructor_" + meth_n + "(") - else: - out_java_struct.write("\tpublic " + ret_info.java_hu_ty + " " + meth_n + "(") - for idx, arg in enumerate(arg_names): - if idx != 0: - if not takes_self or idx > 1: - out_java_struct.write(", ") - elif takes_self: - continue - if arg.java_ty != "void": - if arg.arg_name in default_constructor_args: - for explode_idx, explode_arg in enumerate(default_constructor_args[arg.arg_name]): - if explode_idx != 0: - out_java_struct.write(", ") - out_java_struct.write(explode_arg.java_hu_ty + " " + arg.arg_name + "_" + explode_arg.arg_name) - else: - out_java_struct.write(arg.java_hu_ty + " " + arg.arg_name) - - - out_java.write(");\n") - write_c(") {\n") + elif method_name.startswith("C2Tuple_") and method_name.endswith("_read"): + struct_meth = method_name.rsplit("_", 1)[0] + out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") if out_java_struct is not None: - out_java_struct.write(") {\n") - - for info in arg_names: - if info.arg_conv is not None: - write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n") - - if ret_info.ret_conv is not None: - write_c("\t" + ret_conv_pfx.replace('\n', '\n\t')) - elif ret_info.c_ty != "void": - write_c("\t" + ret_info.c_ty + " ret_val = ") - else: - write_c("\t") + out_java_struct.write(out_java_struct_delta) - if c_call_string is None: - write_c(re_match.group(2) + "(") - else: - write_c(c_call_string) - for idx, info in enumerate(arg_names): - if info.arg_conv_name is not None: - if idx != 0: - write_c(", ") - elif c_call_string is not None: - continue - write_c(info.arg_conv_name) - write_c(")") - if ret_info.ret_conv is not None: - write_c(ret_conv_sfx.replace('\n', '\n\t')) - else: - write_c(";") - for info in arg_names: - if info.arg_conv_cleanup is not None: - write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t")) - if ret_info.ret_conv is not None: - write_c("\n\treturn " + ret_info.ret_conv_name + ";") - elif ret_info.c_ty != "void": - write_c("\n\treturn ret_val;") - write_c("\n}\n\n") - if out_java_struct is not None: - out_java_struct.write("\t\t") - if ret_info.java_ty != "void": - out_java_struct.write(ret_info.java_ty + " ret = ") - out_java_struct.write("bindings." + re_match.group(2) + "(") - for idx, info in enumerate(arg_names): - if idx != 0: - out_java_struct.write(", ") - if idx == 0 and takes_self: - out_java_struct.write("this.ptr") - elif info.arg_name in default_constructor_args: - out_java_struct.write("bindings." + info.java_hu_ty + "_new(") - for explode_idx, explode_arg in enumerate(default_constructor_args[info.arg_name]): - if explode_idx != 0: - out_java_struct.write(", ") - expl_arg_name = info.arg_name + "_" + explode_arg.arg_name - if explode_arg.from_hu_conv is not None: - out_java_struct.write(explode_arg.from_hu_conv[0].replace(explode_arg.arg_name, expl_arg_name)) - else: - out_java_struct.write(expl_arg_name) - out_java_struct.write(")") - elif info.from_hu_conv is not None: - out_java_struct.write(info.from_hu_conv[0]) - else: - out_java_struct.write(info.arg_name) - out_java_struct.write(");\n") - if ret_info.to_hu_conv is not None: - if not takes_self: - out_java_struct.write("\t\t" + ret_info.to_hu_conv.replace("\n", "\n\t\t").replace("this", ret_info.to_hu_conv_name) + "\n") - else: - out_java_struct.write("\t\t" + ret_info.to_hu_conv.replace("\n", "\n\t\t") + "\n") - - for idx, info in enumerate(arg_names): - if idx == 0 and takes_self: - pass - elif info.arg_name in default_constructor_args: - for explode_arg in default_constructor_args[info.arg_name]: - expl_arg_name = info.arg_name + "_" + explode_arg.arg_name - if explode_arg.from_hu_conv is not None and ret_info.to_hu_conv_name: - out_java_struct.write("\t\t" + explode_arg.from_hu_conv[1].replace(explode_arg.arg_name, expl_arg_name).replace("this", ret_info.to_hu_conv_name) + ";\n") - elif info.from_hu_conv is not None and info.from_hu_conv[1] != "": - if not takes_self and ret_info.to_hu_conv_name is not None: - out_java_struct.write("\t\t" + info.from_hu_conv[1].replace("this", ret_info.to_hu_conv_name) + ";\n") - else: - out_java_struct.write("\t\t" + info.from_hu_conv[1] + ";\n") - - if ret_info.to_hu_conv_name is not None: - out_java_struct.write("\t\treturn " + ret_info.to_hu_conv_name + ";\n") - elif ret_info.java_ty != "void" and ret_info.rust_obj != "LDK" + struct_meth: - out_java_struct.write("\t\treturn ret;\n") - out_java_struct.write("\t}\n\n") - out_java_struct.close() - - def map_unitary_enum(struct_name, field_lines): + def map_unitary_enum(struct_name, field_lines, enum_doc_comment): with open(f"{sys.argv[3]}/enums/{struct_name}{consts.file_ext}", "w") as out_java_enum: unitary_enums.add(struct_name) for idx, struct_line in enumerate(field_lines): @@ -546,12 +457,12 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: assert(struct_line == "} %s;" % struct_name) elif idx == len(field_lines) - 1: assert(struct_line == "") - (c_out, native_file_out, native_out) = consts.native_c_unitary_enum_map(struct_name, [x.strip().strip(",") for x in field_lines[1:-3]]) + (c_out, native_file_out, native_out) = consts.native_c_unitary_enum_map(struct_name, [x.strip().strip(",") for x in field_lines[1:-3]], enum_doc_comment) write_c(c_out) out_java_enum.write(native_file_out) out_java.write(native_out) - def map_complex_enum(struct_name, union_enum_items): + def map_complex_enum(struct_name, union_enum_items, enum_doc_comment): java_hu_type = struct_name.replace("LDK", "") complex_enums.add(struct_name) @@ -583,13 +494,13 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: enum_variants.append(ComplexEnumVariantInfo(variant_name, fields)) with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum: - (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake) + (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment) out_java_enum.write(out_java_enum_addendum) out_java.write(out_java_addendum) write_c(out_c_addendum) - def map_trait(struct_name, field_var_lines, trait_fn_lines): + def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment): with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait: field_var_convs = [] for var_line in field_var_lines: @@ -600,7 +511,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)) field_fns = [] - for fn_line in trait_fn_lines: + for fn_docs, fn_line in trait_fn_lines: ret_ty_info = type_mapping_generator.map_type(fn_line.group(2), True, None, False, False) is_const = fn_line.group(4) is not None @@ -610,19 +521,19 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: continue arg_conv_info = type_mapping_generator.map_type(arg, True, None, False, False) arg_tys.append(arg_conv_info) - field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys)) + field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs)) - (out_java_addendum, out_java_trait_addendum, out_c_addendum) = consts.native_c_map_trait(struct_name, field_var_convs, field_fns) + (out_java_addendum, out_java_trait_addendum, out_c_addendum) = consts.native_c_map_trait(struct_name, field_var_convs, field_fns, trait_doc_comment) write_c(out_c_addendum) out_java_trait.write(out_java_trait_addendum) out_java.write(out_java_addendum) - for fn_line in trait_fn_lines: + for fn_docs, fn_line in trait_fn_lines: # For now, just disable enabling the _call_log - we don't know how to inverse-map String is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger" if fn_line.group(3) != "free" and fn_line.group(3) != "clone" and fn_line.group(3) != "eq" and not is_log: - dummy_line = fn_line.group(2) + struct_name.replace("LDK", "") + "_" + fn_line.group(3) + " " + struct_name + "* this_arg" + fn_line.group(5) + "\n" - map_fn(dummy_line, re.compile("([A-Za-z_0-9]*) *([A-Za-z_0-9]*) *(.*)").match(dummy_line), None, "(this_arg_conv->" + fn_line.group(3) + ")(this_arg_conv->this_arg") + dummy_line = fn_line.group(2) + struct_name.replace("LDK", "") + "_" + fn_line.group(3) + " " + struct_name + " *NONNULL_PTR this_arg" + fn_line.group(5) + "\n" + map_fn(dummy_line, re.compile("([A-Za-z_0-9]*) *([A-Za-z_0-9]*) *(.*)").match(dummy_line), None, "(this_arg_conv->" + fn_line.group(3) + ")(this_arg_conv->this_arg", fn_docs) for idx, var_line in enumerate(field_var_lines): if var_line.group(1) not in trait_structs: write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n") @@ -630,8 +541,8 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n") write_c("\treturn this_arg->" + var_line.group(2) + ";\n") write_c("}\n") - dummy_line = var_line.group(1) + " " + struct_name.replace("LDK", "") + "_get_" + var_line.group(2) + " " + struct_name + "* this_arg" + fn_line.group(5) + "\n" - map_fn(dummy_line, re.compile("([A-Za-z_0-9]*) *([A-Za-z_0-9]*) *(.*)").match(dummy_line), None, struct_name + "_set_get_" + var_line.group(2) + "(this_arg_conv") + dummy_line = var_line.group(1) + " " + struct_name.replace("LDK", "") + "_get_" + var_line.group(2) + " " + struct_name + " *NONNULL_PTR this_arg" + fn_line.group(5) + "\n" + map_fn(dummy_line, re.compile("([A-Za-z_0-9]*) *([A-Za-z_0-9]*) *(.*)").match(dummy_line), None, struct_name + "_set_get_" + var_line.group(2) + "(this_arg_conv", fn_docs) def map_result(struct_name, res_ty, err_ty): result_types.add(struct_name) @@ -660,13 +571,13 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: can_clone = False out_java.write("\tpublic static native boolean " + struct_name + "_result_ok(long arg);\n") - write_c(consts.c_fn_ty_pfx + "jboolean " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1result_1ok (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " arg) {\n") + write_c(consts.c_fn_ty_pfx + "jboolean " + consts.c_fn_name_define_pfx(struct_name + "_result_ok", True) + consts.ptr_c_ty + " arg) {\n") write_c("\treturn ((" + struct_name + "*)arg)->result_ok;\n") write_c("}\n") out_java.write("\tpublic static native " + res_map.java_ty + " " + struct_name + "_get_ok(long arg);\n") - write_c(consts.c_fn_ty_pfx + res_map.c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1ok (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " arg) {\n") - write_c("\t" + struct_name + " *val = (" + struct_name + "*)arg;\n") + write_c(consts.c_fn_ty_pfx + res_map.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_ok", True) + consts.ptr_c_ty + " arg) {\n") + write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n") write_c("\tCHECK(val->result_ok);\n\t") out_java_struct.write("\tpublic static final class " + human_ty + "_OK extends " + human_ty + " {\n") if res_map.ret_conv is not None: @@ -696,14 +607,14 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: if res_map.from_hu_conv is not None: out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_ok(" + res_map.from_hu_conv[0] + "));\n") if res_map.from_hu_conv[1] != "": - out_java_struct.write("\t\t\t" + res_map.from_hu_conv[1] + ";\n") + out_java_struct.write("\t\t\t" + res_map.from_hu_conv[1].replace("\n", "\n\t\t\t") + ";\n") else: out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_ok(res));\n") out_java_struct.write("\t\t}\n\t}\n\n") out_java.write("\tpublic static native " + err_map.java_ty + " " + struct_name + "_get_err(long arg);\n") - write_c(consts.c_fn_ty_pfx + err_map.c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1err (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " arg) {\n") - write_c("\t" + struct_name + " *val = (" + struct_name + "*)arg;\n") + write_c(consts.c_fn_ty_pfx + err_map.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_err", True) + consts.ptr_c_ty + " arg) {\n") + write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n") write_c("\tCHECK(!val->result_ok);\n\t") out_java_struct.write("\tpublic static final class " + human_ty + "_Err extends " + human_ty + " {\n") if err_map.ret_conv is not None: @@ -734,59 +645,29 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: if err_map.from_hu_conv is not None: out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_err(" + err_map.from_hu_conv[0] + "));\n") if err_map.from_hu_conv[1] != "": - out_java_struct.write("\t\t\t" + err_map.from_hu_conv[1] + ";\n") + out_java_struct.write("\t\t\t" + err_map.from_hu_conv[1].replace("\n", "\n\t\t\t") + ";\n") else: out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_err(err));\n") out_java_struct.write("\t\t}\n\t}\n}\n") - if can_clone: - clone_fns.add(struct_name.replace("LDK", "") + "_clone") - write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n") - write_c("\t" + struct_name + " res = { .result_ok = orig->result_ok };\n") - write_c("\tif (orig->result_ok) {\n") - if res_map.c_ty == "void": - write_c("\t\tres.contents.result = NULL;\n") - else: - if res_map.is_native_primitive: - write_c("\t\t" + res_map.c_ty + "* contents = MALLOC(sizeof(" + res_map.c_ty + "), \"" + res_map.c_ty + " result OK clone\");\n") - write_c("\t\t*contents = *orig->contents.result;\n") - else: - write_c("\t\t" + res_map.rust_obj + "* contents = MALLOC(sizeof(" + res_map.rust_obj + "), \"" + res_map.rust_obj + " result OK clone\");\n") - write_c("\t\t*contents = " + res_map.rust_obj.replace("LDK", "") + "_clone(orig->contents.result);\n") - write_c("\t\tres.contents.result = contents;\n") - write_c("\t} else {\n") - if err_map.c_ty == "void": - write_c("\t\tres.contents.err = NULL;\n") - else: - if err_map.is_native_primitive: - write_c("\t\t" + err_map.c_ty + "* contents = MALLOC(sizeof(" + err_map.c_ty + "), \"" + err_map.c_ty + " result Err clone\");\n") - write_c("\t\t*contents = *orig->contents.err;\n") - else: - write_c("\t\t" + err_map.rust_obj + "* contents = MALLOC(sizeof(" + err_map.rust_obj + "), \"" + err_map.rust_obj + " result Err clone\");\n") - write_c("\t\t*contents = " + err_map.rust_obj.replace("LDK", "") + "_clone(orig->contents.err);\n") - write_c("\t\tres.contents.err = contents;\n") - write_c("\t}\n\treturn res;\n}\n") - def map_tuple(struct_name, field_lines): out_java.write("\tpublic static native long " + struct_name + "_new(") - write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1new(" + consts.c_fn_args_pfx) + write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_new", len(field_lines) > 3)) ty_list = [] for idx, line in enumerate(field_lines): if idx != 0 and idx < len(field_lines) - 2: ty_info = java_c_types(line.strip(';'), None) if idx != 1: out_java.write(", ") + write_c(", ") e = chr(ord('a') + idx - 1) out_java.write(ty_info.java_ty + " " + e) - write_c(", " + ty_info.c_ty + " " + e) + write_c(ty_info.c_ty + " " + e) ty_list.append(ty_info) tuple_types[struct_name] = (ty_list, struct_name) out_java.write(");\n") write_c(") {\n") write_c("\t" + struct_name + "* ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n") - can_clone = True - clone_str = "static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n" - clone_str = clone_str + "\t" + struct_name + " ret = {\n" for idx, line in enumerate(field_lines): if idx != 0 and idx < len(field_lines) - 2: ty_info = type_mapping_generator.map_type(line.strip(';'), False, None, False, False) @@ -798,25 +679,14 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: write_c("\tret->" + e + " = " + e + ";\n") if ty_info.arg_conv_cleanup is not None: write_c("\t//TODO: Really need to call " + ty_info.arg_conv_cleanup + " here\n") - if not ty_info.is_native_primitive and (ty_info.rust_obj.replace("LDK", "") + "_clone") not in clone_fns: - can_clone = False - elif can_clone and ty_info.is_native_primitive: - clone_str = clone_str + "\t\t." + chr(ord('a') + idx - 1) + " = orig->" + chr(ord('a') + idx - 1) + ",\n" - elif can_clone: - clone_str = clone_str + "\t\t." + chr(ord('a') + idx - 1) + " = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->" + chr(ord('a') + idx - 1) + "),\n" write_c("\treturn (long)ret;\n") write_c("}\n") - if can_clone: - clone_fns.add(struct_name.replace("LDK", "") + "_clone") - write_c(clone_str) - write_c("\t};\n\treturn ret;\n}\n") - for idx, ty_info in enumerate(ty_list): e = chr(ord('a') + idx) out_java.write("\tpublic static native " + ty_info.java_ty + " " + struct_name + "_get_" + e + "(long ptr);\n") - write_c(consts.c_fn_ty_pfx + ty_info.c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1" + e + "(" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " ptr) {\n") - write_c("\t" + struct_name + " *tuple = (" + struct_name + "*)ptr;\n") + write_c(consts.c_fn_ty_pfx + ty_info.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_" + e, True) + consts.ptr_c_ty + " ptr) {\n") + write_c("\t" + struct_name + " *tuple = (" + struct_name + "*)(ptr & ~1);\n") conv_info = type_mapping_generator.map_type_with_info(ty_info, False, None, False, True) if conv_info.ret_conv is not None: write_c("\t" + conv_info.ret_conv[0].replace("\n", "\n\t") + "tuple->" + e + conv_info.ret_conv[1].replace("\n", "\n\t") + "\n") @@ -830,7 +700,8 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct: out_java_struct.write(consts.common_base) - in_block_comment = False + block_comment = None + last_block_comment = None cur_block_obj = None const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$") @@ -853,9 +724,12 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: union_enum_items = {} result_ptr_struct_items = {} for line in in_h: - if in_block_comment: + if block_comment is not None: if line.endswith("*/\n"): - in_block_comment = False + last_block_comment = block_comment.strip("\n") + block_comment = None + else: + block_comment = block_comment + line.strip(" /*") elif cur_block_obj is not None: cur_block_obj = cur_block_obj + line if line.startswith("} "): @@ -874,10 +748,13 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: for idx, struct_line in enumerate(obj_lines): if struct_line.strip().startswith("/*"): - in_block_comment = True - if in_block_comment: + block_comment = struct_line.strip(" /*") + if block_comment is not None: if struct_line.endswith("*/"): - in_block_comment = False + last_struct_block_comment = block_comment.strip("\n") + block_comment = None + else: + block_comment = block_comment + "\n" + struct_line.strip(" /*") else: struct_name_match = struct_name_regex.match(struct_line) if struct_name_match is not None: @@ -901,7 +778,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: is_tuple = True trait_fn_match = line_indicates_trait_regex.match(struct_line) if trait_fn_match is not None: - trait_fn_lines.append(trait_fn_match) + trait_fn_lines.append((last_struct_block_comment, trait_fn_match)) field_var_match = line_field_var_regex.match(struct_line) if field_var_match is not None: field_var_lines.append(field_var_match) @@ -919,7 +796,8 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: if is_opaque: opaque_structs.add(struct_name) with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct: - out_opaque_struct_human = consts.map_opaque_struct(struct_name) + out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment) + last_block_comment = None out_java_struct.write(out_opaque_struct_human) elif result_contents is not None: assert result_contents in result_ptr_struct_items @@ -939,14 +817,15 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False) if len(ty_info.java_fn_ty_arg) == 1: # ie we're a primitive of some form out_java.write("\tpublic static native long " + struct_name + "_new(" + ty_info.java_ty + "[] elems);\n") - write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1new(" + consts.c_fn_args_pfx + ", " + ty_info.c_ty + "Array elems) {\n") + write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_new", True) + ty_info.c_ty + "Array elems) {\n") write_c("\t" + struct_name + " *ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n") write_c("\tret->datalen = " + consts.get_native_arr_len_call[0] + "elems" + consts.get_native_arr_len_call[1] + ";\n") write_c("\tif (ret->datalen == 0) {\n") write_c("\t\tret->data = NULL;\n") write_c("\t} else {\n") write_c("\t\tret->data = MALLOC(sizeof(" + vec_ty + ") * ret->datalen, \"" + struct_name + " Data\");\n") - write_c("\t\t" + ty_info.c_ty + " *java_elems = " + consts.get_native_arr_ptr_call[0] + "elems" + consts.get_native_arr_ptr_call[1] + ";\n") + native_arr_ptr_call = consts.get_native_arr_ptr_call(ty_info.ty_info) + write_c("\t\t" + ty_info.c_ty + " *java_elems = " + native_arr_ptr_call[0] + "elems" + native_arr_ptr_call[1] + ";\n") write_c("\t\tfor (size_t i = 0; i < ret->datalen; i++) {\n") if ty_info.arg_conv is not None: write_c("\t\t\t" + ty_info.c_ty + " arr_elem = java_elems[i];\n") @@ -956,7 +835,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: else: write_c("\t\t\tret->data[i] = java_elems[i];\n") write_c("\t\t}\n") - cleanup = consts.release_native_arr_ptr_call("elems", "java_elems") + cleanup = consts.release_native_arr_ptr_call(ty_info.ty_info, "elems", "java_elems") if cleanup is not None: write_c("\t\t" + cleanup + ";\n") write_c("\t}\n") @@ -985,12 +864,14 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: enum_var_name = struct_name.split("_") union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines elif struct_name in union_enum_items: - map_complex_enum(struct_name, union_enum_items[struct_name]) + map_complex_enum(struct_name, union_enum_items[struct_name], last_block_comment) + last_block_comment = None elif is_unitary_enum: - map_unitary_enum(struct_name, field_lines) + map_unitary_enum(struct_name, field_lines, last_block_comment) + last_block_comment = None elif len(trait_fn_lines) > 0: trait_structs.add(struct_name) - map_trait(struct_name, field_var_lines, trait_fn_lines) + map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment) elif struct_name == "LDKTxOut": with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct: out_java_struct.write(consts.hu_struct_file_prefix) @@ -1016,9 +897,8 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: if line.startswith("#include <"): pass elif line.startswith("/*"): - #out_java.write("\t" + line) if not line.endswith("*/\n"): - in_block_comment = True + block_comment = line.strip(" /*") elif line.startswith("typedef enum "): cur_block_obj = line elif line.startswith("typedef struct "): @@ -1026,25 +906,31 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: elif line.startswith("typedef union "): cur_block_obj = line elif fn_ptr is not None: - map_fn(line, fn_ptr, None, None) + map_fn(line, fn_ptr, None, None, last_block_comment) + last_block_comment = None elif fn_ret_arr is not None: - map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None) + map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment) + last_block_comment = None elif reg_fn is not None: - map_fn(line, reg_fn, None, None) + map_fn(line, reg_fn, None, None, last_block_comment) + last_block_comment = None elif const_val_regex is not None: # TODO Map const variables pass else: assert(line == "\n") - out_java.write("}\n") + out_java.write(consts.bindings_footer) for struct_name in opaque_structs: with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct: out_java_struct.write("}\n") for struct_name in trait_structs: with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct: out_java_struct.write("}\n") + with open(sys.argv[4], "w") as out_c: out_c.write(consts.c_file_pfx) - out_c.write(consts.init_str(c_array_class_caches)) + out_c.write(consts.init_str()) out_c.write(c_file) +with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util: + util.write(consts.util_fn_sfx)