Somewhat redundant changes (new file_ext, arg parse, etc)
[ldk-java] / typescript_strings.py
1 from language_constants import LanguageConstants
2
3 class Consts(LanguageConstants):
4
5     def __init__(self, DEBUG):
6         super().__init__()
7         self.file_extension = 'ts'
8
9         self.common_base = """
10             export default class CommonBase {
11                 ptr: number;
12                 ptrs_to: object[] = new Array(); // new LinkedList(); TODO: build linked list implementation
13                 protected constructor(ptr: number) { this.ptr = ptr; }
14                 public _test_only_get_ptr(): number { return this.ptr; }
15             }
16         """
17
18         self.c_file_pfx = """#include <rust_types.h>
19 #include <stdatomic.h>
20 #include <lightning.h>
21
22 // These should be provided...somehow...
23 void *memset(void *s, int c, size_t n);
24 void *memcpy(void *dest, const void *src, size_t n);
25 int memcmp(const void *s1, const void *s2, size_t n);
26
27 void __attribute__((noreturn)) abort(void);
28 void assert(scalar expression);
29 """
30
31         if not DEBUG:
32             self.c_file_pfx = self.c_file_pfx + """
33 void *malloc(size_t size);
34 void free(void *ptr);
35
36 #define MALLOC(a, _) malloc(a)
37 #define FREE(p) if ((long)(p) > 1024) { free(p); }
38 #define DO_ASSERT(a) (void)(a)
39 #define CHECK(a)
40 """
41         else:
42             self.c_file_pfx = self.c_file_pfx + """
43 // Always run a, then assert it is true:
44 #define DO_ASSERT(a) do { bool _assert_val = (a); assert(_assert_val); } while(0)
45 // Assert a is true or do nothing
46 #define CHECK(a) DO_ASSERT(a)
47
48 // Running a leak check across all the allocations and frees of the JDK is a mess,
49 // so instead we implement our own naive leak checker here, relying on the -wrap
50 // linker option to wrap malloc/calloc/realloc/free, tracking everyhing allocated
51 // and free'd in Rust or C across the generated bindings shared library.
52
53 #define BT_MAX 128
54 typedef struct allocation {
55         struct allocation* next;
56         void* ptr;
57         const char* struct_name;
58 } allocation;
59 static allocation* allocation_ll = NULL;
60
61 void* __real_malloc(size_t len);
62 void* __real_calloc(size_t nmemb, size_t len);
63 static void new_allocation(void* res, const char* struct_name) {
64         allocation* new_alloc = __real_malloc(sizeof(allocation));
65         new_alloc->ptr = res;
66         new_alloc->struct_name = struct_name;
67         new_alloc->next = allocation_ll;
68         allocation_ll = new_alloc;
69 }
70 static void* MALLOC(size_t len, const char* struct_name) {
71         void* res = __real_malloc(len);
72         new_allocation(res, struct_name);
73         return res;
74 }
75 void __real_free(void* ptr);
76 static void alloc_freed(void* ptr) {
77         allocation* p = NULL;
78         allocation* it = allocation_ll;
79         while (it->ptr != ptr) {
80                 p = it; it = it->next;
81                 if (it == NULL) {
82                         //XXX: fprintf(stderr, "Tried to free unknown pointer %p\\n", ptr);
83                         return; // addrsan should catch malloc-unknown and print more info than we have
84                 }
85         }
86         if (p) { p->next = it->next; } else { allocation_ll = it->next; }
87         DO_ASSERT(it->ptr == ptr);
88         __real_free(it);
89 }
90 static void FREE(void* ptr) {
91         if ((long)ptr < 1024) return; // Rust loves to create pointers to the NULL page for dummys
92         alloc_freed(ptr);
93         __real_free(ptr);
94 }
95
96 void* __wrap_malloc(size_t len) {
97         void* res = __real_malloc(len);
98         new_allocation(res, "malloc call");
99         return res;
100 }
101 void* __wrap_calloc(size_t nmemb, size_t len) {
102         void* res = __real_calloc(nmemb, len);
103         new_allocation(res, "calloc call");
104         return res;
105 }
106 void __wrap_free(void* ptr) {
107         if (ptr == NULL) return;
108         alloc_freed(ptr);
109         __real_free(ptr);
110 }
111
112 void* __real_realloc(void* ptr, size_t newlen);
113 void* __wrap_realloc(void* ptr, size_t len) {
114         if (ptr != NULL) alloc_freed(ptr);
115         void* res = __real_realloc(ptr, len);
116         new_allocation(res, "realloc call");
117         return res;
118 }
119 void __wrap_reallocarray(void* ptr, size_t new_sz) {
120         // Rust doesn't seem to use reallocarray currently
121         DO_ASSERT(false);
122 }
123
124 void __attribute__((destructor)) check_leaks() {
125         for (allocation* a = allocation_ll; a != NULL; a = a->next) {
126                 //XXX: fprintf(stderr, "%s %p remains\\n", a->struct_name, a->ptr);
127         }
128         DO_ASSERT(allocation_ll == NULL);
129 }
130 """
131         self.c_file_pfx = self.c_file_pfx + """
132 // We assume that CVec_u8Z and u8slice are the same size and layout (and thus pointers to the two can be mixed)
133 _Static_assert(sizeof(LDKCVec_u8Z) == sizeof(LDKu8slice), "Vec<u8> and [u8] need to have been mapped identically");
134 _Static_assert(offsetof(LDKCVec_u8Z, data) == offsetof(LDKu8slice, data), "Vec<u8> and [u8] need to have been mapped identically");
135 _Static_assert(offsetof(LDKCVec_u8Z, datalen) == offsetof(LDKu8slice, datalen), "Vec<u8> and [u8] need to have been mapped identically");
136
137 _Static_assert(sizeof(void*) == 4, "Pointers mut be 32 bits");
138
139 typedef struct int64_tArray {uint32_t len;int64_t *ptr;} int64_tArray;
140 typedef struct uint32_tArray {uint32_t len;int32_t *ptr;} uint32_tArray;
141 typedef struct int8_tArray {uint32_t len;int8_t *ptr;} int8_tArray;
142
143 typedef bool jboolean;
144
145 """
146
147         self.hu_struct_file_prefix = f"""
148 import CommonBase from './CommonBase';
149 import * as bindings from '../bindings' // TODO: figure out location
150
151 """
152         self.c_fn_ty_pfx = ""
153         self.c_fn_name_pfx = ""
154         self.c_fn_args_pfx = "void* ctx_TODO"
155         self.file_ext = ""
156         self.ptr_c_ty = "uint32_t"
157         self.ptr_native_ty = "uint32_t"
158         self.result_c_ty = "uint32_t"
159         self.ptr_arr = "uint32_tArray"
160         self.get_native_arr_len_call = ("", ".len")
161         self.get_native_arr_ptr_call = ("", ".ptr")
162
163     def release_native_arr_ptr_call(self, arr_var, arr_ptr_var):
164         return None
165     def create_native_arr_call(self, arr_len, ty_info):
166         if ty_info.c_ty == "int8_tArray":
167             return "{ .len = " + arr_len + ", .ptr = MALLOC(" + arr_len + ", \"Native " + ty_info.c_ty + " Bytes\") }"
168         elif ty_info.c_ty == "int64_tArray":
169             return "{ .len = " + arr_len + ", .ptr = MALLOC(" + arr_len + " * sizeof(int64_t), \"Native " + ty_info.c_ty + " Bytes\") }"
170         elif ty_info.c_ty == "uint32_tArray":
171             return "{ .len = " + arr_len + ", .ptr = MALLOC(" + arr_len + " * sizeof(int32_t), \"Native " + ty_info.c_ty + " Bytes\") }"
172         else:
173             print("Need to create arr!", ty_info.c_ty)
174             return ty_info.c_ty
175     def set_native_arr_contents(self, arr_name, arr_len, ty_info):
176         if ty_info.c_ty == "int8_tArray":
177             return ("memcpy(" + arr_name + ".ptr, ", ", " + arr_len + ")")
178         else:
179             assert False
180     def get_native_arr_contents(self, arr_name, dest_name, arr_len, ty_info, copy):
181         if ty_info.c_ty == "int8_tArray":
182             if copy:
183                 return "memcpy(" + dest_name + ", " + arr_name + ".ptr, " + arr_len + ")"
184             else:
185                 return arr_name + ".ptr"
186         else:
187             return "(" + ty_info.subty.c_ty + "*) " + arr_name + ".ptr"
188     def get_native_arr_elem(self, arr_name, idxc, ty_info):
189         assert False # Only called if above is None
190     def cleanup_native_arr_ref_contents(self, arr_name, dest_name, arr_len, ty_info):
191         if ty_info.c_ty == "int8_tArray":
192             return None
193         else:
194             return None
195
196     def init_str(self, c_array_class_caches):
197         return ""
198
199     def native_c_unitary_enum_map(self, struct_name, variants):
200         out_c = "static inline " + struct_name + " " + struct_name + "_from_js(int32_t ord) {\n"
201         out_c = out_c + "\tswitch (ord) {\n"
202         ord_v = 0
203         for var in variants:
204             out_c = out_c + "\t\tcase %d: return %s;\n" % (ord_v, var)
205             ord_v = ord_v + 1
206         out_c = out_c + "\t}\n"
207         out_c = out_c + "\tabort();\n"
208         out_c = out_c + "}\n"
209
210         out_c = out_c + "static inline int32_t " + struct_name + "_to_js(" + struct_name + " val) {\n"
211         out_c = out_c + "\tswitch (val) {\n"
212         ord_v = 0
213         for var in variants:
214             out_c = out_c + "\t\tcase " + var + ": return %d;\n" % ord_v
215             ord_v = ord_v + 1
216         out_c = out_c + "\t\tdefault: abort();\n"
217         out_c = out_c + "\t}\n"
218         out_c = out_c + "}\n"
219         return (out_c, "", "")
220
221     def c_unitary_enum_to_native_call(self, ty_info):
222         return (ty_info.rust_obj + "_to_js(", ")")
223     def native_unitary_enum_to_c_call(self, ty_info):
224         return (ty_info.rust_obj + "_from_js(", ")")
225
226     def c_complex_enum_pfx(self, struct_name, variants, init_meth_jty_strs):
227         return ""
228
229     def c_complex_enum_pass_ty(self, struct_name):
230         return "uint32_t"
231
232     def c_constr_native_complex_enum(self, struct_name, variant, c_params):
233         ret = "0 /* " + struct_name + " - " + variant + " */"
234         for param in c_params:
235             ret = ret + "; (void) " + param
236         return ret
237
238     def native_c_map_trait(self, struct_name, field_var_convs, field_fn_lines):
239         return ("", "")