README.md
1# es2panda_lib generation
2
3> What is it?
4
5Automatic export of ArkTS public classes and methods into C API.
6
7> I fixed CODECHECK and got a new failure "UNSUPPORTED TYPE".
8
91) Check if your new method should be private and automatically excluded from C API, error will disappear.
10
112) Otherwise support method arguments types in `cppToCTypes.yaml`.
12
13> What is `cppToCTypes.yaml`
14
15It describes how C++ types should be transformed into C types in plugin API.
16Tranformation "one to many" is supported to express map of e.g. `std::vector<int>` to `int*, size_t pair` pair.
17
18## How to add new type:
19
201) Copy the template below to the end of [cppToCTypes.yaml](./cppToCTypes.yaml).
21
22 <details><summary>Template</summary>
23
24 ```yaml
25 # Describes C++ original argument.
26 - es2panda_arg:
27 name: '|arg_name|'
28 type:
29 name: 'FunctionSignature'
30 namespace: 'ir' # optional
31 min_ptr_depth: 1 # optional
32 max_ptr_depth: 1 # optional
33
34 # Describes C arguments, into which the original argument will be expanded.
35 new_args:
36 - type:
37 name: "es2panda_FunctionSignature"
38 ptr_depth: '|es2panda_arg.type.ptr_depth_int|'
39 name: '|arg_name|'
40 namespace: "ir::"
41
42 # Describes additional C return arguments IF original argument is return type and expands to multiple arguments.
43 return_args:
44 - type:
45 name: size_t
46 ptr_depth: 1
47 name: '|arg_name|Len'
48
49 cast:
50 # Create C++ variable from C argument.
51 expression: >-
52 auto |es2panda_arg.type.ptr_depth||arg_name|E2p =
53 reinterpret_cast<ir::FunctionSignature |es2panda_arg.type.ptr_depth|>(|arg_name|);
54
55 # Create C variable from C++ return value.
56 reverse_cast:
57 start: >-
58 reinterpret_cast<?const? es2panda_FunctionSignature |es2panda_arg.type.ptr_depth|>
59
60 # Cast C argument to C++ class, to call method from it.
61 call_cast:
62 call_var: 'es2panda_FunctionSignature *ast'
63 start: >-
64 (reinterpret_cast<?const? ir::FunctionSignature *>(ast))->
65
66 # Create new class and return C++ pointer to it.
67 constructor_cast:
68 start: >-
69 ctxAllocator->New<ir::FunctionSignature>(
70 end: )
71
72 # Name of veriable, created by expression.
73 var_name: '|arg_name|E2p'
74 ```
75
76 </details>
77
782) Remove comments.
793) Remove unnecessary fields:
80 - `return_args` is needed only if you return new type from function and this type expands to multiple arguments.
81 - `reverse_cast` is needed only if you return new type from function.
82 - `call_cast` is needed only if you add new class to generation.
83 - `constructor_cast` is needed only if you add new class to generation.
844) Modify it for new type. Below you can see [Template description](#template-description).
85
86## Template description:
87All non-basic types are described in [cppToCTypes.yaml](./cppToCTypes.yaml).
88
89There are 4 keys in first layer:
901) `es2panda_arg`: describes original C++ argument. It is used to match which **template** from `cppToCTypes.yaml` should be used for current argument.
91
92 <details><summary>More info</summary>
93
94 FunctionSignature in `cppToCTypes.yaml`:
95 ```yaml
96 es2panda_arg:
97 name: '|arg_name|'
98 type:
99 name: 'FunctionSignature'
100 namespace: 'ir'
101 min_ptr_depth: 1
102 ```
103
104 ### Generator finds match if:
105 ```
106 original_argument['type']['name'] == es2panda_arg['type']['name'] &&
107 original_argument['type']['namespace'] == es2panda_arg['type']['namespace'] &&
108 original_argument['type']['ptr_depth'] >= es2panda_arg['min_ptr_depth'] &&
109 original_argument['type']['ptr_depth'] <= es2panda_arg['max_ptr_depth']
110 ```
111 If any of the fields are missing, the generator will skip the corresponding check (except for the type::name field).
112
113 ### What is `|arg_name|`:
114 It is placeholder. After matching **template**, generator stores placeholder values:
115 ```ruby
116 # Generator finds placeholder |arg_name| in es2panda_arg['name']
117 # It stores the same value from original_argument:
118 |arg_name| = original_argument['type']
119 ```
120
121 You can utilize this placeholder in various contexts, and it will be substituted with the saved value.
122
123 ### Addressing other fields not outlined in the **template**:
124 Following the alignment of the **template** and retention of placeholder values, es2panda_arg is supplanted by original_argument. Hence, other attributes are preserved.
125
126 ### Clarification on ptr_depth and ref_depth:
127
128 `ptr_depth` is number of `*` in argument.
129 `ref_depth` is number of `&` in argument.
130
131 #### Why is it needed:
132 `min_ptr_depth` and `max_ptr_depth` are needed to separate 0 and 1+ ptr-cases, because the es2panda API stores pointers to empty structures and is not able to provide an instance of the class, only a pointer to it (except for primitive C types).
133 For example:
134 `AstNode` -> `es2panda_AstNode *`
135 `AstNode *` -> `es2panda_AstNode *`
136 `AstNode **` -> `es2panda_AstNode **`
137 Where es2panda_AstNode is pointer to empty structure in es2panda API.
138
139 ---
140 </details>
141
1422) `new_args`: describes C arguments, into which the original argument will be expanded.
143
144 <details><summary>More info</summary>
145
146 FunctionSignature in `cppToCTypes.yaml`:
147 ```yaml
148 new_args:
149 - type:
150 name: "es2panda_FunctionSignature"
151 ptr_depth: 1
152 name: '|arg_name|'
153 namespace: "ir::"
154 ```
155
156 Describes argument for C-API:
157 ```c++
158 // original C++ argument:
159 ir::FunctionSignature *MyVarName
160
161 // new C argument:
162 es2panda_FunctionSignature *MyVarName
163 ```
164
165 **Note:** please manually write namespace in the format like `ir::` (with `::`).
166
167 ---
168 </details>
169
1703) `return_args`: describes additional C return arguments IF original argument is return type and expands to multiple arguments.
171
172 <details><summary>More info</summary>
173
174 FunctionSignature in `cppToCTypes.yaml`:
175 ```yaml
176 - name: '|arg_name|Len'
177 type:
178 name: size_t
179 ptr_depth: 1
180 ```
181
182 ### When it is needed:
183 If `original_argument` expands to **several argument** and if it is **return type** additional arguments should appear, through which the necessary values will be returned.
184 For example:
185 ```c++
186 // Example: ArenaVector<int> -> int *, size_t *
187
188 // C++ function
189 ArenaVector<int> Foo();
190
191 // C-API function
192 int *FooInAPI(size_t *arenaVectorLen /* return argument appeared */)
193 ```
194
195 ---
196 </details>
197
1984) `cast`:
199 - `expression`: create C++ variable from C argument.
200
201 <details><summary>More info</summary>
202
203 FunctionSignature in `cppToCTypes.yaml`:
204 ```yaml
205 expression: >-
206 auto |es2panda_arg.type.ptr_depth||arg_name|E2p =
207 reinterpret_cast<ir::FunctionSignature |es2panda_arg.type.ptr_depth|>(|arg_name|);
208 ```
209
210 Result:
211 ```c++
212 // C++ function
213 void Foo(FunctionSignature *myArgument);
214
215 // C-API function
216 void FooInAPI(es2panda_FunctionSignature *myArgument) {
217 auto *myArgumentE2p = reinterpret_cast<ir::FunctionSignature *>(myArgument);
218 // ... other code
219 }
220 ```
221
222 ### Note:
223 You can see clever placeholder `|es2panda_arg.type.ptr_depth|`. It allows to get value from `es2panda_arg['type']['ptr_depth']`.
224 If `es2panda_arg['type']['ptr_depth'] = 2`, then `|es2panda_arg.type.ptr_depth|` will be raplaced with `**` and `|es2panda_arg.type.ptr_depth_int|` will be replaced with `2`.
225
226 ---
227 </details>
228
229 - `reverse_cast`: create C variable from C++ return value.
230
231 <details><summary>More info</summary>
232
233 FunctionSignature in `cppToCTypes.yaml`:
234 ```yaml
235 reverse_cast:
236 start: >-
237 reinterpret_cast<?const? es2panda_FunctionSignature |es2panda_arg.type.ptr_depth|>
238 ```
239
240 Result:
241 ```c++
242 // C++ function
243 FunctionSignature *Foo();
244
245 // C-API function
246 es2panda_FunctionSignature *FooInAPI() {
247 // auto res = reverse_cast['start']( Foo() )reverse_cast['end']
248 auto res = reinterpret_cast<es2panda_FunctionSignature *>(Foo());
249 return res;
250 }
251 ```
252
253 ### Note:
254 You can see `?const?`, it will be replaced with `const` if the type is const, and will be deleted otherwise.
255
256 ---
257 </details>
258
259 - `call_cast`: cast C argument to C++ class, to call method from it.
260
261 <details><summary>More info</summary>
262
263 FunctionSignature in `cppToCTypes.yaml`:
264 ```yaml
265 call_cast:
266 call_var: 'es2panda_FunctionSignature *ast'
267 start: >-
268 (reinterpret_cast<?const? ir::FunctionSignature *>(ast))->
269 ```
270
271 Result:
272 ```c++
273 // C++ method
274 class FunctionSignature {
275 void Foo();
276 }
277
278 // C-API function
279 void FooInAPI(es2panda_FunctionSignature *ast /* call_var appeared */) {
280 // call_cast['start']Foo();
281 (reinterpret_cast<ir::FunctionSignature *>(ast))->Foo();
282 }
283
284 ```
285
286 `call_var`: additional C argument - class pointer, to call method from.
287
288 ### Note:
289 You can see `?const?`, it will be replaced with `const` if the type is const, and will be deleted otherwise.
290
291 ---
292 </details>
293
294
295 - `constructor_cast`: create new class and return C++ pointer to it.
296
297 <details><summary>More info</summary>
298
299 FunctionSignature in `cppToCTypes.yaml`:
300 ```yaml
301 constructor_cast:
302 start: >-
303 ctxAllocator->New<ir::FunctionSignature>(
304 end: )
305 ```
306
307 Result:
308 ```c++
309 // C++ constructor
310 class FunctionSignature {
311 FunctionSignature(int arg1, int arg2);
312 }
313
314 // C-API function
315 es2panda_FunctionSignature FunctionSignatureInAPI(int arg1, int arg2) {
316 // return reverse_cast['start']( constructor_cast['start'] <ARGUMENTS> constructor_cast['end'] )reverse_cast['end']
317 return reinterpret_cast<es2panda_FunctionSignature *>(/* constructor cast -> */ ctxAllocator->New<ir::FunctionSignature>(arg1, arg2));
318 }
319 ```
320
321 ### Note:
322 Using only in constructors. Constructor cast is wrapped by reverse cast.
323
324 ---
325 </details>
326
327 - `var_name`: name of veriable, created by expression.
328
329 <details><summary>More info</summary>
330
331 FunctionSignature in `cppToCTypes.yaml`:
332 ```yaml
333 var_name: '|arg_name|E2p'
334 ```
335
336 Result:
337 ```c++
338 // C++ function
339 void Foo(FunctionSignature *myArgument);
340
341 // C-API function
342 void FooInAPI(es2panda_FunctionSignature *myArgument) {
343 // expression:
344 auto *myArgumentE2p = reinterpret_cast<ir::FunctionSignature *>(myArgument);
345
346 // ... other code
347
348 // calling C++ function, using new variable with name 'var_name'
349 Foo(myArgumentE2p /* var_name */);
350 }
351 ```
352
353 ---
354 </details>
355
356
357es2panda_lib_decl.inc, es2panda_lib_enums.inc, es2panda_lib_impl.inc, es2panda_lib_include.inc, es2panda_lib_list.inc
358
359## How to run:
360```bash
361ninja gen_api # only generates *.inc files.
362
363ninja es2panda-public # compiles es2panda_lib
364```
365
366You can find generated files in `<build>/tools/es2panda/generated/es2panda_lib`.
367
368## Tests:
369Tests are located in `ets_frontend/ets2panda/test/unit/public`, their names start with "e2p_test_plugin".
370
371Run tests:
372```bash
373ninja es2panda-plugin-test
374```
375