5 print("USAGE: /path/to/lightning.h /path/to/bindings/output.java /path/to/bindings/output.c")
8 with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java, open(sys.argv[3], "w") as out_c:
9 var_is_arr_regex = re.compile("\(\*([A-za-z_]*)\)\[([0-9]*)\]")
10 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
11 def map_type(fn_arg, print_void, ret_arr_len):
12 fn_arg = fn_arg.strip()
13 if fn_arg.startswith("MUST_USE_RES "):
15 if fn_arg.startswith("const "):
20 if fn_arg.startswith("void"):
22 out_java.write("void")
25 return (None, None, None)
26 fn_arg = fn_arg.strip("void ")
27 elif fn_arg.startswith("bool"):
28 out_java.write("boolean")
30 fn_arg = fn_arg.strip("bool ")
31 elif fn_arg.startswith("uint8_t"):
32 out_java.write("byte")
34 fn_arg = fn_arg.strip("uint8_t ")
35 elif fn_arg.startswith("uint32_t"):
38 fn_arg = fn_arg.strip("uint32_t ")
39 elif fn_arg.startswith("uint64_t"):
40 out_java.write("long")
42 fn_arg = fn_arg.strip("uint64_t ")
44 ma = var_ty_regex.match(fn_arg)
45 out_java.write("long")
47 is_ptr_to_obj = ma.group(1)
52 var_is_arr = var_is_arr_regex.match(fn_arg)
53 no_ptr = fn_arg.replace('*', '')
54 if var_is_arr is not None or ret_arr_len is not None:
57 if var_is_arr is not None:
58 arr_name = var_is_arr.group(1)
59 arr_len = var_is_arr.group(2)
60 out_java.write(arr_name)
65 assert(c_ty == "jbyte")
66 return ("unsigned char " + arr_name + "_arr[" + arr_len + "];\n" +
67 "(*_env)->GetByteArrayRegion (_env, """ + arr_name + ", 0, " + arr_len + ", " + arr_name + "_arr);\n" +
68 "unsigned char (*""" + arr_name + "_ref)[" + arr_len + "] = &" + arr_name + "_arr;",
69 (c_ty + "Array " + arr_name + "_arr = (*_env)->NewByteArray(_env, 0); // XXX: len 0\n" +
70 "(*_env)->SetByteArrayRegion(_env, " + arr_name + "_arr, 0, " + arr_len + ", *",
71 ");\nreturn ret_arr;"),
73 elif no_ptr.strip() != "":
74 # If we have a parameter name, print it (noting that it may indicate its a pointer)
75 out_java.write(" " + no_ptr.strip())
76 out_c.write(" " + no_ptr.strip())
77 if is_ptr_to_obj is not None:
79 return (is_ptr_to_obj + " " + no_ptr.strip() + "_conv = *(" + is_ptr_to_obj + "*)" + no_ptr.strip() + ";",
80 "XXX2", no_ptr.strip() + "_conv")
82 return (is_ptr_to_obj + "* " + no_ptr.strip() + "_conv = (" + is_ptr_to_obj + "*)" + no_ptr.strip() + ";",
83 "XXX2", no_ptr.strip() + "_conv")
84 elif no_ptr != fn_arg:
85 return ("YYY1", "XXX3", no_ptr.strip())
87 return (None, "XXX4", no_ptr.strip())
89 # We don't have a parameter name, and want one, just call it arg
90 out_java.write(" arg")
92 if is_ptr_to_obj is not None:
93 return (is_ptr_to_obj + " arg_conv = *(" + is_ptr_to_obj + "*)arg;", "XXX2", "arg_conv")
95 return (None, "XXX6", "arg")
97 # We don't have a parameter name, and don't want one (cause we're returning)
98 if is_ptr_to_obj is not None:
100 return (None, (is_ptr_to_obj + "* ret = malloc(sizeof(" + is_ptr_to_obj + "));\n*ret = ", ";\nreturn (long)ret;"), None)
102 return (None, ("return (long) ", ";"), None)
104 return (None, None, None)
106 def map_fn_args(fn_args, f):
107 for idx, arg in enumerate(fn_args.split(',')):
114 def map_fn(re_match, ret_arr_len):
115 out_java.write("\t/// " + line)
116 out_java.write("\tpublic static native ")
117 out_c.write("JNIEXPORT ")
119 _, ret_conv, _ = map_type(re_match.group(1), True, ret_arr_len)
120 if ret_conv is not None:
121 ret_conv_pfx, ret_conv_sfx = ret_conv
123 out_java.write(" " + re_match.group(2).replace('_', '') + "(")
124 out_c.write(" JNICALL " + re_match.group(2).replace('_', '') + "(JNIEnv * _env, jclass _b")
127 for idx, arg in enumerate(re_match.group(3).split(',')):
132 arg_names.append(map_type(arg, False, None))
134 out_java.write(");\n")
137 for arg_conv, _, _ in arg_names:
138 if arg_conv is not None:
139 out_c.write("\t" + arg_conv.replace('\n', "\n\t") + "\n");
141 if ret_conv is not None:
142 out_c.write("\t" + ret_conv_pfx.replace('\n', '\n\t'));
144 out_c.write("\treturn ");
146 out_c.write(re_match.group(2) + "(")
147 for idx, (_, _, arg) in enumerate(arg_names):
153 if ret_conv is not None:
154 out_c.write(ret_conv_sfx.replace('\n', '\n\t'))
157 out_c.write("\n}\n\n")
159 out_java.write("""package org.ldk;
161 public class bindings {
163 System.loadLibrary(\"lightning\");
167 out_c.write("#include \"org_ldk_bindings.h\"\n")
168 out_c.write("#include <rust_types.h>\n\n")
169 out_c.write("#include <lightning.h>\n\n")
171 in_block_comment = False
172 in_block_enum = False
173 in_block_struct = False
174 in_block_union = False
176 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
177 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
178 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
182 #out_java.write("\t" + line)
183 if line.endswith("*/\n"):
184 in_block_comment = False
185 elif in_block_struct:
186 if line.startswith("} "):
187 in_block_struct = False
189 if line.startswith("} "):
190 in_block_union = False
192 if line.startswith("} "):
193 in_block_enum = False
195 fn_ptr = fn_ptr_regex.match(line)
196 fn_ret_arr = fn_ret_arr_regex.match(line)
197 reg_fn = reg_fn_regex.match(line)
199 if line.startswith("#include <"):
201 elif line.startswith("/*"):
202 #out_java.write("\t" + line)
203 if not line.endswith("*/\n"):
204 in_block_comment = True
205 elif line.startswith("typedef enum "):
207 elif line.startswith("typedef struct "):
208 in_block_struct = True
209 elif line.startswith("typedef union "):
210 in_block_union = True
211 elif line.startswith("typedef "):
213 elif fn_ptr is not None:
215 elif fn_ret_arr is not None:
216 map_fn(fn_ret_arr, fn_ret_arr.group(4))
217 elif reg_fn is not None:
222 out_java.write("}\n")