X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=genbindings.py;h=f022c1b34062ff004dcbef1c25acf1472526edba;hb=9f93df58323e1dea5f3900d5d06b8506b8bc3278;hp=b434969a31e55a4c73cff6316005fecbef14ad2b;hpb=c406e9dff9112e39fe5ec21adfcf2825c415a3fc;p=ldk-java diff --git a/genbindings.py b/genbindings.py index b434969a..f022c1b3 100755 --- a/genbindings.py +++ b/genbindings.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import sys, re -if len(sys.argv) != 7: +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") sys.exit(1) @@ -13,14 +13,19 @@ else: print("debug should be true or false and indicates whether to track allocations and ensure we don't leak") sys.exit(1) +target = None if sys.argv[6] == "java": from java_strings import Consts elif sys.argv[6] == "typescript": + import typescript_strings from typescript_strings import Consts + target = typescript_strings.Target.NODEJS + if len(sys.argv) == 8 and sys.argv[7] == 'browser': + target = typescript_strings.Target.BROWSER else: print("Only java or typescript can be set for lang") sys.exit(1) -consts = Consts(DEBUG) +consts = Consts(DEBUG, target=target) from bindingstypes import * @@ -170,6 +175,8 @@ def java_c_types(fn_arg, ret_arr_len): is_primitive = False arr_len = None + mapped_type = [] + java_type_plural = None if fn_arg.startswith("void"): java_ty = "void" c_ty = "void" @@ -183,26 +190,30 @@ def java_c_types(fn_arg, ret_arr_len): fn_arg = fn_arg[4:].strip() is_primitive = True elif fn_arg.startswith("uint8_t"): - java_ty = "byte" + mapped_type = consts.c_type_map['uint8_t'] + java_ty = mapped_type[0] c_ty = "int8_t" fn_ty_arg = "B" fn_arg = fn_arg[7:].strip() is_primitive = True elif fn_arg.startswith("uint16_t"): - java_ty = "short" + mapped_type = consts.c_type_map['uint16_t'] + java_ty = mapped_type[0] c_ty = "jshort" fn_ty_arg = "S" fn_arg = fn_arg[8:].strip() is_primitive = True elif fn_arg.startswith("uint32_t"): - java_ty = "int" + mapped_type = consts.c_type_map['uint32_t'] + java_ty = mapped_type[0] c_ty = "int32_t" fn_ty_arg = "I" fn_arg = fn_arg[8:].strip() is_primitive = True elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"): # TODO: uintptr_t is arch-dependent :( - java_ty = "long" + mapped_type = consts.c_type_map['long'] + java_ty = mapped_type[0] c_ty = "int64_t" fn_ty_arg = "J" if fn_arg.startswith("uint64_t"): @@ -295,7 +306,11 @@ def java_c_types(fn_arg, ret_arr_len): if var_is_arr is not None or ret_arr_len is not None: assert(not take_by_ptr) assert(not is_ptr) - java_ty = java_ty + "[]" + # is there a special case for plurals? + if len(mapped_type) == 2: + java_ty = mapped_type[1] + else: + java_ty = java_ty + "[]" c_ty = c_ty + "Array" if var_is_arr is not None: if var_is_arr.group(1) == "": @@ -568,7 +583,8 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: arg_conv = opaque_arg_conv, arg_conv_name = "&" + ty_info.var_name + "_conv", arg_conv_cleanup = None, ret_conv = (ty_info.rust_obj + " " + ty_info.var_name + "_var = *", opaque_ret_conv_suf), ret_conv_name = ty_info.var_name + "_ref", - to_hu_conv = ty_info.java_hu_ty + " " + ty_info.var_name + "_hu_conv = new " + ty_info.java_hu_ty + "(null, " + ty_info.var_name + ");", + # to_hu_conv = ty_info.java_hu_ty + " " + ty_info.var_name + "_hu_conv = new " + ty_info.java_hu_ty + "(null, " + ty_info.var_name + ");", + to_hu_conv = consts.to_hu_conv_templates['ptr'].replace('{human_type}', ty_info.java_hu_ty).replace('{var_name}', ty_info.var_name), to_hu_conv_name = ty_info.var_name + "_hu_conv", from_hu_conv = (ty_info.var_name + " == null ? 0 : " + ty_info.var_name + ".ptr & ~1", "this.ptrs_to.add(" + ty_info.var_name + ")")) else: @@ -576,7 +592,8 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: arg_conv = opaque_arg_conv, arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None, ret_conv = (ty_info.rust_obj + " " + ty_info.var_name + "_var = ", opaque_ret_conv_suf), ret_conv_name = ty_info.var_name + "_ref", - to_hu_conv = ty_info.java_hu_ty + " " + ty_info.var_name + "_hu_conv = new " + ty_info.java_hu_ty + "(null, " + ty_info.var_name + ");", + # to_hu_conv = ty_info.java_hu_ty + " " + ty_info.var_name + "_hu_conv = new " + ty_info.java_hu_ty + "(null, " + ty_info.var_name + ");", + to_hu_conv = consts.to_hu_conv_templates['default'].replace('{human_type}', ty_info.java_hu_ty).replace('{var_name}', ty_info.var_name), to_hu_conv_name = ty_info.var_name + "_hu_conv", from_hu_conv = (ty_info.var_name + " == null ? 0 : " + ty_info.var_name + ".ptr & ~1", "this.ptrs_to.add(" + ty_info.var_name + ")")) @@ -924,7 +941,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: 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): java_hu_type = struct_name.replace("LDK", "") complex_enums.add(struct_name) @@ -985,208 +1002,10 @@ 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)) - write_c(consts.native_c_map_trait(struct_name, field_var_convs, field_fns)[1]) - - out_java_trait.write(consts.hu_struct_file_prefix) - out_java_trait.write("public class " + struct_name.replace("LDK","") + " extends CommonBase {\n") - out_java_trait.write("\tfinal bindings." + struct_name + " bindings_instance;\n") - out_java_trait.write("\t" + struct_name.replace("LDK", "") + "(Object _dummy, long ptr) { super(ptr); bindings_instance = null; }\n") - out_java_trait.write("\tprivate " + struct_name.replace("LDK", "") + "(bindings." + struct_name + " arg") - for idx, var_line in enumerate(field_var_lines): - if var_line.group(1) in trait_structs: - out_java_trait.write(", bindings." + var_line.group(1) + " " + var_line.group(2)) - else: - out_java_trait.write(", " + field_var_convs[idx].java_hu_ty + " " + var_line.group(2)) - out_java_trait.write(") {\n") - out_java_trait.write("\t\tsuper(bindings." + struct_name + "_new(arg") - for idx, var_line in enumerate(field_var_lines): - if var_line.group(1) in trait_structs: - out_java_trait.write(", " + var_line.group(2)) - elif field_var_convs[idx].from_hu_conv is not None: - out_java_trait.write(", " + field_var_convs[idx].from_hu_conv[0]) - else: - out_java_trait.write(", " + var_line.group(2)) - out_java_trait.write("));\n") - out_java_trait.write("\t\tthis.ptrs_to.add(arg);\n") - for idx, var_line in enumerate(field_var_lines): - if var_line.group(1) in trait_structs: - out_java_trait.write("\t\tthis.ptrs_to.add(" + var_line.group(2) + ");\n") - elif field_var_convs[idx].from_hu_conv is not None and field_var_convs[idx].from_hu_conv[1] != "": - out_java_trait.write("\t\t" + field_var_convs[idx].from_hu_conv[1] + ";\n") - out_java_trait.write("\t\tthis.bindings_instance = arg;\n") - out_java_trait.write("\t}\n") - out_java_trait.write("\t@Override @SuppressWarnings(\"deprecation\")\n") - out_java_trait.write("\tprotected void finalize() throws Throwable {\n") - out_java_trait.write("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); } super.finalize();\n") - out_java_trait.write("\t}\n\n") - - java_trait_constr = "\tprivate static class " + struct_name + "Holder { " + struct_name.replace("LDK", "") + " held; }\n" - java_trait_constr = java_trait_constr + "\tpublic static " + struct_name.replace("LDK", "") + " new_impl(" + struct_name.replace("LDK", "") + "Interface arg" - for idx, var_line in enumerate(field_var_lines): - if var_line.group(1) in trait_structs: - # Ideally we'd be able to take any instance of the interface, but our C code can only represent - # Java-implemented version, so we require users pass a Java implementation here :/ - java_trait_constr = java_trait_constr + ", " + var_line.group(1).replace("LDK", "") + "." + var_line.group(1).replace("LDK", "") + "Interface " + var_line.group(2) + "_impl" - else: - java_trait_constr = java_trait_constr + ", " + field_var_convs[idx].java_hu_ty + " " + var_line.group(2) - java_trait_constr = java_trait_constr + ") {\n\t\tfinal " + struct_name + "Holder impl_holder = new " + struct_name + "Holder();\n" - java_trait_constr = java_trait_constr + "\t\timpl_holder.held = new " + struct_name.replace("LDK", "") + "(new bindings." + struct_name + "() {\n" - out_java_trait.write("\tpublic static interface " + struct_name.replace("LDK", "") + "Interface {\n") - out_java.write("\tpublic interface " + struct_name + " {\n") - java_meths = [] - for fn_line in trait_fn_lines: - java_meth_descr = "(" - if fn_line.group(3) != "free" and fn_line.group(3) != "clone": - ret_ty_info = map_type(fn_line.group(2), True, None, False, False) - - out_java.write("\t\t " + ret_ty_info.java_ty + " " + fn_line.group(3) + "(") - java_trait_constr = java_trait_constr + "\t\t\t@Override public " + ret_ty_info.java_ty + " " + fn_line.group(3) + "(" - out_java_trait.write("\t\t" + ret_ty_info.java_hu_ty + " " + fn_line.group(3) + "(") - is_const = fn_line.group(4) is not None - - arg_names = [] - for idx, arg in enumerate(fn_line.group(5).split(',')): - if arg == "": - continue - if idx >= 2: - out_java.write(", ") - java_trait_constr = java_trait_constr + ", " - out_java_trait.write(", ") - arg_conv_info = map_type(arg, True, None, False, False) - out_java.write(arg_conv_info.java_ty + " " + arg_conv_info.arg_name) - out_java_trait.write(arg_conv_info.java_hu_ty + " " + arg_conv_info.arg_name) - java_trait_constr = java_trait_constr + arg_conv_info.java_ty + " " + arg_conv_info.arg_name - arg_names.append(arg_conv_info) - java_meth_descr = java_meth_descr + arg_conv_info.java_fn_ty_arg - java_meth_descr = java_meth_descr + ")" + ret_ty_info.java_fn_ty_arg - java_meths.append((fn_line, java_meth_descr)) - - out_java.write(");\n") - out_java_trait.write(");\n") - java_trait_constr = java_trait_constr + ") {\n" - - for arg_info in arg_names: - if arg_info.to_hu_conv is not None: - java_trait_constr = java_trait_constr + "\t\t\t\t" + arg_info.to_hu_conv.replace("\n", "\n\t\t\t\t") + "\n" - - if ret_ty_info.java_ty != "void": - java_trait_constr = java_trait_constr + "\t\t\t\t" + ret_ty_info.java_hu_ty + " ret = arg." + fn_line.group(3) + "(" - else: - java_trait_constr = java_trait_constr + "\t\t\t\targ." + fn_line.group(3) + "(" - - for idx, arg_info in enumerate(arg_names): - if idx != 0: - java_trait_constr = java_trait_constr + ", " - if arg_info.to_hu_conv_name is not None: - java_trait_constr = java_trait_constr + arg_info.to_hu_conv_name - else: - java_trait_constr = java_trait_constr + arg_info.arg_name - - java_trait_constr = java_trait_constr + ");\n" - if ret_ty_info.java_ty != "void": - if ret_ty_info.from_hu_conv is not None: - java_trait_constr = java_trait_constr + "\t\t\t\t" + ret_ty_info.java_ty + " result = " + ret_ty_info.from_hu_conv[0] + ";\n" - if ret_ty_info.from_hu_conv[1] != "": - java_trait_constr = java_trait_constr + "\t\t\t\t" + ret_ty_info.from_hu_conv[1].replace("this", "impl_holder.held") + ";\n" - if ret_ty_info.rust_obj in result_types: - # Avoid double-free by breaking the result - we should learn to clone these and then we can be safe instead - java_trait_constr = java_trait_constr + "\t\t\t\tret.ptr = 0;\n" - java_trait_constr = java_trait_constr + "\t\t\t\treturn result;\n" - else: - java_trait_constr = java_trait_constr + "\t\t\t\treturn ret;\n" - java_trait_constr = java_trait_constr + "\t\t\t}\n" - java_trait_constr = java_trait_constr + "\t\t}" - for var_line in field_var_lines: - if var_line.group(1) in trait_structs: - java_trait_constr = java_trait_constr + ", " + var_line.group(2) + ".new_impl(" + var_line.group(2) + "_impl).bindings_instance" - else: - java_trait_constr = java_trait_constr + ", " + var_line.group(2) - out_java_trait.write("\t}\n") - out_java_trait.write(java_trait_constr + ");\n\t\treturn impl_holder.held;\n\t}\n") - - # Write out a clone function whether we need one or not, as we use them in moving to rust - write_c("static void* " + struct_name + "_JCalls_clone(const void* this_arg) {\n") - write_c("\t" + struct_name + "_JCalls *j_calls = (" + struct_name + "_JCalls*) this_arg;\n") - write_c("\tatomic_fetch_add_explicit(&j_calls->refcnt, 1, memory_order_release);\n") - for var_line in field_var_lines: - if var_line.group(1) in trait_structs: - write_c("\tatomic_fetch_add_explicit(&j_calls->" + var_line.group(2) + "->refcnt, 1, memory_order_release);\n") - write_c("\treturn (void*) this_arg;\n") - write_c("}\n") - - out_java.write("\t}\n") - - out_java.write("\tpublic static native long " + struct_name + "_new(" + struct_name + " impl") - write_c("static inline " + struct_name + " " + struct_name + "_init (" + consts.c_fn_args_pfx + ", jobject o") - for idx, var_line in enumerate(field_var_lines): - if var_line.group(1) in trait_structs: - out_java.write(", " + var_line.group(1) + " " + var_line.group(2)) - write_c(", jobject " + var_line.group(2)) - else: - out_java.write(", " + field_var_convs[idx].java_ty + " " + var_line.group(2)) - write_c(", " + field_var_convs[idx].c_ty + " " + var_line.group(2)) - out_java.write(");\n") - write_c(") {\n") - - write_c("\tjclass c = (*env)->GetObjectClass(env, o);\n") - write_c("\tCHECK(c != NULL);\n") - write_c("\t" + struct_name + "_JCalls *calls = MALLOC(sizeof(" + struct_name + "_JCalls), \"" + struct_name + "_JCalls\");\n") - write_c("\tatomic_init(&calls->refcnt, 1);\n") - write_c("\tDO_ASSERT((*env)->GetJavaVM(env, &calls->vm) == 0);\n") - write_c("\tcalls->o = (*env)->NewWeakGlobalRef(env, o);\n") - for (fn_line, java_meth_descr) in java_meths: - if fn_line.group(3) != "free" and fn_line.group(3) != "clone": - write_c("\tcalls->" + fn_line.group(3) + "_meth = (*env)->GetMethodID(env, c, \"" + fn_line.group(3) + "\", \"" + java_meth_descr + "\");\n") - write_c("\tCHECK(calls->" + fn_line.group(3) + "_meth != NULL);\n") - for idx, var_line in enumerate(field_var_lines): - if var_line.group(1) not in trait_structs and field_var_convs[idx].arg_conv is not None: - write_c("\n\t" + field_var_convs[idx].arg_conv.replace("\n", "\n\t") +"\n") - write_c("\n\t" + struct_name + " ret = {\n") - write_c("\t\t.this_arg = (void*) calls,\n") - for fn_line in trait_fn_lines: - if fn_line.group(3) != "free" and fn_line.group(3) != "clone": - write_c("\t\t." + fn_line.group(3) + " = " + fn_line.group(3) + "_jcall,\n") - elif fn_line.group(3) == "free": - write_c("\t\t.free = " + struct_name + "_JCalls_free,\n") - else: - write_c("\t\t.clone = " + struct_name + "_JCalls_clone,\n") - for idx, var_line in enumerate(field_var_lines): - if var_line.group(1) in trait_structs: - write_c("\t\t." + var_line.group(2) + " = " + var_line.group(1) + "_init(env, clz, " + var_line.group(2) + "),\n") - elif field_var_convs[idx].arg_conv_name is not None: - write_c("\t\t." + var_line.group(2) + " = " + field_var_convs[idx].arg_conv_name + ",\n") - write_c("\t\t.set_" + var_line.group(2) + " = NULL,\n") - else: - write_c("\t\t." + var_line.group(2) + " = " + var_line.group(2) + ",\n") - write_c("\t\t.set_" + var_line.group(2) + " = NULL,\n") - write_c("\t};\n") - for var_line in field_var_lines: - if var_line.group(1) in trait_structs: - write_c("\tcalls->" + var_line.group(2) + " = ret." + var_line.group(2) + ".this_arg;\n") - write_c("\treturn ret;\n") - write_c("}\n") - - write_c(consts.c_fn_ty_pfx + "long " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1new (" + consts.c_fn_args_pfx + ", jobject o") - for idx, var_line in enumerate(field_var_lines): - if var_line.group(1) in trait_structs: - write_c(", jobject " + var_line.group(2)) - else: - write_c(", " + field_var_convs[idx].c_ty + " " + var_line.group(2)) - write_c(") {\n") - write_c("\t" + struct_name + " *res_ptr = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n") - write_c("\t*res_ptr = " + struct_name + "_init(env, clz, o") - for var_line in field_var_lines: - write_c(", " + var_line.group(2)) - write_c(");\n") - write_c("\treturn (long)res_ptr;\n") - write_c("}\n") - - out_java.write("\tpublic static native " + struct_name + " " + struct_name + "_get_obj_from_jcalls(long val);\n") - write_c(consts.c_fn_ty_pfx + "jobject " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1obj_1from_1jcalls (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " val) {\n") - write_c("\tjobject ret = (*env)->NewLocalRef(env, ((" + struct_name + "_JCalls*)val)->o);\n") - write_c("\tCHECK(ret != NULL);\n") - write_c("\treturn ret;\n") - write_c("}\n") + (out_java_addendum, out_java_trait_addendum, out_c_addendum) = consts.native_c_map_trait(struct_name, field_var_convs, field_fns) + 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 now, just disable enabling the _call_log - we don't know how to inverse-map String @@ -1396,41 +1215,9 @@ 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("""package org.ldk.impl; -import org.ldk.enums.*; - -public class bindings { - public static class VecOrSliceDef { - public long dataptr; - public long datalen; - public long stride; - public VecOrSliceDef(long dataptr, long datalen, long stride) { - this.dataptr = dataptr; this.datalen = datalen; this.stride = stride; - } - } - static { - System.loadLibrary(\"lightningjni\"); - init(java.lang.Enum.class, VecOrSliceDef.class); - init_class_cache(); - } - static native void init(java.lang.Class c, java.lang.Class slicedef); - static native void init_class_cache(); - - public static native boolean deref_bool(long ptr); - public static native long deref_long(long ptr); - public static native void free_heap_ptr(long ptr); - public static native byte[] read_bytes(long ptr, long len); - public static native byte[] get_u8_slice_bytes(long slice_ptr); - public static native long bytes_to_u8_vec(byte[] bytes); - public static native long new_txpointer_copy_data(byte[] txdata); - public static native void txpointer_free(long ptr); - public static native byte[] txpointer_get_buffer(long ptr); - public static native long vec_slice_len(long vec); - public static native long new_empty_slice_vec(); - -""") - - with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "a") as out_java_struct: + out_java.write(consts.bindings_header) + + 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