Initial bindings header generation demo
[ldk-java] / genbindings.py
1 #!/usr/bin/env python3
2 import sys, re
3
4 if len(sys.argv) != 3:
5     print("USAGE: /path/to/lightning.h /path/to/bindings.java")
6     sys.exit(1)
7
8 with open(sys.argv[1]) as f, open(sys.argv[2], "w") as out_f:
9     var_is_arr_regex = re.compile("\(\*([A-za-z_]*)\)\[[0-9]*\]");
10     def map_type(fn_arg, print_void):
11         fn_arg = fn_arg.strip()
12         if fn_arg.startswith("MUST_USE_RES "):
13             fn_arg = fn_arg[13:]
14         if fn_arg.startswith("const "):
15             fn_arg = fn_arg[6:]
16         if fn_arg.startswith("void"):
17             if print_void:
18                 out_f.write("void")
19             else:
20                 return
21             fn_arg = fn_arg.strip("void ")
22         elif fn_arg.startswith("bool"):
23             out_f.write("boolean")
24             fn_arg = fn_arg.strip("bool ")
25         elif fn_arg.startswith("uint8_t"):
26             out_f.write("byte")
27             fn_arg = fn_arg.strip("uint8_t ")
28         elif fn_arg.startswith("uint32_t"):
29             out_f.write("int")
30             fn_arg = fn_arg.strip("uint32_t ")
31         elif fn_arg.startswith("uint64_t"):
32             out_f.write("long")
33             fn_arg = fn_arg.strip("uint64_t ")
34         else:
35             out_f.write("long")
36             fn_arg = "".join([e + " " for e in fn_arg.split(" ")[1:]]).strip()
37         var_is_arr = var_is_arr_regex.match(fn_arg)
38         if var_is_arr is not None:
39             out_f.write("[] " + var_is_arr.group(1))
40         elif fn_arg.strip() != "":
41             out_f.write(" " + fn_arg.replace('*', '').strip())
42         elif not print_void:
43             out_f.write(" arg");
44
45     def map_fn_args(fn_args):
46         for idx, arg in enumerate(fn_args.split(',')):
47             if idx != 0:
48                 out_f.write(", ")
49             map_type(arg, False)
50
51     def map_fn(re_match, ret_ty_suffix):
52         out_f.write("\t/// " + line)
53         out_f.write("\tpublic static native ")
54         map_type(re_match.group(1), True)
55         out_f.write(ret_ty_suffix + " " + re_match.group(2).replace('_', '') + "(")
56         map_fn_args(re_match.group(3))
57         out_f.write(");\n")
58
59     out_f.write("""package org.ldk;
60
61 public class bindings {
62         static {
63                 System.loadLibrary(\"lightning\");
64         }
65
66 """)
67
68     in_block_comment = False
69     in_block_enum = False
70     in_block_struct = False
71     in_block_union = False
72
73     fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
74     fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[.*\];$")
75     reg_fn_regex = re.compile("([A-Za-z_0-9\* ]*) \*?([a-zA-Z_0-9]*)\((.*)\);$")
76
77     for line in f:
78         if in_block_comment:
79             #out_f.write("\t" + line)
80             if line.endswith("*/\n"):
81                 in_block_comment = False
82         elif in_block_struct:
83             if line.startswith("} "):
84                 in_block_struct = False
85         elif in_block_union:
86             if line.startswith("} "):
87                 in_block_union = False
88         elif in_block_enum:
89             if line.startswith("} "):
90                 in_block_enum = False
91         else:
92             fn_ptr = fn_ptr_regex.match(line)
93             fn_ret_arr = fn_ret_arr_regex.match(line)
94             reg_fn = reg_fn_regex.match(line)
95
96             if line.startswith("#include <"):
97                 pass
98             elif line.startswith("/*"):
99                 #out_f.write("\t" + line)
100                 if not line.endswith("*/\n"):
101                     in_block_comment = True
102             elif line.startswith("typedef enum "):
103                 in_block_enum = True
104             elif line.startswith("typedef struct "):
105                 in_block_struct = True
106             elif line.startswith("typedef union "):
107                 in_block_union = True
108             elif line.startswith("typedef "):
109                 pass
110             elif fn_ptr is not None:
111                 map_fn(fn_ptr, "")
112             elif fn_ret_arr is not None:
113                 map_fn(fn_ret_arr, "[]")
114             elif reg_fn is not None:
115                 map_fn(reg_fn, "")
116             else:
117                 assert(line == "\n")
118
119     out_f.write("}\n");