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