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