X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=genbindings.py;h=35a3be01a2259b1a4f9ec596da93763c4eef9516;hb=b1216b13577d42952013c14c88c1155eb6c6499f;hp=2d6771c30d792786873456ff9fd98884d284ec84;hpb=7dd1685ed3de4a8464e84fa277adabab513d9f13;p=ldk-java diff --git a/genbindings.py b/genbindings.py index 2d6771c3..35a3be01 100755 --- a/genbindings.py +++ b/genbindings.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -import sys, re +import os, sys, re, subprocess if len(sys.argv) < 7: print("USAGE: /path/to/lightning.h /path/to/bindings/output /path/to/bindings/ /path/to/bindings/output.c debug lang") @@ -33,6 +33,10 @@ else: consts = Consts(DEBUG, target=target) +local_git_version = os.getenv("LDK_GARBAGECOLLECTED_GIT_OVERRIDE") +if local_git_version is None: + local_git_version = subprocess.check_output(["git", "describe", '--tag', '--dirty']).decode("utf-8").strip() + from bindingstypes import * c_file = "" @@ -69,7 +73,7 @@ def camel_to_snake(s): unitary_enums = set() complex_enums = set() opaque_structs = set() -trait_structs = set() +trait_structs = {} result_types = set() tuple_types = {} @@ -101,6 +105,11 @@ def java_c_types(fn_arg, ret_arr_len): assert var_is_arr_regex.match(fn_arg[8:]) rust_obj = "LDKThirtyTwoBytes" arr_access = "data" + elif fn_arg.startswith("LDKTxid"): + fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]" + assert var_is_arr_regex.match(fn_arg[8:]) + rust_obj = "LDKThirtyTwoBytes" + arr_access = "data" elif fn_arg.startswith("LDKPublicKey"): fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]" assert var_is_arr_regex.match(fn_arg[8:]) @@ -116,6 +125,11 @@ def java_c_types(fn_arg, ret_arr_len): assert var_is_arr_regex.match(fn_arg[8:]) rust_obj = "LDKSignature" arr_access = "compact_form" + elif fn_arg.startswith("LDKRecoverableSignature"): + fn_arg = "uint8_t (*" + fn_arg[25:] + ")[68]" + assert var_is_arr_regex.match(fn_arg[8:]) + rust_obj = "LDKRecoverableSignature" + arr_access = "serialized_form" elif fn_arg.startswith("LDKThreeBytes"): fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]" assert var_is_arr_regex.match(fn_arg[8:]) @@ -131,6 +145,11 @@ def java_c_types(fn_arg, ret_arr_len): assert var_is_arr_regex.match(fn_arg[8:]) rust_obj = "LDKSixteenBytes" arr_access = "data" + elif fn_arg.startswith("LDKTwentyBytes"): + fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]" + assert var_is_arr_regex.match(fn_arg[8:]) + rust_obj = "LDKTwentyBytes" + arr_access = "data" elif fn_arg.startswith("LDKTenBytes"): fn_arg = "uint8_t (*" + fn_arg[12:] + ")[10]" assert var_is_arr_regex.match(fn_arg[8:]) @@ -146,7 +165,7 @@ def java_c_types(fn_arg, ret_arr_len): rust_obj = "LDKCVec_u8Z" assert var_is_arr_regex.match(fn_arg[8:]) arr_access = "data" - elif fn_arg.startswith("LDKTransaction"): + elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction": fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]" rust_obj = "LDKTransaction" assert var_is_arr_regex.match(fn_arg[8:]) @@ -205,6 +224,13 @@ def java_c_types(fn_arg, ret_arr_len): fn_ty_arg = "B" fn_arg = fn_arg[7:].strip() is_primitive = True + elif fn_arg.startswith("LDKu5"): + java_ty = consts.c_type_map['uint8_t'][0] + java_hu_ty = "UInt5" + rust_obj = "LDKu5" + c_ty = "int8_t" + fn_ty_arg = "B" + fn_arg = fn_arg[6:].strip() elif fn_arg.startswith("uint16_t"): mapped_type = consts.c_type_map['uint16_t'] java_ty = mapped_type[0] @@ -238,6 +264,7 @@ def java_c_types(fn_arg, ret_arr_len): fn_ty_arg = "Ljava/lang/String;" fn_arg = fn_arg[6:].strip() elif fn_arg.startswith("LDKStr"): + rust_obj = "LDKStr" java_ty = "String" c_ty = "jstring" fn_ty_arg = "Ljava/lang/String;" @@ -247,9 +274,11 @@ def java_c_types(fn_arg, ret_arr_len): else: ma = var_ty_regex.match(fn_arg) if ma.group(1).strip() in unitary_enums: - java_ty = ma.group(1).strip() + assert ma.group(1).strip().startswith("LDK") + java_ty = ma.group(1).strip()[3:] + java_hu_ty = java_ty c_ty = consts.result_c_ty - fn_ty_arg = "Lorg/ldk/enums/" + ma.group(1).strip() + ";" + fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";" fn_arg = ma.group(2).strip() rust_obj = ma.group(1).strip() elif ma.group(1).strip().startswith("LDKC2Tuple"): @@ -377,26 +406,30 @@ 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, doc_comment): method_return_type = re_match.group(1) method_name = re_match.group(2) + orig_method_name = str(method_name) method_comma_separated_arguments = re_match.group(3) method_arguments = method_comma_separated_arguments.split(',') is_free = method_name.endswith("_free") - if method_name.startswith("COption"): + if method_name.startswith("COption") or method_name.startswith("CResult"): struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z" else: struct_meth = method_name.split("_")[0] - return_type_info = type_mapping_generator.map_type(method_return_type, True, ret_arr_len, False, False) + return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, False) argument_types = [] default_constructor_args = {} takes_self = False + takes_self_ptr = False args_known = True 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 argument_conversion_info.ty_info.is_ptr: + takes_self_ptr = True 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 @@ -411,10 +444,14 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: 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) + if not takes_self and return_type_info.java_hu_ty != struct_meth: + if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth): + method_name = orig_method_name + struct_meth = "" 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) + consts.map_function(argument_types, c_call_string, method_name, return_type_info, struct_meth, default_constructor_args, takes_self, takes_self_ptr, args_known, type_mapping_generator, doc_comment) out_java.write(out_java_delta) if is_free: @@ -440,17 +477,29 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: write_c(out_c_delta) out_java_struct = None - if ("LDK" + struct_meth in opaque_structs or "LDK" + struct_meth in trait_structs - or "LDK" + struct_meth in complex_enums or "LDKC" + struct_meth in complex_enums) and not is_free: + expected_struct = "LDK" + struct_meth + expected_cstruct = "LDKC" + struct_meth + if (expected_struct in opaque_structs or expected_struct in trait_structs + or expected_struct in complex_enums or expected_cstruct in complex_enums + or expected_cstruct in result_types) and not is_free: out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a") - 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(out_java_struct_delta) + elif (not is_free and not method_name.endswith("_clone") and + not method_name.startswith("_") and + method_name != "check_platform" and method_name != "Result_read" and + not expected_struct in unitary_enums and + ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_")) + or method_name.endswith("_read"))): + out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") + for line in out_java_struct_delta.splitlines(): + if not line.strip().startswith("this."): + out_java_struct.write(line + "\n") + else: + out_java_struct.write("\t\t// " + line.strip() + "\n") 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: + assert struct_name.startswith("LDK") + with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum: unitary_enums.add(struct_name) for idx, struct_line in enumerate(field_lines): if idx == 0: @@ -461,12 +510,13 @@ 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]], enum_doc_comment) + assert struct_name.startswith("LDK") + (c_out, native_file_out, native_out) = consts.native_c_unitary_enum_map(struct_name[3:], [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, enum_doc_comment): + def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment): java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option") complex_enums.add(struct_name) @@ -487,15 +537,14 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: if "LDK" + variant_name in union_enum_items: enum_var_lines = union_enum_items["LDK" + variant_name] for idx, field in enumerate(enum_var_lines): - if idx != 0 and idx < len(enum_var_lines) - 2: + if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "": fields.append(type_mapping_generator.map_type(field.strip(' ;'), False, None, False, True)) - else: - # TODO: Assert line format - pass + enum_variants.append(ComplexEnumVariantInfo(variant_name, fields, False)) + elif camel_to_snake(variant_name) in inline_enum_variants: + fields.append(type_mapping_generator.map_type(inline_enum_variants[camel_to_snake(variant_name)] + " " + camel_to_snake(variant_name), False, None, False, True)) + enum_variants.append(ComplexEnumVariantInfo(variant_name, fields, True)) else: - # TODO: Assert line format - pass - enum_variants.append(ComplexEnumVariantInfo(variant_name, fields)) + enum_variants.append(ComplexEnumVariantInfo(variant_name, fields, True)) 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, enum_doc_comment) @@ -507,16 +556,21 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: 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 = [] + flattened_field_var_convs = [] for var_line in field_var_lines: if var_line.group(1) in trait_structs: - field_var_convs.append((var_line.group(1), var_line.group(2))) + field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)])) + flattened_field_var_convs.append((var_line.group(1), var_line.group(2), )) + flattened_field_var_convs.extend(trait_structs[var_line.group(1)]) else: - field_var_convs.append( - type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)) + mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False) + field_var_convs.append(mapped) + flattened_field_var_convs.append(mapped) + trait_structs[struct_name] = field_var_convs field_fns = [] 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) + ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False) is_const = fn_line.group(4) is not None arg_tys = [] @@ -527,7 +581,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: arg_tys.append(arg_conv_info) 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, trait_doc_comment) + (out_java_addendum, out_java_trait_addendum, out_c_addendum) = consts.native_c_map_trait(struct_name, field_var_convs, flattened_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) @@ -604,17 +658,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: else: out_java_struct.write("\t\t\tthis.res = bindings." + struct_name + "_get_ok(ptr);\n") out_java_struct.write("\t\t}\n") - if struct_name.startswith("LDKCResult_None"): - out_java_struct.write("\t\tpublic " + human_ty + "_OK() {\n\t\t\tthis(null, bindings.C" + human_ty + "_ok());\n") - else: - out_java_struct.write("\t\tpublic " + human_ty + "_OK(" + res_map.java_hu_ty + " res) {\n") - 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].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_struct.write("\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_define_pfx(struct_name + "_get_err", True) + consts.ptr_c_ty + " arg) {\n") @@ -642,17 +686,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: out_java_struct.write("\t\t\tthis.err = bindings." + struct_name + "_get_err(ptr);\n") out_java_struct.write("\t\t}\n") - if struct_name.endswith("NoneZ"): - out_java_struct.write("\t\tpublic " + human_ty + "_Err() {\n\t\t\tthis(null, bindings.C" + human_ty + "_err());\n") - else: - out_java_struct.write("\t\tpublic " + human_ty + "_Err(" + err_map.java_hu_ty + " err) {\n") - 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].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") + out_java_struct.write("\t}\n\n") def map_tuple(struct_name, field_lines): out_java.write("\tpublic static native long " + struct_name + "_new(") @@ -683,7 +717,7 @@ 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") - write_c("\treturn (long)ret;\n") + write_c("\treturn (uint64_t)ret;\n") write_c("}\n") for idx, ty_info in enumerate(ty_list): @@ -699,7 +733,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: write_c("\treturn tuple->" + e + ";\n") write_c("}\n") - out_java.write(consts.bindings_header) + out_java.write(consts.bindings_header.replace('', local_git_version)) with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct: out_java_struct.write(consts.common_base) @@ -843,7 +877,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: if cleanup is not None: write_c("\t\t" + cleanup + ";\n") write_c("\t}\n") - write_c("\treturn (long)ret;\n") + write_c("\treturn (uint64_t)ret;\n") write_c("}\n") if ty_info.is_native_primitive: @@ -868,13 +902,32 @@ 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], last_block_comment) + tuple_variants = {} + elem_items = -1 + for line in field_lines: + if line == " struct {": + elem_items = 0 + elif line == " };": + elem_items = -1 + elif elem_items > -1: + line = line.strip() + if line.startswith("struct "): + line = line[7:] + elif line.startswith("enum "): + line = line[5:] + split = line.split(" ") + assert len(split) == 2 + tuple_variants[split[1].strip(";")] = split[0] + elem_items += 1 + if elem_items > 1: + # We don't currently support tuple variant with more than one element + assert False + map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment) last_block_comment = None elif is_unitary_enum: 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, last_block_comment) elif struct_name == "LDKTxOut": with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct: @@ -934,9 +987,12 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: for struct_name in complex_enums: with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct: out_java_struct.write("}\n") + for struct_name in result_types: + with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{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.c_file_pfx.replace('', local_git_version)) 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: