mirror of
https://github.com/aphrody-labs/cef.git
synced 2026-10-14 05:09:23 +00:00
Unpack the CppToC and CToCpp generator results before writing generated content to stdout. This preserves the existing generator return contracts. Add successful CLI regressions that verify exact output, empty stderr, and unchanged input files.
1053 lines
40 KiB
Python
1053 lines
40 KiB
Python
# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
|
|
# reserved. Use of this source code is governed by a BSD-style license that
|
|
# can be found in the LICENSE file.
|
|
|
|
from __future__ import absolute_import
|
|
from cef_parser import *
|
|
import copy
|
|
import functools
|
|
|
|
|
|
def make_cpptoc_impl_proto(name, func, parts):
|
|
proto = ''
|
|
if func.has_attrib('no_stack_protector'):
|
|
proto += 'NO_STACK_PROTECTOR '
|
|
if isinstance(func, obj_function_virtual):
|
|
proto += parts['retval'] + ' CEF_CALLBACK'
|
|
else:
|
|
proto += 'CEF_EXPORT ' + parts['retval']
|
|
|
|
proto += ' ' + name + '(' + ', '.join(parts['args']) + ')'
|
|
return proto
|
|
|
|
|
|
def make_cpptoc_function_impl_existing(cls, name, func, impl, defined_names,
|
|
version, version_finder):
|
|
notify(name + ' has manual edits')
|
|
|
|
# retrieve the C API prototype parts
|
|
parts = func.get_capi_parts(
|
|
defined_names, True, version=version, version_finder=version_finder)
|
|
|
|
changes = format_translation_changes(impl, parts)
|
|
if len(changes) > 0:
|
|
notify(name + ' prototype changed')
|
|
|
|
return make_cpptoc_impl_proto(name, func,
|
|
parts) + '{' + changes + impl['body'] + '\n}\n'
|
|
|
|
|
|
def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped,
|
|
version, version_finder):
|
|
if not version is None and isinstance(func, obj_function_virtual) and \
|
|
not func.exists_at_version(version):
|
|
raise Exception(
|
|
'Attempting to generate non-existing function %s at version %d' %
|
|
(name, version))
|
|
|
|
# Special handling for the cef_shutdown global function.
|
|
is_cef_shutdown = name == 'cef_shutdown' and isinstance(
|
|
func.parent, obj_header)
|
|
|
|
# retrieve the C API prototype parts
|
|
parts = func.get_capi_parts(
|
|
defined_names, True, version=version, version_finder=version_finder)
|
|
result = make_cpptoc_impl_proto(name, func, parts) + ' {'
|
|
|
|
if isinstance(func.parent, obj_class) and \
|
|
not func.parent.has_attrib('no_debugct_check') and \
|
|
not base_scoped:
|
|
result += '\n shutdown_checker::AssertNotShutdown();\n'
|
|
|
|
invalid = []
|
|
|
|
# retrieve the function arguments
|
|
args = func.get_arguments()
|
|
|
|
# determine the argument types
|
|
for arg in args:
|
|
if arg.get_arg_type() == 'invalid':
|
|
invalid.append(arg.get_name())
|
|
|
|
# retrieve the function return value
|
|
retval = func.get_retval()
|
|
retval_type = retval.get_retval_type()
|
|
if retval_type == 'invalid':
|
|
invalid.append('(return value)')
|
|
retval_default = ''
|
|
else:
|
|
retval_default = retval.get_retval_default(True)
|
|
if len(retval_default) > 0:
|
|
retval_default = ' ' + retval_default
|
|
|
|
if len(invalid) > 0:
|
|
notify(name + ' could not be autogenerated')
|
|
# code could not be auto-generated
|
|
result += '\n // BEGIN DELETE BEFORE MODIFYING'
|
|
result += '\n // AUTO-GENERATED CONTENT'
|
|
result += '\n // COULD NOT IMPLEMENT DUE TO: ' + ', '.join(invalid)
|
|
result += '\n #pragma message("Warning: " __FILE__ ": ' + name + ' is not implemented")'
|
|
result += '\n // END DELETE BEFORE MODIFYING'
|
|
result += '\n}\n\n'
|
|
return result
|
|
|
|
result += '\n // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING\n'
|
|
|
|
result_len = len(result)
|
|
|
|
optional = []
|
|
|
|
# parameter verification
|
|
if isinstance(func, obj_function_virtual):
|
|
result += '\n DCHECK(self);'\
|
|
'\n if (!self) {'\
|
|
'\n return'+retval_default+';'\
|
|
'\n }'
|
|
|
|
for arg in args:
|
|
arg_type = arg.get_arg_type()
|
|
arg_name = arg.get_type().get_name()
|
|
|
|
# skip optional params
|
|
optional_params = arg.parent.get_attrib_list('optional_param')
|
|
if not optional_params is None and arg_name in optional_params:
|
|
optional.append(arg_name)
|
|
continue
|
|
|
|
comment = '\n // Verify param: ' + arg_name + '; type: ' + arg_type
|
|
|
|
if arg_type == 'simple_byref' or arg_type == 'simple_byref_const' or \
|
|
arg_type == 'simple_byaddr' or arg_type == 'bool_byref' or arg_type == 'bool_byaddr' or \
|
|
arg_type == 'struct_byref_const' or arg_type == 'struct_byref' or \
|
|
arg_type == 'string_byref_const' or arg_type == 'string_byref' or \
|
|
arg_type == 'refptr_same' or arg_type == 'refptr_same_byref' or \
|
|
arg_type == 'refptr_diff' or arg_type == 'refptr_diff_byref' or \
|
|
arg_type == 'ownptr_same' or arg_type == 'ownptr_same_byref' or \
|
|
arg_type == 'ownptr_diff' or arg_type == 'ownptr_diff_byref' or \
|
|
arg_type == 'rawptr_same' or arg_type == 'rawptr_same_byref' or \
|
|
arg_type == 'rawptr_diff' or arg_type == 'rawptr_diff_byref' or \
|
|
arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const' or \
|
|
arg_type == 'string_map_single_byref' or arg_type == 'string_map_single_byref_const' or \
|
|
arg_type == 'string_map_multi_byref' or arg_type == 'string_map_multi_byref_const':
|
|
result += comment+\
|
|
'\n DCHECK('+arg_name+');'\
|
|
'\n if (!'+arg_name+') {'\
|
|
'\n return'+retval_default+';'\
|
|
'\n }'
|
|
if arg_type == 'struct_byref_const' or arg_type == 'struct_byref':
|
|
result +=\
|
|
'\n if (!template_util::has_valid_size('+arg_name+')) {'\
|
|
'\n DCHECK(false) << "invalid '+arg_name+'->[base.]size";'\
|
|
'\n return'+retval_default+';'\
|
|
'\n }'
|
|
elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
|
|
arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref' or \
|
|
arg_type == 'ownptr_vec_same_byref' or arg_type == 'ownptr_vec_diff_byref' or \
|
|
arg_type == 'rawptr_vec_same_byref' or arg_type == 'rawptr_vec_diff_byref':
|
|
result += comment+\
|
|
'\n DCHECK('+arg_name+'Count && (*'+arg_name+'Count == 0 || '+arg_name+'));'\
|
|
'\n if (!'+arg_name+'Count || (*'+arg_name+'Count > 0 && !'+arg_name+')) {'\
|
|
'\n return'+retval_default+';'\
|
|
'\n }'
|
|
elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \
|
|
arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \
|
|
arg_type == 'ownptr_vec_same_byref_const' or arg_type == 'ownptr_vec_diff_byref_const' or \
|
|
arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
|
|
result += comment+\
|
|
'\n DCHECK('+arg_name+'Count == 0 || '+arg_name+');'\
|
|
'\n if ('+arg_name+'Count > 0 && !'+arg_name+') {'\
|
|
'\n return'+retval_default+';'\
|
|
'\n }'
|
|
|
|
# check index params
|
|
index_params = arg.parent.get_attrib_list('index_param')
|
|
if not index_params is None and arg_name in index_params:
|
|
result += comment+\
|
|
'\n DCHECK_GE('+arg_name+', 0);'\
|
|
'\n if ('+arg_name+' < 0) {'\
|
|
'\n return'+retval_default+';'\
|
|
'\n }'
|
|
|
|
if len(optional) > 0:
|
|
# Wrap the comment at 80 characters.
|
|
str = '\n // Unverified params: ' + optional[0]
|
|
for name in optional[1:]:
|
|
str += ','
|
|
if len(str) + len(name) + 1 > 80:
|
|
result += str
|
|
str = '\n //'
|
|
str += ' ' + name
|
|
result += str
|
|
|
|
if len(result) != result_len:
|
|
result += '\n'
|
|
result_len = len(result)
|
|
|
|
# parameter translation
|
|
params = []
|
|
|
|
for arg in args:
|
|
arg_type = arg.get_arg_type()
|
|
arg_name = arg.get_type().get_name()
|
|
|
|
comment = '\n // Translate param: ' + arg_name + '; type: ' + arg_type
|
|
|
|
if arg_type == 'simple_byval' or arg_type == 'simple_byaddr':
|
|
params.append(arg_name)
|
|
elif arg_type == 'simple_byref' or arg_type == 'simple_byref_const':
|
|
data_type = arg.get_type().get_type()
|
|
default = arg.get_type().get_result_simple_default()
|
|
result += comment+\
|
|
'\n '+data_type+' '+arg_name+'Val = '+arg_name+'?*'+arg_name+':'+default+';'
|
|
params.append(arg_name + 'Val')
|
|
elif arg_type == 'bool_byval':
|
|
params.append(arg_name + '?true:false')
|
|
elif arg_type == 'bool_byref' or arg_type == 'bool_byaddr':
|
|
result += comment+\
|
|
'\n bool '+arg_name+'Bool = ('+arg_name+' && *'+arg_name+')?true:false;'
|
|
if arg_type == 'bool_byref':
|
|
params.append(arg_name + 'Bool')
|
|
else:
|
|
params.append('&' + arg_name + 'Bool')
|
|
elif arg_type == 'struct_byref_const':
|
|
struct_type = arg.get_type().get_type()
|
|
result += comment+\
|
|
'\n '+struct_type+' '+arg_name+'Obj;'\
|
|
'\n if ('+arg_name+') {'\
|
|
'\n '+arg_name+'Obj.Set(*'+arg_name+', false);'\
|
|
'\n }'
|
|
params.append(arg_name + 'Obj')
|
|
elif arg_type == 'struct_byref':
|
|
struct_type = arg.get_type().get_type()
|
|
result += comment+\
|
|
'\n '+struct_type+' '+arg_name+'Obj;'\
|
|
'\n if ('+arg_name+') {'\
|
|
'\n '+arg_name+'Obj.AttachTo(*'+arg_name+');'\
|
|
'\n }'
|
|
params.append(arg_name + 'Obj')
|
|
elif arg_type == 'string_byref_const':
|
|
params.append('CefString(' + arg_name + ')')
|
|
elif arg_type == 'string_byref':
|
|
result += comment+\
|
|
'\n CefString '+arg_name+'Str('+arg_name+');'
|
|
params.append(arg_name + 'Str')
|
|
elif arg_type == 'refptr_same' or arg_type == 'refptr_diff':
|
|
ptr_class = arg.get_type().get_ptr_type()
|
|
if arg_type == 'refptr_same':
|
|
params.append(ptr_class + 'CppToC_Unwrap(' + arg_name + ')')
|
|
else:
|
|
params.append(ptr_class + 'CToCpp_Wrap(' + arg_name + ')')
|
|
elif arg_type == 'ownptr_same' or arg_type == 'rawptr_same':
|
|
ptr_class = arg.get_type().get_ptr_type()
|
|
if arg_type == 'ownptr_same':
|
|
params.append(ptr_class + 'CppToC_UnwrapOwn(' + arg_name + ')')
|
|
else:
|
|
params.append(ptr_class + 'CppToC_UnwrapRaw(' + arg_name + ')')
|
|
elif arg_type == 'ownptr_diff' or arg_type == 'rawptr_diff':
|
|
ptr_class = arg.get_type().get_ptr_type()
|
|
result += comment+\
|
|
'\n CefOwnPtr<'+ptr_class+'> '+arg_name+'Ptr('+ptr_class+'CToCpp_Wrap('+arg_name+'));'
|
|
if arg_type == 'ownptr_diff':
|
|
params.append('std::move(' + arg_name + 'Ptr)')
|
|
else:
|
|
params.append(arg_name + 'Ptr.get()')
|
|
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
|
|
ptr_class = ptr_class_u = arg.get_type().get_ptr_type()
|
|
if arg_type == 'refptr_same_byref':
|
|
assign = ptr_class + 'CppToC_Unwrap(*' + arg_name + ')'
|
|
else:
|
|
assign = ptr_class + 'CToCpp_Wrap(*' + arg_name + ')'
|
|
result += comment+\
|
|
'\n CefRefPtr<'+ptr_class_u+'> '+arg_name+'Ptr;'\
|
|
'\n if ('+arg_name+' && *'+arg_name+') {'\
|
|
'\n '+arg_name+'Ptr = '+assign+';'\
|
|
'\n }'\
|
|
'\n '+ptr_class+'* '+arg_name+'Orig = '+arg_name+'Ptr.get();'
|
|
params.append(arg_name + 'Ptr')
|
|
elif arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const':
|
|
result += comment+\
|
|
'\n std::vector<CefString> '+arg_name+'List;'\
|
|
'\n transfer_string_list_contents('+arg_name+', '+arg_name+'List);'
|
|
params.append(arg_name + 'List')
|
|
elif arg_type == 'string_map_single_byref' or arg_type == 'string_map_single_byref_const':
|
|
result += comment+\
|
|
'\n std::map<CefString, CefString> '+arg_name+'Map;'\
|
|
'\n transfer_string_map_contents('+arg_name+', '+arg_name+'Map);'
|
|
params.append(arg_name + 'Map')
|
|
elif arg_type == 'string_map_multi_byref' or arg_type == 'string_map_multi_byref_const':
|
|
result += comment+\
|
|
'\n std::multimap<CefString, CefString> '+arg_name+'Multimap;'\
|
|
'\n transfer_string_multimap_contents('+arg_name+', '+arg_name+'Multimap);'
|
|
params.append(arg_name + 'Multimap')
|
|
elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
|
|
arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
|
|
vec_type = arg.get_type().get_vector_type()
|
|
if arg_type == 'simple_vec_byref':
|
|
assign = arg_name + '[i]'
|
|
elif arg_type == 'bool_vec_byref':
|
|
assign = arg_name + '[i]?true:false'
|
|
elif arg_type == 'refptr_vec_same_byref':
|
|
ptr_class = arg.get_type().get_ptr_type()
|
|
assign = ptr_class + 'CppToC_Unwrap(' + arg_name + '[i])'
|
|
elif arg_type == 'refptr_vec_diff_byref':
|
|
ptr_class = arg.get_type().get_ptr_type()
|
|
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i])'
|
|
result += comment+\
|
|
'\n std::vector<'+vec_type+' > '+arg_name+'List;'\
|
|
'\n if ('+arg_name+'Count && *'+arg_name+'Count > 0 && '+arg_name+') {'\
|
|
'\n for (size_t i = 0; i < *'+arg_name+'Count; ++i) {'\
|
|
'\n '+arg_name+'List.push_back('+assign+');'\
|
|
'\n }'\
|
|
'\n }'
|
|
params.append(arg_name + 'List')
|
|
elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \
|
|
arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \
|
|
arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
|
|
vec_type = arg.get_type().get_vector_type()
|
|
if arg_type == 'simple_vec_byref_const':
|
|
assign = arg_name + '[i]'
|
|
elif arg_type == 'bool_vec_byref_const':
|
|
assign = arg_name + '[i]?true:false'
|
|
else:
|
|
ptr_class = arg.get_type().get_ptr_type()
|
|
if arg_type == 'refptr_vec_same_byref_const':
|
|
assign = ptr_class + 'CppToC_Unwrap(' + arg_name + '[i])'
|
|
elif arg_type == 'refptr_vec_diff_byref_const':
|
|
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i])'
|
|
elif arg_type == 'rawptr_vec_same_byref_const':
|
|
assign = ptr_class + 'CppToC_UnwrapRaw(' + arg_name + '[i])'
|
|
elif arg_type == 'rawptr_vec_diff_byref_const':
|
|
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i]).release()'
|
|
result += comment+\
|
|
'\n std::vector<'+vec_type+' > '+arg_name+'List;'\
|
|
'\n if ('+arg_name+'Count > 0) {'\
|
|
'\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
|
|
'\n '+vec_type+' '+arg_name+'Val = '+assign+';'\
|
|
'\n '+arg_name+'List.push_back('+arg_name+'Val);'\
|
|
'\n }'\
|
|
'\n }'
|
|
params.append(arg_name + 'List')
|
|
else:
|
|
raise Exception('Unsupported argument type %s for parameter %s in %s' %
|
|
(arg_type, arg_name, name))
|
|
|
|
if len(result) != result_len:
|
|
result += '\n'
|
|
result_len = len(result)
|
|
|
|
# execution
|
|
result += '\n // Execute\n '
|
|
|
|
if retval_type != 'none':
|
|
# has a return value
|
|
if retval_type == 'simple' or retval_type == 'simple_byaddr':
|
|
result += retval.get_type().get_result_simple_type()
|
|
else:
|
|
result += retval.get_type().get_type()
|
|
result += ' _retval = '
|
|
|
|
if isinstance(func.parent, obj_class):
|
|
# virtual and static class methods
|
|
if isinstance(func, obj_function_virtual):
|
|
ptr_class = cls.get_name()
|
|
if not version_finder is None:
|
|
ptr_class = version_finder(ptr_class, as_cpp=True)
|
|
if cls.get_name() == func.parent.get_name():
|
|
# virtual method called for the current class
|
|
result += ptr_class + 'CppToC::Get(self)->'
|
|
else:
|
|
# virtual method called for a parent class
|
|
result += ptr_class + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name(
|
|
version) + '*>(self))->'
|
|
else:
|
|
result += func.parent.get_name() + '::'
|
|
result += func.get_name() + '('
|
|
|
|
if len(params) > 0:
|
|
result += '\n ' + ',\n '.join(params)
|
|
|
|
result += ');\n'
|
|
|
|
if is_cef_shutdown:
|
|
result += '\n\n#if DCHECK_IS_ON()'\
|
|
'\n shutdown_checker::SetIsShutdown();'\
|
|
'\n#endif\n'
|
|
|
|
result_len = len(result)
|
|
|
|
# parameter restoration
|
|
for arg in args:
|
|
arg_type = arg.get_arg_type()
|
|
arg_name = arg.get_type().get_name()
|
|
|
|
comment = '\n // Restore param: ' + arg_name + '; type: ' + arg_type
|
|
|
|
if arg_type == 'simple_byref':
|
|
result += comment+\
|
|
'\n if ('+arg_name+') {'\
|
|
'\n *'+arg_name+' = '+arg_name+'Val;'\
|
|
'\n }'
|
|
elif arg_type == 'bool_byref' or arg_type == 'bool_byaddr':
|
|
result += comment+\
|
|
'\n if ('+arg_name+') {'\
|
|
'\n *'+arg_name+' = '+arg_name+'Bool?true:false;'\
|
|
'\n }'
|
|
elif arg_type == 'struct_byref':
|
|
result += comment+\
|
|
'\n if ('+arg_name+') {'\
|
|
'\n '+arg_name+'Obj.DetachTo(*'+arg_name+');'\
|
|
'\n }'
|
|
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
|
|
ptr_class = arg.get_type().get_ptr_type()
|
|
if arg_type == 'refptr_same_byref':
|
|
assign = ptr_class + 'CppToC_Wrap(' + arg_name + 'Ptr)'
|
|
else:
|
|
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + 'Ptr)'
|
|
result += comment+\
|
|
'\n if ('+arg_name+') {'\
|
|
'\n if ('+arg_name+'Ptr.get()) {'\
|
|
'\n if ('+arg_name+'Ptr.get() != '+arg_name+'Orig) {'\
|
|
'\n *'+arg_name+' = '+assign+';'\
|
|
'\n }'\
|
|
'\n } else {'\
|
|
'\n *'+arg_name+' = nullptr;'\
|
|
'\n }'\
|
|
'\n }'
|
|
elif arg_type == 'string_vec_byref':
|
|
result += comment+\
|
|
'\n cef_string_list_clear('+arg_name+');'\
|
|
'\n transfer_string_list_contents('+arg_name+'List, '+arg_name+');'
|
|
elif arg_type == 'string_map_single_byref':
|
|
result += comment+\
|
|
'\n cef_string_map_clear('+arg_name+');'\
|
|
'\n transfer_string_map_contents('+arg_name+'Map, '+arg_name+');'
|
|
elif arg_type == 'string_map_multi_byref':
|
|
result += comment+\
|
|
'\n cef_string_multimap_clear('+arg_name+');'\
|
|
'\n transfer_string_multimap_contents('+arg_name+'Multimap, '+arg_name+');'
|
|
elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
|
|
arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
|
|
if arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref':
|
|
assign = arg_name + 'List[i]'
|
|
elif arg_type == 'refptr_vec_same_byref':
|
|
ptr_class = arg.get_type().get_ptr_type()
|
|
assign = ptr_class + 'CppToC_Wrap(' + arg_name + 'List[i])'
|
|
elif arg_type == 'refptr_vec_diff_byref':
|
|
ptr_class = arg.get_type().get_ptr_type()
|
|
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + 'List[i])'
|
|
result += comment+\
|
|
'\n if ('+arg_name+'Count && '+arg_name+') {'\
|
|
'\n *'+arg_name+'Count = std::min('+arg_name+'List.size(), *'+arg_name+'Count);'\
|
|
'\n if (*'+arg_name+'Count > 0) {'\
|
|
'\n for (size_t i = 0; i < *'+arg_name+'Count; ++i) {'\
|
|
'\n '+arg_name+'[i] = '+assign+';'\
|
|
'\n }'\
|
|
'\n }'\
|
|
'\n }'
|
|
elif arg_type == 'rawptr_vec_diff_byref_const':
|
|
result += comment+\
|
|
'\n if ('+arg_name+'Count > 0) {'\
|
|
'\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
|
|
'\n delete '+arg_name+'List[i];'\
|
|
'\n }'\
|
|
'\n }'
|
|
|
|
if len(result) != result_len:
|
|
result += '\n'
|
|
result_len = len(result)
|
|
|
|
if len(result) != result_len:
|
|
result += '\n'
|
|
result_len = len(result)
|
|
|
|
# return translation
|
|
if retval_type != 'none':
|
|
# has a return value
|
|
result += '\n // Return type: ' + retval_type
|
|
if retval_type == 'simple' or retval_type == 'simple_byaddr' or retval_type == 'bool':
|
|
result += '\n return _retval;'
|
|
elif retval_type == 'string':
|
|
result += '\n return _retval.DetachToUserFree();'
|
|
elif retval_type == 'refptr_same':
|
|
ptr_class = retval.get_type().get_ptr_type()
|
|
result += '\n return ' + ptr_class + 'CppToC_Wrap(_retval);'
|
|
elif retval_type == 'refptr_diff':
|
|
ptr_class = retval.get_type().get_ptr_type()
|
|
result += '\n return ' + ptr_class + 'CToCpp_Unwrap(_retval);'
|
|
elif retval_type == 'ownptr_same':
|
|
ptr_class = retval.get_type().get_ptr_type()
|
|
result += '\n return ' + ptr_class + 'CppToC_WrapOwn(std::move(_retval));'
|
|
elif retval_type == 'ownptr_diff':
|
|
ptr_class = retval.get_type().get_ptr_type()
|
|
result += '\n return ' + ptr_class + 'CToCpp_UnwrapOwn(std::move(_retval));'
|
|
else:
|
|
raise Exception('Unsupported return type %s in %s' % (retval_type, name))
|
|
|
|
if len(result) != result_len:
|
|
result += '\n'
|
|
|
|
result += '}\n'
|
|
return result
|
|
|
|
|
|
def make_cpptoc_function_impl(cls, funcs, existing, prefixname, suffixname,
|
|
defined_names, base_scoped, version,
|
|
version_finder):
|
|
impl = ''
|
|
|
|
customized = False
|
|
|
|
for func in funcs:
|
|
if not version is None and isinstance(func, obj_function_virtual) and \
|
|
not func.exists_at_version(version):
|
|
continue
|
|
|
|
name = func.get_capi_name()
|
|
if not prefixname is None:
|
|
name = prefixname + '_' + name
|
|
if not suffixname is None:
|
|
name += '_' + suffixname
|
|
|
|
if version is None:
|
|
pre, post = get_version_surround(func, long=True)
|
|
else:
|
|
pre = post = ''
|
|
|
|
value = get_next_function_impl(existing, name)
|
|
if not value is None \
|
|
and value['body'].find('// AUTO-GENERATED CONTENT') < 0:
|
|
# an implementation exists that was not auto-generated
|
|
customized = True
|
|
impl += pre + make_cpptoc_function_impl_existing(
|
|
cls, name, func, value, defined_names, version,
|
|
version_finder) + post + '\n'
|
|
else:
|
|
impl += pre + make_cpptoc_function_impl_new(
|
|
cls, name, func, defined_names, base_scoped, version,
|
|
version_finder) + post + '\n'
|
|
|
|
if not customized and impl.find('// COULD NOT IMPLEMENT') >= 0:
|
|
customized = True
|
|
|
|
return (impl, customized)
|
|
|
|
|
|
def make_cpptoc_virtual_function_impl(header, cls, existing, prefixname,
|
|
suffixname, defined_names, base_scoped,
|
|
version, version_finder):
|
|
# don't modify the original list
|
|
funcs = copy.copy(cls.get_virtual_funcs(version=version))
|
|
cur_cls = cls
|
|
while True:
|
|
parent_name = cur_cls.get_parent_name()
|
|
if is_base_class(parent_name):
|
|
break
|
|
else:
|
|
parent_cls = header.get_class(parent_name)
|
|
if parent_cls is None:
|
|
raise Exception('Class does not exist: ' + parent_name)
|
|
defined_names.append(parent_cls.get_capi_name(version))
|
|
funcs.extend(parent_cls.get_virtual_funcs(version=version))
|
|
cur_cls = header.get_class(parent_name)
|
|
defined_names.append(cur_cls.get_capi_name(version))
|
|
|
|
return make_cpptoc_function_impl(cls, funcs, existing, prefixname, suffixname,
|
|
defined_names, base_scoped, version,
|
|
version_finder)
|
|
|
|
|
|
def make_cpptoc_virtual_function_assignment_block(cls, offset, prefixname,
|
|
suffixname, version):
|
|
impl = ''
|
|
|
|
funcs = cls.get_virtual_funcs(version_order=True, version=version)
|
|
|
|
for func in funcs:
|
|
# should only include methods directly declared in the current class
|
|
assert func.parent.get_name() == cls.get_name(), func.get_name()
|
|
if version is None:
|
|
pre, post = get_version_surround(func)
|
|
else:
|
|
if func.removed_at_version(version):
|
|
continue
|
|
pre = post = ''
|
|
name = oname = func.get_capi_name()
|
|
if not prefixname is None:
|
|
name = prefixname + '_' + name
|
|
if not suffixname is None:
|
|
name += '_' + suffixname
|
|
impl += pre + ' GetStruct()->' + offset + oname + ' = ' + name + ';\n' + post
|
|
return impl
|
|
|
|
|
|
def make_cpptoc_virtual_function_assignment(header, cls, prefixname, suffixname,
|
|
defined_names, version,
|
|
version_finder):
|
|
impl = make_cpptoc_virtual_function_assignment_block(cls, '', prefixname,
|
|
suffixname, version)
|
|
|
|
cur_cls = cls
|
|
offset = ''
|
|
while True:
|
|
parent_name = cur_cls.get_parent_name()
|
|
offset += 'base.'
|
|
if is_base_class(parent_name):
|
|
break
|
|
else:
|
|
parent_cls = header.get_class(parent_name)
|
|
if parent_cls is None:
|
|
raise Exception('Class does not exist: ' + parent_name)
|
|
defined_names.append(parent_cls.get_capi_name(version))
|
|
impl += make_cpptoc_virtual_function_assignment_block(
|
|
parent_cls, offset, prefixname, suffixname, version)
|
|
cur_cls = header.get_class(parent_name)
|
|
defined_names.append(cur_cls.get_capi_name(version))
|
|
|
|
return impl
|
|
|
|
|
|
def make_cpptoc_unwrap_derived(header, cls, base_scoped, version):
|
|
# identify all classes that derive from cls
|
|
derived_classes = []
|
|
cur_clsname = cls.get_name()
|
|
allclasses = header.get_classes()
|
|
for cur_cls in allclasses:
|
|
if cur_cls.get_name() == cur_clsname:
|
|
continue
|
|
if cur_cls.has_parent(cur_clsname):
|
|
derived_classes.append(cur_cls.get_name())
|
|
|
|
derived_classes = sorted(derived_classes)
|
|
|
|
if base_scoped:
|
|
impl = ['', '']
|
|
for clsname in derived_classes:
|
|
derived_cls = header.get_class(clsname)
|
|
if version is None:
|
|
capiname = derived_cls.get_capi_name()
|
|
pre, post = get_version_surround(derived_cls)
|
|
else:
|
|
if not derived_cls.exists_at_version(version):
|
|
continue
|
|
capiname = derived_cls.get_capi_name(first_version=True)
|
|
pre = post = ''
|
|
|
|
impl[0] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
|
|
' return '+clsname+'CppToC_UnwrapOwn(reinterpret_cast<'+capiname+'*>(s));\n'+\
|
|
' }\n' + post
|
|
impl[1] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
|
|
' return '+clsname+'CppToC_UnwrapRaw(reinterpret_cast<'+capiname+'*>(s));\n'+\
|
|
' }\n' + post
|
|
else:
|
|
impl = ''
|
|
for clsname in derived_classes:
|
|
derived_cls = header.get_class(clsname)
|
|
if version is None:
|
|
capiname = derived_cls.get_capi_name()
|
|
pre, post = get_version_surround(derived_cls)
|
|
else:
|
|
if not derived_cls.exists_at_version(version):
|
|
continue
|
|
capiname = derived_cls.get_capi_name(first_version=True)
|
|
pre = post = ''
|
|
|
|
impl += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
|
|
' return '+clsname+'CppToC_Unwrap(reinterpret_cast<'+capiname+'*>(s));\n'+\
|
|
' }\n' + post
|
|
return impl
|
|
|
|
|
|
def make_cpptoc_version_wrappers(header, cls, base_scoped, versions):
|
|
assert len(versions) > 0
|
|
|
|
clsname = cls.get_name()
|
|
typename = clsname + 'CppToC'
|
|
structname = cls.get_capi_name(version=versions[0])
|
|
|
|
rversions = sorted(versions, reverse=True)
|
|
|
|
notreached = format_notreached(
|
|
True,
|
|
'" called with invalid version " << version',
|
|
default_retval='nullptr')
|
|
|
|
impl = ''
|
|
|
|
if base_scoped:
|
|
impl += structname + '* ' + typename + '_WrapOwn(CefOwnPtr<' + clsname + '> c) {\n' + \
|
|
' const int version = cef_api_version();\n'
|
|
|
|
for version in rversions:
|
|
vstr = str(version)
|
|
impl += ' if (version >= ' + vstr + ') {\n'
|
|
if versions[0] == version:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::WrapOwn(std::move(c));\n'
|
|
else:
|
|
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CppToC::WrapOwn(std::move(c)));\n'
|
|
impl += ' }\n'
|
|
|
|
impl += ' ' + notreached + '\n'+ \
|
|
'}\n\n' + \
|
|
'std::pair<CefOwnPtr<CefBaseScoped>, '+ structname + '*> ' + typename + '_WrapRaw(CefRawPtr<' + clsname + '> c) {\n' + \
|
|
' const int version = cef_api_version();\n'
|
|
|
|
for version in rversions:
|
|
vstr = str(version)
|
|
impl += ' if (version >= ' + vstr + ') {\n'
|
|
if versions[0] == version:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::WrapRaw(std::move(c));\n'
|
|
else:
|
|
impl += ' auto [ownPtr, structPtr] = ' + clsname + '_' + vstr + '_CppToC::WrapRaw(std::move(c));\n' + \
|
|
' return std::make_pair(std::move(ownPtr), reinterpret_cast<' + structname + '*>(structPtr));\n'
|
|
impl += ' }\n'
|
|
|
|
impl += ' ' + notreached + '\n'+ \
|
|
'}\n\n' + \
|
|
'CefOwnPtr<' + clsname + '> ' + typename + '_UnwrapOwn('+ structname + '* s) {\n' + \
|
|
' const int version = cef_api_version();\n'
|
|
|
|
for version in rversions:
|
|
vstr = str(version)
|
|
impl += ' if (version >= ' + vstr + ') {\n'
|
|
if versions[0] == version:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapOwn(s);\n'
|
|
else:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapOwn(reinterpret_cast<' + cls.get_capi_name(
|
|
version) + '*>(s));\n'
|
|
impl += ' }\n'
|
|
|
|
impl += ' ' + notreached + '\n'+ \
|
|
'}\n\n' + \
|
|
'CefRawPtr<' + clsname + '> ' + typename + '_UnwrapRaw('+ structname + '* s) {\n' + \
|
|
' const int version = cef_api_version();\n'
|
|
|
|
for version in rversions:
|
|
vstr = str(version)
|
|
impl += ' if (version >= ' + vstr + ') {\n'
|
|
if versions[0] == version:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapRaw(s);\n'
|
|
else:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapRaw(reinterpret_cast<' + cls.get_capi_name(
|
|
version) + '*>(s));\n'
|
|
impl += ' }\n'
|
|
|
|
impl += ' ' + notreached + '\n'+ \
|
|
'}\n\n' + \
|
|
'CefBaseScoped* ' + typename + '_GetWrapper('+ structname + '* s) {\n' + \
|
|
' const int version = cef_api_version();\n'
|
|
|
|
for version in rversions:
|
|
vstr = str(version)
|
|
impl += ' if (version >= ' + vstr + ') {\n'
|
|
if versions[0] == version:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::GetWrapper(s);\n'
|
|
else:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::GetWrapper(reinterpret_cast<' + cls.get_capi_name(
|
|
version) + '*>(s));\n'
|
|
impl += ' }\n'
|
|
|
|
impl += ' ' + notreached + '\n'+ \
|
|
'}\n'
|
|
else:
|
|
impl += structname + '* ' + typename + '_Wrap(CefRefPtr<' + clsname + '> c) {\n' + \
|
|
' const int version = cef_api_version();\n'
|
|
|
|
for version in rversions:
|
|
vstr = str(version)
|
|
impl += ' if (version >= ' + vstr + ') {\n'
|
|
if versions[0] == version:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::Wrap(c);\n'
|
|
else:
|
|
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CppToC::Wrap(c));\n'
|
|
impl += ' }\n'
|
|
|
|
impl += ' ' + notreached + '\n'+ \
|
|
'}\n\n' + \
|
|
'CefRefPtr<' + clsname + '> ' + typename + '_Unwrap('+ structname + '* s) {\n' + \
|
|
' const int version = cef_api_version();\n'
|
|
|
|
for version in rversions:
|
|
vstr = str(version)
|
|
impl += ' if (version >= ' + vstr + ') {\n'
|
|
if versions[0] == version:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::Unwrap(s);\n'
|
|
else:
|
|
impl += ' return ' + clsname + '_' + vstr + '_CppToC::Unwrap(reinterpret_cast<' + cls.get_capi_name(
|
|
version) + '*>(s));\n'
|
|
impl += ' }\n'
|
|
|
|
impl += ' ' + notreached + '\n'+ \
|
|
'}\n'
|
|
|
|
return impl + '\n'
|
|
|
|
|
|
def _version_finder(header, version, name, as_cpp=False):
|
|
assert version is None or isinstance(version, int), version
|
|
assert name[-1] != '*', name
|
|
|
|
if as_cpp:
|
|
cls = header.get_class(name)
|
|
if cls is None:
|
|
return name
|
|
return cls.get_name(version=version)
|
|
|
|
cls = header.get_capi_class(name)
|
|
if not cls is None:
|
|
return cls.get_capi_name(first_version=True)
|
|
return name
|
|
|
|
|
|
def make_cpptoc_class_impl(header, clsname, impl):
|
|
# structure names that have already been defined
|
|
defined_names = header.get_defined_structs()
|
|
|
|
# retrieve the class and populate the defined names
|
|
cls = header.get_class(clsname)
|
|
if cls is None:
|
|
raise Exception('Class does not exist: ' + clsname)
|
|
|
|
prefixname = get_capi_name(clsname[3:], False)
|
|
|
|
base_class_name = header.get_base_class_name(clsname)
|
|
base_scoped = True if base_class_name == 'CefBaseScoped' else False
|
|
if base_scoped:
|
|
template_class = 'CefCppToCScoped'
|
|
else:
|
|
template_class = 'CefCppToCRefCounted'
|
|
|
|
with_versions = cls.is_library_side()
|
|
versions = list(cls.get_all_versions()) if with_versions else (None,)
|
|
|
|
# retrieve the existing static function implementations
|
|
existing_static = get_function_impls(impl, 'CEF_EXPORT')
|
|
|
|
# retrieve the existing virtual function implementations
|
|
existing_virtual = get_function_impls(impl, 'CEF_CALLBACK')
|
|
|
|
staticout = virtualout = ''
|
|
customized = False
|
|
first = True
|
|
idx = 0
|
|
|
|
for version in versions:
|
|
version_finder = functools.partial(_version_finder, header,
|
|
version) if with_versions else None
|
|
defined_names.append(cls.get_capi_name(version=version))
|
|
|
|
if first:
|
|
first = False
|
|
|
|
# generate static functions
|
|
staticimpl, scustomized = make_cpptoc_function_impl(
|
|
cls,
|
|
cls.get_static_funcs(), existing_static, None, None, defined_names,
|
|
base_scoped, version, version_finder)
|
|
if len(staticimpl) > 0:
|
|
staticout += '// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + staticimpl
|
|
if scustomized:
|
|
customized = True
|
|
|
|
if len(versions) > 1:
|
|
staticout += '// HELPER FUNCTIONS - Do not edit by hand.\n\n'
|
|
staticout += make_cpptoc_version_wrappers(header, cls, base_scoped,
|
|
versions)
|
|
|
|
comment = '' if version is None else (' FOR VERSION %d' % version)
|
|
|
|
suffixname = str(version) if (len(versions) > 1 and version > 0) else None
|
|
|
|
# generate virtual functions
|
|
virtualimpl, vcustomized = make_cpptoc_virtual_function_impl(
|
|
header, cls, existing_virtual, prefixname, suffixname, defined_names,
|
|
base_scoped, version, version_finder)
|
|
if len(virtualimpl) > 0:
|
|
virtualout += 'namespace {\n\n// MEMBER FUNCTIONS' + comment + ' - Body may be edited by hand.\n\n' + \
|
|
virtualimpl + '} // namespace\n\n'
|
|
if vcustomized:
|
|
customized = True
|
|
|
|
# any derived classes can be unwrapped
|
|
unwrapderived = make_cpptoc_unwrap_derived(header, cls, base_scoped,
|
|
version)
|
|
|
|
capiname = cls.get_capi_name(version=version)
|
|
typename = cls.get_name(version=version) + 'CppToC'
|
|
|
|
const = '// CONSTRUCTOR' + comment + ' - Do not edit by hand.\n\n'+ \
|
|
typename+'::'+typename+'() {\n'
|
|
|
|
if not version is None:
|
|
if idx < len(versions) - 1:
|
|
condition = 'version < %d || version >= %d' % (version, versions[idx
|
|
+ 1])
|
|
else:
|
|
condition = 'version < %d' % version
|
|
|
|
const += ' const int version = cef_api_version();\n' + \
|
|
' LOG_IF(FATAL, ' + condition + ') << __func__ << " called with invalid version " << version;\n\n'
|
|
|
|
const += make_cpptoc_virtual_function_assignment(header, cls, prefixname,
|
|
suffixname, defined_names,
|
|
version, version_finder)
|
|
const += '}\n\n'+ \
|
|
'// DESTRUCTOR' + comment + ' - Do not edit by hand.\n\n'+ \
|
|
typename+'::~'+typename+'() {\n'
|
|
|
|
if not cls.has_attrib('no_debugct_check') and not base_scoped:
|
|
const += ' shutdown_checker::AssertNotShutdown();\n'
|
|
|
|
const += '}\n\n'
|
|
|
|
parent_sig = template_class + '<' + typename + ', ' + clsname + ', ' + capiname + '>'
|
|
notreached = format_notreached(
|
|
with_versions,
|
|
'" called with unexpected class type " << type',
|
|
default_retval='nullptr')
|
|
|
|
if base_scoped:
|
|
const += 'template<> CefOwnPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, '+capiname+'* s) {\n' + \
|
|
unwrapderived[0] + \
|
|
' ' + notreached + '\n'+ \
|
|
'}\n\n' + \
|
|
'template<> CefRawPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, '+capiname+'* s) {\n' + \
|
|
unwrapderived[1] + \
|
|
' ' + notreached + '\n'+ \
|
|
'}\n\n'
|
|
else:
|
|
const += 'template<> CefRefPtr<'+clsname+'> '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+capiname+'* s) {\n' + \
|
|
unwrapderived + \
|
|
' ' + notreached + '\n'+ \
|
|
'}\n\n'
|
|
|
|
const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum(
|
|
clsname) + ';\n\n'
|
|
|
|
virtualout += const
|
|
idx += 1
|
|
|
|
out = staticout + virtualout
|
|
|
|
# determine what includes are required by identifying what translation
|
|
# classes are being used
|
|
includes = format_translation_includes(
|
|
header,
|
|
out + (unwrapderived[0] if base_scoped else unwrapderived),
|
|
with_versions=with_versions)
|
|
|
|
# build the final output
|
|
result = get_copyright()
|
|
|
|
result += includes + '\n'
|
|
|
|
if with_versions:
|
|
pre = post = ''
|
|
else:
|
|
pre, post = get_version_surround(cls, long=True)
|
|
if len(pre) > 0:
|
|
result += pre + '\n'
|
|
|
|
result += out + '\n'
|
|
|
|
if len(post) > 0:
|
|
result += post + '\n'
|
|
|
|
return (result, customized)
|
|
|
|
|
|
def make_cpptoc_global_impl(header, impl):
|
|
# structure names that have already been defined
|
|
defined_names = header.get_defined_structs()
|
|
|
|
# retrieve the existing global function implementations
|
|
existing = get_function_impls(impl, 'CEF_EXPORT')
|
|
|
|
version_finder = functools.partial(_version_finder, header, None)
|
|
|
|
# generate global functions
|
|
impl, customized = make_cpptoc_function_impl(None,
|
|
header.get_funcs(), existing,
|
|
None, None, defined_names, False,
|
|
None, version_finder)
|
|
if len(impl) > 0:
|
|
impl = '\n// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + impl
|
|
|
|
includes = ''
|
|
|
|
# include required headers for global functions
|
|
paths = set()
|
|
for func in header.get_funcs():
|
|
filename = func.get_file_name()
|
|
paths.add('include/' + func.get_file_name())
|
|
paths.add('include/capi/' + func.get_capi_file_name(versions=True))
|
|
|
|
# determine what includes are required by identifying what translation
|
|
# classes are being used
|
|
includes += format_translation_includes(
|
|
header, impl, with_versions=True, other_includes=paths)
|
|
|
|
# build the final output
|
|
result = get_copyright()
|
|
|
|
result += includes + '\n' + impl
|
|
|
|
return (result, customized)
|
|
|
|
|
|
def write_cpptoc_impl(header, clsname, dir):
|
|
if clsname is None:
|
|
# global file
|
|
file = dir
|
|
else:
|
|
# class file
|
|
# give the output file the same directory offset as the input file
|
|
cls = header.get_class(clsname)
|
|
dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
|
|
file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_cpptoc.cc')
|
|
|
|
set_notify_context(file)
|
|
|
|
if path_exists(file):
|
|
oldcontents = read_file(file)
|
|
else:
|
|
oldcontents = ''
|
|
|
|
if clsname is None:
|
|
newcontents, customized = make_cpptoc_global_impl(header, oldcontents)
|
|
else:
|
|
newcontents, customized = make_cpptoc_class_impl(header, clsname,
|
|
oldcontents)
|
|
|
|
set_notify_context(None)
|
|
|
|
return (file, newcontents, customized)
|
|
|
|
|
|
# test the module
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
# verify that the correct number of command-line arguments are provided
|
|
if len(sys.argv) < 4:
|
|
sys.stderr.write('Usage: ' + sys.argv[0] +
|
|
' <infile> <classname> <existing_impl>')
|
|
sys.exit()
|
|
|
|
# create the header object
|
|
header = obj_header()
|
|
header.add_file(sys.argv[1])
|
|
|
|
# read the existing implementation file into memory
|
|
try:
|
|
with open(sys.argv[3], 'r') as f:
|
|
data = f.read()
|
|
except IOError as e:
|
|
(errno, strerror) = e.args
|
|
raise Exception('Failed to read file ' + sys.argv[3] + ': ' + strerror)
|
|
else:
|
|
f.close()
|
|
|
|
# dump the result to stdout
|
|
result, _ = make_cpptoc_class_impl(header, sys.argv[2], data)
|
|
sys.stdout.write(result)
|