• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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