1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2024 Huawei Device Co., Ltd. 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17from __future__ import absolute_import 18 19import os 20import file_parser 21import make_file_base 22 23# pylint:disable=variable-type-changed 24# pylint:disable=huawei-redefined-outer-name 25 26def make_cpptoc_impl_proto(name, func, parts, flag): 27 if isinstance(func, file_parser.obj_function_virtual): 28 proto = parts['retval'] + ' ARK_WEB_CALLBACK' 29 elif flag: 30 proto = 'ARK_WEB_EXPORT ' + parts['retval'] 31 else: 32 proto = parts['retval'] 33 34 proto += ' ' + name + '(' + ', '.join(parts['args']) + ')' 35 return proto 36 37def verify_cpptoc_func_args(func, retval_default, macro_retval_default): 38 result = '' 39 if isinstance(func, file_parser.obj_function_virtual): 40 result += '\n ARK_WEB_CPPTOC_DV_LOG(\"capi struct is %{public}ld\", (long)self);\n' 41 result += '\n ARK_WEB_CPPTOC_CHECK_PARAM(self, ' + macro_retval_default + ');' 42 43 args = func.get_arguments() 44 for arg in args: 45 arg_type = arg.get_arg_type() 46 arg_name = arg.get_type().get_name() 47 comment = '\n // Verify param: ' + arg_name + '; type: ' + arg_type 48 49 if arg_type == 'bool_byref' or arg_type == 'bool_byref_const' or \ 50 arg_type == 'simple_byref' or arg_type == 'simple_byref_const' or \ 51 arg_type == 'struct_byref' or arg_type == 'struct_byref_const' or \ 52 arg_type == 'refptr_diff_byref': 53 result += '\n ARK_WEB_CPPTOC_CHECK_PARAM(' + arg_name + ', ' + macro_retval_default + ');' 54 if arg_type == 'struct_byref_const' or arg_type == 'struct_byref': 55 result += '\n if (!template_util::has_valid_size(' + arg_name + ')) {'\ 56 '\n return' + retval_default + ';'\ 57 '\n }' 58 59 # check index params 60 index_params = arg.parent.get_attrib_list('index_param') 61 if not index_params is None and arg_name in index_params: 62 result += comment + \ 63 '\n if (' + arg_name + ' < 0) {'\ 64 '\n return' + retval_default + ';'\ 65 '\n }' 66 return result 67 68def restore_cpptoc_func_args(func): 69 result = '' 70 args = func.get_arguments() 71 for arg in args: 72 arg_type = arg.get_arg_type() 73 arg_name = arg.get_type().get_name() 74 comment = '\n // Restore param: ' + arg_name + '; type: ' + arg_type 75 76 if arg_type == 'struct_byref': 77 result += comment + \ 78 '\n if (' + arg_name + ') {'\ 79 '\n '+ arg_name + 'Obj.DetachTo(*' + arg_name + ');'\ 80 '\n }' 81 elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': 82 ptr_class = arg.get_type().get_ptr_type() 83 if arg_type == 'refptr_same_byref': 84 assign = ptr_class + 'CppToC::Invert(' + arg_name + 'Ptr)' 85 else: 86 assign = ptr_class + 'CToCpp::Revert(' + arg_name + 'Ptr)' 87 result += comment + \ 88 '\n if (' + arg_name + ') {'\ 89 '\n if (' + arg_name + 'Ptr.get()) {'\ 90 '\n if (' + arg_name + 'Ptr.get() != ' + arg_name + 'Orig) {'\ 91 '\n *' + arg_name + ' = ' + assign + ';'\ 92 '\n }'\ 93 '\n } else {'\ 94 '\n *' + arg_name + ' = nullptr;'\ 95 '\n }'\ 96 '\n }' 97 return result; 98 99def translate_cpptoc_func_args(func): 100 result = '' 101 params = [] 102 args = func.get_arguments() 103 for arg in args: 104 arg_type = arg.get_arg_type() 105 arg_name = arg.get_type().get_name() 106 comment = ' // Translate param: ' + arg_name + '; type: ' + arg_type 107 108 if arg_type == 'simple_byval' or arg_type == 'simple_byaddr': 109 if arg_name[0] == '*': 110 params.append(arg_name[1:]) 111 else: 112 pos = arg_name.find('[') 113 if pos == -1: 114 params.append(arg_name) 115 else: 116 params.append(arg_name[0:pos]) 117 elif arg_type == 'simple_byref' or arg_type == 'simple_byref_const': 118 params.append('*' + arg_name) 119 elif arg_type == 'bool_byval': 120 params.append(arg_name) 121 elif arg_type == 'bool_byref' or arg_type == 'bool_byaddr': 122 params.append('*' + arg_name) 123 elif arg_type == 'struct_byref_const': 124 struct_type = arg.get_type().get_type() 125 result += comment + \ 126 '\n ' + struct_type + ' ' + arg_name + 'Obj;'\ 127 '\n if (' + arg_name + ') {'\ 128 '\n ' + arg_name + 'Obj.Set(*' + arg_name + ', false);'\ 129 '\n }' 130 params.append(arg_name + 'Obj') 131 elif arg_type == 'struct_byref': 132 struct_type = arg.get_type().get_type() 133 result += comment + \ 134 '\n ' + struct_type + ' ' + arg_name + 'Obj;'\ 135 '\n if (' + arg_name + ') {'\ 136 '\n ' + arg_name + 'Obj.AttachTo(*' + arg_name + ');'\ 137 '\n }' 138 params.append(arg_name + 'Obj') 139 elif arg_type == 'refptr_same' or arg_type == 'refptr_diff': 140 ptr_class = arg.get_type().get_ptr_type() 141 if arg_type == 'refptr_same': 142 params.append(ptr_class + 'CppToC::Revert(' + arg_name + ')') 143 else: 144 params.append(ptr_class + 'CToCpp::Invert(' + arg_name + ')') 145 elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': 146 ptr_class = arg.get_type().get_ptr_type() 147 if arg_type == 'refptr_same_byref': 148 assign = ptr_class + 'CppToC::Revert(*' + arg_name + ')' 149 else: 150 assign = ptr_class + 'CToCpp::Invert(*' + arg_name + ')' 151 result += comment + \ 152 '\n ArkWebRefPtr<' + ptr_class + '> ' + arg_name + 'Ptr;'\ 153 '\n if (' + arg_name + ' && *' + arg_name + ') {'\ 154 '\n ' + arg_name + 'Ptr = ' + assign + ';'\ 155 '\n }'\ 156 '\n ' + ptr_class + '* ' + arg_name + 'Orig = ' + arg_name + 'Ptr.get();' 157 params.append(arg_name + 'Ptr') 158 else: 159 raise Exception('Unsupported argument type %s for parameter %s in %s' % 160 (arg_type, arg_name, name)) 161 return result, params 162 163def make_cpptoc_function_impl_new(cls, name, func, defined_names): 164 # retrieve the C API prototype parts 165 parts = func.get_capi_parts(defined_names, True) 166 result = make_cpptoc_impl_proto(name, func, parts, False) + ' {' 167 168 invalid = make_file_base.get_func_invalid_info(name, func) 169 if len(invalid) > 0: 170 return result + invalid 171 172 retval = func.get_retval() 173 retval_default = retval.get_retval_default(True) 174 if len(retval_default) > 0: 175 retval_default = ' ' + retval_default 176 macro_retval_default = retval_default 177 else: 178 macro_retval_default = 'ARK_WEB_RETURN_VOID' 179 180 result_len = len(result) 181 182 # parameter verification 183 result += verify_cpptoc_func_args(func, retval_default, macro_retval_default) 184 if len(result) != result_len: 185 result += '\n' 186 result_len = len(result) 187 188 # parameter translation 189 trans, params = translate_cpptoc_func_args(func) 190 if len(trans) != 0: 191 result += trans + '\n' 192 193 # execution 194 result += '\n // Execute\n ' 195 196 retval_type = retval.get_retval_type() 197 if retval_type != 'none': 198 # has a return value 199 if retval_type == 'simple' or retval_type == 'bool' or retval_type == 'void*' or retval_type == 'uint8_t*' or \ 200 retval_type == 'uint32_t*' or retval_type == 'char*' or file_parser.check_arg_type_is_struct(retval_type): 201 result += 'return ' 202 else: 203 result += retval.get_type().get_type() + ' _retval = ' 204 205 if isinstance(func.parent, file_parser.obj_class): 206 parent_clsname = func.parent.get_name() 207 if isinstance(func, file_parser.obj_function_virtual): 208 if cls.get_name() == parent_clsname: 209 result += parent_clsname + 'CppToC::Get(self)->' 210 else: 211 result += cls.get_name() + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name() + '*>(self))->' 212 else: 213 result += parent_clsname + '::' 214 result += func.get_name() + '(' 215 216 if len(params) > 0: 217 result += '\n ' + ',\n '.join(params) 218 219 result += ');\n' 220 result_len = len(result) 221 222 # parameter restoration 223 result += restore_cpptoc_func_args(func) 224 if len(result) != result_len: 225 result += '\n' 226 result_len = len(result) 227 228 if retval_type == 'refptr_same': 229 result += '\n // Return type: ' + retval_type 230 result += '\n return ' + retval.get_type().get_ptr_type() + 'CppToC::Invert(_retval);' 231 elif retval_type == 'refptr_diff': 232 result += '\n // Return type: ' + retval_type 233 result += '\n return ' + retval.get_type().get_ptr_type() + 'CToCpp::Revert(_retval);' 234 235 if len(result) != result_len: 236 result += '\n' 237 238 result += '}\n\n' 239 return result 240 241 242def make_cpptoc_function_impl(cls, funcs, prefixname, defined_names): 243 impl = '' 244 245 new_list = [] 246 old_list = make_file_base.get_func_name_list(funcs) 247 248 for func in funcs: 249 suffix = '' 250 new_list = make_file_base.get_func_name_count(func.get_capi_name(), old_list, new_list) 251 if new_list.count(func.get_capi_name()) != 0: 252 suffix = str(new_list.count(func.get_capi_name())) 253 254 if not prefixname is None: 255 name = prefixname + '_' + func.get_capi_name() + suffix 256 else: 257 name = func.get_capi_name() + suffix 258 impl += make_cpptoc_function_impl_new(cls, name, func, defined_names) 259 260 return impl 261 262 263def make_cpptoc_virtual_function_impl(header, cls, prefixname, defined_names): 264 funcs = [] 265 parent_cls = cls 266 while True: 267 funcs.extend(parent_cls.get_virtual_funcs()) 268 269 parent_clsname = parent_cls.get_parent_name() 270 if file_parser.is_base_class(parent_clsname): 271 break 272 273 parent_cls = header.get_class(parent_clsname, defined_names) 274 if parent_cls is None: 275 raise Exception('Class does not exist: ' + parent_clsname) 276 277 return make_cpptoc_function_impl(cls, funcs, prefixname, defined_names) 278 279 280def make_cpptoc_virtual_function_assignment_block(funcs, offset, prefixname): 281 new_list = [] 282 old_list = make_file_base.get_func_name_list(funcs) 283 284 impl = '' 285 for func in funcs: 286 suffix = '' 287 suffix1 = '' 288 new_list = make_file_base.get_func_name_count(func.get_capi_name(), old_list, new_list) 289 if new_list.count(func.get_capi_name()) != 0: 290 suffix = str(new_list.count(func.get_capi_name())) 291 elif file_parser.check_func_name_is_key_work(func.get_capi_name()): 292 suffix1 = '0' 293 294 name = func.get_capi_name() 295 impl += ' GetStruct()->' + offset + name + suffix + suffix1 + ' = ' + prefixname + '_' + name + suffix + ';\n' 296 return impl 297 298 299def make_cpptoc_virtual_function_assignment(header, cls, prefixname, 300 defined_names): 301 impl = '' 302 offset = '' 303 parent_cls = cls 304 while True: 305 impl += make_cpptoc_virtual_function_assignment_block(parent_cls.get_virtual_funcs(), offset, prefixname) 306 307 parent_clsname = parent_cls.get_parent_name() 308 if file_parser.is_base_class(parent_clsname): 309 break 310 311 offset += 'base.' 312 parent_cls = header.get_class(parent_clsname, defined_names) 313 if parent_cls is None: 314 raise Exception('Class does not exist: ' + parent_clsname) 315 316 return impl 317 318 319def make_cpptoc_static_function_impl(cls, funcs, defined_names): 320 new_list = [] 321 old_list = make_file_base.get_func_name_list(funcs) 322 323 impl = '#ifdef __cplusplus\n' + \ 324 'extern "C" {\n' + \ 325 '#endif // __cplusplus\n\n' 326 327 for func in funcs: 328 suffix = '' 329 suffix1 = '' 330 new_list = make_file_base.get_func_name_count(func.get_capi_name(), old_list, new_list) 331 if new_list.count(func.get_capi_name()) != 0: 332 suffix = str(new_list.count(func.get_capi_name())) 333 func_name = func.get_capi_name() + suffix 334 parts = func.get_capi_parts(defined_names, True) 335 impl += make_cpptoc_impl_proto(func_name + '_static', func, parts, True) + ' {\n'\ 336 ' ARK_WEB_CPPTOC_DV_LOG();\n\n' 337 338 retval = func.get_retval() 339 retval_type = retval.get_retval_type() 340 if retval_type != 'none': 341 impl += ' return ' 342 impl += 'OHOS::ArkWeb::'+ func_name + '(' 343 344 params = [] 345 args = func.get_arguments() 346 for arg in args: 347 arg_name = arg.get_type().get_name() 348 params.append(arg_name) 349 350 if len(params) > 0: 351 impl += '\n ' + ',\n '.join(params) 352 353 impl += ');\n}\n\n' 354 355 impl += '#ifdef __cplusplus\n' + \ 356 '}\n' + \ 357 '#endif // __cplusplus' 358 359 return impl 360 361 362def make_cpptoc_unwrap_derived(header, cls, base_scoped): 363 derived_classes = make_file_base.get_derived_classes(cls, header) 364 365 if base_scoped: 366 impl = ['', ''] 367 for clsname in derived_classes: 368 impl[0] += ' if (type == '+file_parser.get_wrapper_type_enum(clsname)+') {\n'+\ 369 ' return '+clsname+'CppToC::UnwrapOwn(reinterpret_cast<'+\ 370 file_parser.get_capi_name(clsname, True)+'*>(s));\n'+\ 371 ' }\n' 372 impl[1] += ' if (type == '+file_parser.get_wrapper_type_enum(clsname)+') {\n'+\ 373 ' return '+clsname+'CppToC::UnwrapRaw(reinterpret_cast<'+\ 374 file_parser.get_capi_name(clsname, True)+'*>(s));\n'+\ 375 ' }\n' 376 else: 377 impl = '' 378 for clsname in derived_classes: 379 impl += ' if (type == '+file_parser.get_wrapper_type_enum(clsname)+') {\n'+\ 380 ' return '+clsname+'CppToC::Revert(reinterpret_cast<'+\ 381 file_parser.get_capi_name(clsname, True)+'*>(s));\n'+\ 382 ' }\n' 383 return impl 384 385 386def make_cpptoc_impl_file(header, dir_path, dir_name, clsname): 387 defined_names = header.get_defined_structs() 388 cls = header.get_class(clsname, defined_names) 389 if cls is None: 390 raise Exception('Class does not exist: ' + clsname) 391 392 capiname = cls.get_capi_name() 393 prefixname = file_parser.get_capi_name(clsname, False) 394 395 base_class_name = header.get_base_class_name(clsname) 396 base_scoped = True if base_class_name == 'ArkWebBaseScoped' else False 397 if base_scoped: 398 template_class = 'ArkWebCppToCScoped' 399 else: 400 template_class = 'ArkWebCppToCRefCounted' 401 402 virtualimpl = make_cpptoc_virtual_function_impl(header, cls, prefixname, defined_names) 403 if len(virtualimpl) > 0: 404 virtualimpl = 'namespace {\n\n' + virtualimpl + '} // namespace' 405 406 defined_names.append(cls.get_capi_name()) 407 408 staticimpl = make_cpptoc_function_impl(cls, cls.get_static_funcs(), None, defined_names) 409 410 resultingimpl = staticimpl + virtualimpl 411 412 unwrapderived = make_cpptoc_unwrap_derived(header, cls, base_scoped) 413 414 const = clsname+'CppToC::'+clsname+'CppToC() {\n' 415 const += make_cpptoc_virtual_function_assignment(header, cls, prefixname, 416 defined_names) 417 const += '}\n\n'+ \ 418 clsname+'CppToC::~'+clsname+'CppToC() {\n' 419 const += '}\n\n' 420 421 includes = file_parser.format_translation_includes(header, dir_name, const + resultingimpl + 422 (unwrapderived[0] 423 if base_scoped else unwrapderived)) 424 includes += '#include "base/cpptoc/ark_web_cpptoc_macros.h"\n' 425 426 content = make_file_base.get_copyright() 427 content += '\n' + includes + '\n' + 'namespace OHOS::ArkWeb {\n\n' + resultingimpl + '\n' 428 429 parent_sig = template_class + '<' + clsname + 'CppToC, ' + clsname + ', ' + capiname + '>' 430 const += make_file_base.make_wrapper_type(clsname, parent_sig) 431 432 content += '\n' + const + '\n' + \ 433 '\n} // namespace OHOS::ArkWeb\n\n' 434 435 if len(cls.get_static_funcs()) > 0: 436 staticimpl = make_cpptoc_static_function_impl(cls, cls.get_static_funcs(), defined_names) 437 content += staticimpl 438 439 absolute_dir = os.path.join(os.path.join(dir_path, dir_name), 'cpptoc') 440 absolute_path = os.path.join(absolute_dir, file_parser.get_capi_name(clsname, False) + '_cpptoc.cpp') 441 442 return (content, absolute_path) 443