file modules/classutils.py
[No description available]
Namespaces
Name |
---|
modules |
modules::classutils |
Source code
####################################
# #
# Utility functions for handling #
# C++ classes with BOSS #
# #
####################################
from __future__ import print_function
from collections import OrderedDict
import os
# import modules.cfg as cfg
import modules.active_cfg as active_cfg
exec("import configs." + active_cfg.module_name + " as cfg")
import modules.gb as gb
import modules.funcutils as funcutils
import modules.utils as utils
import modules.exceptions as exceptions
import modules.infomsg as infomsg
# ====== getAbstractClassName ========
def getAbstractClassName(input_name, prefix=gb.abstr_class_prefix, short=False):
if '::' in input_name:
namespaces, short_class_name = input_name.rsplit('::',1)
abstract_class_name = namespaces + '::' + gb.abstr_class_prefix + short_class_name
else:
abstract_class_name = gb.abstr_class_prefix + input_name
if short == True:
return abstract_class_name.rsplit('::',1)[-1]
else:
return abstract_class_name
# ====== END: getAbstractClassName ========
# ====== constrEmptyTemplClassDecl ========
def constrEmptyTemplClassDecl(abstr_class_name_short, namespaces, template_bracket, indent=4):
n_indents = len(namespaces)
class_decl = ''
class_decl += utils.constrNamespace(namespaces, 'open')
class_decl += ' '*n_indents*indent + 'template ' + template_bracket + '\n'
class_decl += ' '*n_indents*indent + 'class ' + abstr_class_name_short + ' {};\n'
class_decl += utils.constrNamespace(namespaces, 'close')
class_decl += '\n'
return class_decl
# ====== END: constrEmptyTemplClassDecl ========
# ====== constrTemplForwDecl ========
def constrTemplForwDecl(class_name_short, namespaces, template_bracket, indent=4):
n_indents = len(namespaces)
forw_decl = ''
forw_decl += utils.constrNamespace(namespaces, 'open')
forw_decl += ' '*n_indents*indent + 'template ' + template_bracket + '\n'
forw_decl += ' '*n_indents*indent + 'class ' + class_name_short + ';\n'
forw_decl += utils.constrNamespace(namespaces, 'close')
forw_decl += '\n'
return forw_decl
# ====== END: constrTemplForwDecl ========
# ====== constrAbstractClassDecl ========
def constrAbstractClassDecl(class_el, class_name, abstr_class_name, namespaces, indent=4, file_for_gambit=False, template_types=[], has_copy_constructor=True, construct_assignment_operator=True):
n_indents = len(namespaces)
# Check template_types argument:
if len(template_types) > 0:
is_template = True
else:
is_template = False
# Create list of all 'non-artificial' members of the class
member_elements = utils.getMemberElements(class_el, include_artificial=False)
# Get list of dicts with info on parent classes
parent_classes = utils.getParentClasses(class_el)
#
# Construct the abstract class declaration
#
class_decl = ''
# - Construct the beginning of the namespaces
class_decl += utils.constrNamespace(namespaces, 'open')
# - If this class is a template specialization, add 'template <>' at the top
if is_template == True:
class_decl += ' '*n_indents*indent + 'template <>\n'
# - Construct the declaration line, with inheritance of abstract classes
inheritance_line = ''
for parent_dict in parent_classes:
if parent_dict['loaded']:
inheritance_line += 'virtual ' + parent_dict['access'] + ' ' + parent_dict['abstr_class_name']['long_templ'] + ', '
elif parent_dict['fundamental'] or parent_dict['std']:
# inheritance_line += 'virtual ' + parent_dict['access'] + ' ' + parent_dict['class_name']['long_templ'] + ', '
reason = 'Avoid inheritance ambiguity.'
infomsg.ParentClassIgnored(abstr_class_name['short'], parent_dict['class_name']['long_templ'], reason).printMessage()
else:
reason = 'Not loaded or accepted type.'
infomsg.ParentClassIgnored(abstr_class_name['short'], parent_dict['class_name']['long_templ'], reason).printMessage()
continue
inheritance_line = inheritance_line.rstrip(', ')
# If no other parent classes, add AbstractBase
if inheritance_line == '':
inheritance_line = ' : public virtual AbstractBase'
else:
inheritance_line = ' : ' + inheritance_line
class_decl += ' '*n_indents*indent
if is_template:
class_decl += 'class ' + abstr_class_name['short'] + '<' + ','.join(template_types) + '>' + inheritance_line + '\n'
else:
class_decl += 'class ' + abstr_class_name['short'] + inheritance_line + '\n'
# - Construct body of class declaration
current_access = ''
class_decl += ' '*n_indents*indent
class_decl += '{' + '\n'
done_members = []
ptr_members_for_init = []
for el in member_elements:
# Check access
element_access = el.get('access')
if element_access != 'public':
continue
if current_access != element_access:
class_decl += ' '*(n_indents+1)*indent
class_decl += element_access + ':' +'\n'
current_access = element_access
#
# Add code based on what element type this is
#
if el.tag in ['Constructor', 'Destructor']:
pass # (An empty virtual destructor will be added later)
elif el.tag in ['Method', 'OperatorMethod']:
# Check if this is an operator function
is_operator = False
if el.tag == 'OperatorMethod':
is_operator = True
# Check if this member function should be ignored.
if funcutils.ignoreFunction(el):
# infomsg.IgnoredMemberFunction( is_operator*'operator' + el.get('name') ).printMessage()
continue
# Check if this member function makes use of loaded types
uses_loaded_type = funcutils.usesLoadedType(el)
return_type_dict = utils.findType( gb.id_dict[el.get('returns')] )
return_el = return_type_dict['el']
pointerness = return_type_dict['pointerness']
is_ref = return_type_dict['is_reference']
return_kw = return_type_dict['cv_qualifiers']
return_kw_str = ' '.join(return_kw) + ' '*bool(len(return_kw))
return_type = return_type_dict['name'] + '*'*pointerness + '&'*is_ref
return_is_loaded = utils.isLoadedClass(return_el)
args = funcutils.getArgs(el)
w_args = funcutils.constrWrapperArgs(args, add_ref=True)
# If return type is a known class, add '::' for absolute namespace.
if (not return_is_loaded) and utils.isKnownClass(return_el):
return_type = '::' + return_type
# Check constness
if ('const' in el.keys()) and (el.get('const')=='1'):
is_const = True
else:
is_const = False
# If default arguments are used, we need to generate overloaded versions
n_overloads = funcutils.numberOfDefaultArgs(el)
# One overloaded version for each set of default arguments
for remove_n_args in range(n_overloads+1):
if remove_n_args == 0:
use_args = args
use_w_args = w_args
else:
use_args = args[:-remove_n_args]
use_w_args = w_args[:-remove_n_args]
w_args_bracket = funcutils.constrArgsBracket(use_w_args, include_arg_name=True, include_arg_type=True, include_namespace=True)
w_args_bracket_notypes = funcutils.constrArgsBracket(use_w_args, include_arg_name=True, include_arg_type=False)
w_args_bracket_nonames = funcutils.constrArgsBracket(use_w_args, include_arg_name=False, include_arg_type=True, include_namespace=True)
if is_operator:
if uses_loaded_type:
w_func_name = 'operator_' + gb.operator_names[el.get('name')] + gb.code_suffix
else:
w_func_name = 'operator' + el.get('name')
else:
if uses_loaded_type or (remove_n_args>0):
w_func_name = el.get('name') + gb.code_suffix
else:
w_func_name = el.get('name')
#
# If the method makes use of a loaded class, construct a pair of wrapper methods.
#
if uses_loaded_type:
# Construct the virtual member function that is overridden, e.g.:
#
# virtual X* getX_GAMBIT(arguments) {}
#
if return_is_loaded:
if is_ref:
# w_return_type = toWrapperType(return_type, include_namespace=True, include_global_namespace=True)
w_return_type = toAbstractType(return_type, include_namespace=True)
elif (not is_ref) and (pointerness > 0):
w_return_type = toAbstractType(return_type, include_namespace=True)
else:
w_return_type = toAbstractType(return_type, include_namespace=True, add_pointer=True, remove_reference=True)
else:
w_return_type = return_type
class_decl += '\n'
class_decl += ' '*(n_indents+2)*indent
class_decl += 'virtual ' + return_kw_str + w_return_type + ' ' + w_func_name + w_args_bracket_nonames + is_const*' const' + ' =0;' + '\n'
#
# If the method does not make use of any loaded class, construct a single virtual method
#
else:
class_decl += '\n'
class_decl += ' '*(n_indents+2)*indent
class_decl += 'virtual ' + return_kw_str + return_type + ' ' + w_func_name + w_args_bracket_nonames + is_const*' const' + ' =0;' + '\n'
#
# If element is a public member variable of accepted type, construct virtual method that returns a reference to this variable
#
elif (el.tag in ('Field', 'Variable')) and (el.get('access') == 'public') and isAcceptedMemberVariable(el):
class_decl += '\n'
class_decl += constrVariableRefFunction(el, virtual=True, indent=indent, n_indents=n_indents+2)
# For member variables that are of type pointer-to-loaded-class, create a pointer-to-wrapper-class member variable
if utils.isLoadedClass(el):
el_type_dict = utils.findType(el)
pointerness = el_type_dict['pointerness']
is_ref = el_type_dict['is_reference']
if (pointerness > 0) and (not is_ref):
el_type = el_type_dict['name'] + '*'*pointerness
variable_name = el.get('name') + gb.code_suffix
class_decl += ' '*(n_indents+2)*indent + el_type + ' ' + variable_name + ';\n'
# Register variable name so that it can be initialized in the constructor
ptr_members_for_init.append(variable_name)
#
# Ignore element
#
else:
pass
# - Member functions of the abstract class living in GAMBIT should never be called. If that happens, something is very wrong.
general_boss_warning = 'BOSS WARNING: Problem detected with the BOSSed class %s from backend %s. The function %s::%s in GAMBIT should never have been called...'
# - Construct 'pointer_assign' and 'pointer_copy' functions
if class_name['long_templ'] in gb.contains_pure_virtual_members:
reason = "Contains pure virtual member functions."
infomsg.NoPointerCopyAndAssignmentFunctions(class_name['long_templ'], reason).printMessage()
else:
class_decl += '\n'
if has_copy_constructor or construct_assignment_operator:
class_decl += ' '*(n_indents+1)*indent + 'public:\n'
if construct_assignment_operator:
for parent_dict in parent_classes:
if (parent_dict['loaded']) and (parent_dict['class_name']['long_templ'] not in gb.contains_pure_virtual_members):
class_decl += ' '*(n_indents+2)*indent + 'using ' + parent_dict['abstr_class_name']['long_templ'] + '::pointer_assign' + gb.code_suffix + ';\n'
class_decl += constrPtrAssignFunc(class_el, abstr_class_name['short'], class_name['short'], virtual=True, indent=indent, n_indents=n_indents+2)
if has_copy_constructor:
class_decl += constrPtrCopyFunc(class_el, abstr_class_name['short'], class_name['short'], virtual=True, indent=indent, n_indents=n_indents+2)
# - Construct code needed for 'destructor pattern' (abstract class and wrapper class must can delete each other)
class_decl += '\n'
class_decl += ' '*(n_indents+1)*indent + 'private:\n'
class_decl += ' '*(n_indents+2)*indent + class_name['short'] + '* wptr;\n'
class_decl += ' '*(n_indents+2)*indent + 'bool delete_wrapper;\n'
class_decl += ' '*(n_indents+1)*indent + 'public:\n'
class_decl += ' '*(n_indents+2)*indent + class_name['short'] + '* get_wptr() { return wptr; }\n'
class_decl += ' '*(n_indents+2)*indent + 'void set_wptr(' + class_name['short'] + '* wptr_in) { wptr = wptr_in; }\n'
class_decl += ' '*(n_indents+2)*indent + 'bool get_delete_wrapper() { return delete_wrapper; }\n'
class_decl += ' '*(n_indents+2)*indent + 'void set_delete_wrapper(bool del_wrp_in) { delete_wrapper = del_wrp_in; }\n'
# - Constructor
class_decl += '\n'
class_decl += ' '*(n_indents+1)*indent + 'public:\n'
class_decl += ' '*(n_indents+2)*indent + abstr_class_name['short'] + '()\n'
class_decl += ' '*(n_indents+2)*indent + '{\n'
if gb.debug_mode:
class_decl += ' '*(n_indents+3)*indent + 'std::cerr << "DEBUG: " << this << " ' + abstr_class_name['short'] + ' ctor" << std::endl;\n'
class_decl += ' '*(n_indents+3)*indent + 'wptr = 0;\n'
class_decl += ' '*(n_indents+3)*indent + 'delete_wrapper = false;\n'
class_decl += ' '*(n_indents+2)*indent + '}\n'
# - Copy constructor
# -- Construct code for calling copy constructors of *all* parent classes.
# (Required because this is the copy ctor of an abstract base class.)
all_parent_classes = utils.getAllParentClasses(class_el, only_loaded_classes=True, return_dicts=True, reverse_order=True)
parent_cctors_line = ''
for parent_dict in all_parent_classes:
if parent_dict['loaded']:
parent_cctors_line += parent_dict['abstr_class_name']['long_templ'] + '(in), '
elif parent_dict['fundamental'] or parent_dict['std']:
reason = 'Avoid inheritance ambiguity.'
infomsg.ParentClassIgnored(abstr_class_name['short'], parent_dict['class_name']['long_templ'], reason).printMessage()
else:
reason = 'Not loaded or accepted type.'
infomsg.ParentClassIgnored(abstr_class_name['short'], parent_dict['class_name']['long_templ'], reason).printMessage()
continue
parent_cctors_line = parent_cctors_line.rstrip(', ')
class_decl += '\n'
if parent_cctors_line == '':
class_decl += ' '*(n_indents+2)*indent + abstr_class_name['short'] + '(const ' + abstr_class_name['short'] + '&)\n'
else:
parent_cctors_line = parent_cctors_line.rstrip(',\n') + '\n'
class_decl += ' '*(n_indents+2)*indent + abstr_class_name['short'] + '(const ' + abstr_class_name['short'] + '& in) : \n'
class_decl += ' '*(n_indents+3)*indent + parent_cctors_line
class_decl += ' '*(n_indents+2)*indent + '{\n'
if gb.debug_mode:
class_decl += ' '*(n_indents+3)*indent + 'std::cerr << "DEBUG: " << this << " ' + abstr_class_name['short'] + ' copy ctor" << std::endl;\n'
class_decl += ' '*(n_indents+3)*indent + 'wptr = 0;\n'
class_decl += ' '*(n_indents+3)*indent + 'delete_wrapper = false;\n'
class_decl += ' '*(n_indents+2)*indent + '}\n'
# - Assignment operator. (Actually, no copying should be done. It only returns *this.)
class_decl += '\n'
class_decl += ' '*(n_indents+2)*indent + abstr_class_name['short'] + '& operator=(const ' + abstr_class_name['short'] + '&) { return *this; }\n'
# - Function init_wrapper()
if file_for_gambit:
class_decl += '\n'
class_decl += ' '*(n_indents+2)*indent + 'virtual void init_wrapper() =0;\n'
else:
class_decl += '\n'
class_decl += ' '*(n_indents+2)*indent + 'virtual void init_wrapper()\n'
class_decl += ' '*(n_indents+2)*indent + '{\n'
class_decl += ' '*(n_indents+3)*indent + 'if (wptr == 0)\n'
class_decl += ' '*(n_indents+3)*indent + '{\n'
class_decl += ' '*(n_indents+4)*indent + 'wptr = wrapper_creator(this);\n'
# class_decl += ' '*(n_indents+4)*indent + 'wrapper_creator(this);\n'
class_decl += ' '*(n_indents+4)*indent + 'delete_wrapper = true;\n'
class_decl += ' '*(n_indents+3)*indent + '}\n'
class_decl += ' '*(n_indents+2)*indent + '}\n'
# - Function get_init_wptr()
class_decl += '\n'
class_decl += ' '*(n_indents+2)*indent + class_name['short'] + '* get_init_wptr()\n'
class_decl += ' '*(n_indents+2)*indent + '{\n'
class_decl += ' '*(n_indents+3)*indent + 'init_wrapper();\n'
class_decl += ' '*(n_indents+3)*indent + 'return wptr;\n'
class_decl += ' '*(n_indents+2)*indent + '}\n'
# - Function get_init_wref()
class_decl += '\n'
class_decl += ' '*(n_indents+2)*indent + class_name['short'] + '& get_init_wref()\n'
class_decl += ' '*(n_indents+2)*indent + '{\n'
class_decl += ' '*(n_indents+3)*indent + 'init_wrapper();\n'
class_decl += ' '*(n_indents+3)*indent + 'return *wptr;\n'
class_decl += ' '*(n_indents+2)*indent + '}\n'
# - Destructor
if file_for_gambit:
class_decl += '\n'
class_decl += ' '*(n_indents+2)*indent + 'virtual ~' + abstr_class_name['short'] + '() =0;\n'
else:
class_decl += '\n'
class_decl += ' '*(n_indents+2)*indent + 'virtual ~' + abstr_class_name['short'] + '()\n'
class_decl += ' '*(n_indents+2)*indent + '{\n'
if gb.debug_mode:
class_decl += ' '*(n_indents+3)*indent + 'std::cerr << "DEBUG: " << this << " ' + abstr_class_name['short'] + ' dtor (BEGIN)" << std::endl;\n'
class_decl += ' '*(n_indents+3)*indent + 'if (wptr != 0)\n'
class_decl += ' '*(n_indents+3)*indent + '{\n'
class_decl += ' '*(n_indents+4)*indent + 'set_delete_BEptr(wptr, false);\n'
class_decl += ' '*(n_indents+4)*indent + 'if (delete_wrapper == true)\n'
class_decl += ' '*(n_indents+4)*indent + '{\n'
class_decl += ' '*(n_indents+5)*indent + 'wrapper_deleter(wptr);\n'
class_decl += ' '*(n_indents+5)*indent + 'wptr = 0;\n'
# Set wptr = 0 in all parent classes as well
for parent_dict in all_parent_classes:
if parent_dict['loaded']:
class_decl += ' '*(n_indents+5)*indent + parent_dict['abstr_class_name']['long_templ'] + '::set_wptr(0);\n'
class_decl += ' '*(n_indents+5)*indent + 'delete_wrapper = false;\n'
class_decl += ' '*(n_indents+4)*indent + '}\n'
class_decl += ' '*(n_indents+3)*indent + '}\n'
if gb.debug_mode:
class_decl += ' '*(n_indents+3)*indent + 'std::cerr << "DEBUG: " << this << " ' + abstr_class_name['short'] + ' dtor (END)" << std::endl;\n'
class_decl += ' '*(n_indents+2)*indent + '}\n'
# - Close the class body
class_decl += ' '*n_indents*indent + '};' + '\n'
# - Construct the closing of the namespaces
class_decl += utils.constrNamespace(namespaces, 'close')
# Insert tags for the GAMBIT namespace
class_decl = '\n__START_GAMBIT_NAMESPACE__\n\n' + class_decl + '\n__END_GAMBIT_NAMESPACE__\n'
# - Add forward declaration of wrapper_creator function (needed by the 'destructor pattern')
if not file_for_gambit:
frwd_decl_creator = '\n'
frwd_decl_creator += '// Forward declaration for wrapper_creator.\n'
frwd_decl_creator += gb.gambit_backend_namespace + '::' + class_name['long'] + '* wrapper_creator(' + gb.gambit_backend_namespace + '::' + abstr_class_name['long'] + '*);\n'
# frwd_decl_creator += 'void wrapper_creator(' + gb.gambit_backend_namespace + '::' + abstr_class_name['long'] + '*);\n'
frwd_decl_creator += '\n'
class_decl = frwd_decl_creator + class_decl
# - Add forward declaration of wrapper_deleter function (needed by the 'destructor pattern')
if not file_for_gambit:
frwd_decl_deleter = '\n'
frwd_decl_deleter += '// Forward declaration needed by the destructor pattern.\n'
frwd_decl_deleter += 'void wrapper_deleter(' + gb.gambit_backend_namespace + '::' + class_name['long'] + '*);\n'
frwd_decl_deleter += '\n'
class_decl = frwd_decl_deleter + class_decl
# - Add forward declaration of set_delete_BEptr function (needed by the 'destructor pattern')
if not file_for_gambit:
frwd_decl_setdel = '\n'
frwd_decl_setdel += '// Forward declaration needed by the destructor pattern.\n'
frwd_decl_setdel += 'void set_delete_BEptr(' + gb.gambit_backend_namespace + '::' + class_name['long'] + '*, bool);\n'
frwd_decl_setdel += '\n'
class_decl = frwd_decl_setdel + class_decl
# Insert include statements needed by GAMBIT
backend_undef_incl_statement = '#include "' + os.path.join(gb.gambit_backend_incl_dir, 'backend_undefs.hpp') + '"\n'
identification_incl_statement = '#include "' + 'identification.hpp' + '"\n'
class_decl = identification_incl_statement + class_decl + '\n' + backend_undef_incl_statement
return class_decl
# ====== END: constrAbstractClassDecl ========
# ====== getAcceptableConstructors ========
def getAcceptableConstructors(class_el, skip_copy_constructors=False):
# Check for copy constructor?
if skip_copy_constructors:
has_copy_constructor, copy_constr_id = checkCopyConstructor(class_el, return_id=True)
# Create list of all acceptable constructors of the class
constructor_elements = []
if 'members' in class_el.keys():
for mem_id in class_el.get('members').split():
el = gb.id_dict[mem_id]
if (el.tag == 'Constructor'): #and ('artificial' not in el.keys()): #(el.get('explicit') == "1"):
if skip_copy_constructors and (el.get('id') == copy_constr_id):
pass
else:
constructor_elements.append(el)
return constructor_elements
# ====== END: getAcceptableConstructors ========
# ====== constrFactoryFunctionCode ========
def constrFactoryFunctionCode(class_el, class_name, indent=4, template_types=[], skip_copy_constructors=False, use_wrapper_return=False, use_wrapper_args=False, add_include_statements=True, add_signatures_comment=True):
# Replace '*' and '&' in list of template types
template_types = [e.replace('*','P').replace('&','R') for e in template_types]
constructor_elements = getAcceptableConstructors(class_el, skip_copy_constructors=skip_copy_constructors)
# If no public constructors are found, return nothing
if len(constructor_elements) == 0:
reason = "No public constructors."
infomsg.NoFactoryFunctions(class_name['long_templ'], reason).printMessage()
return ''
# List to hold include statements that are generated based on the types used
# in the constructors
if add_include_statements:
include_statements = []
# Construct factory function definition(s)
func_def = ''
counter = 0
for el in constructor_elements:
if (el.tag == 'Constructor') and ((el.get('access') == 'protected') or (el.get('access') == 'private')):
continue
if add_include_statements:
# - Generate include statements based on the types used in the constructor
include_statements += utils.getIncludeStatements(el, convert_loaded_to='none', input_element='function', forward_declared='exclude')
include_statements += utils.getIncludeStatements(el, convert_loaded_to='wrapper', input_element='function', forward_declared='exclude', use_full_path=True)
# We need to generate as many overloaded versions as there are arguments with default values
n_overloads = funcutils.numberOfDefaultArgs(el)
# Identify arguments
args = funcutils.getArgs(el)
# Translate argument type of loaded classes
if use_wrapper_args:
w_args = funcutils.constrWrapperArgs(args, add_ref=True, convert_loaded_to_abstract=False)
else:
w_args = funcutils.constrWrapperArgs(args, add_ref=True, convert_loaded_to_abstract=True)
# Invent argument names if missing
argc = 1
for i in range(len(args)):
if args[i]['name'] == '':
args[i]['name'] = 'arg_' + str(argc)
argc += 1
# Generate one factory function for each set of default arguments
for remove_n_args in range(n_overloads+1):
# Check that the constructor is acceptable
if funcutils.ignoreFunction(el, limit_pointerness=True, remove_n_args=remove_n_args):
continue
# - Factory function name
factory_name = 'Factory_' + class_name['short'] + '_' + str(counter)
if len(template_types) > 0:
factory_name += '_' + '_'.join(template_types)
factory_name += gb.code_suffix + '_' + str(gb.symbol_name_counter)
gb.symbol_name_counter += 1
if remove_n_args == 0:
use_args = args
use_w_args = w_args
else:
use_args = args[:-remove_n_args]
use_w_args = w_args[:-remove_n_args]
# Construct bracket with input arguments
if use_wrapper_args:
args_bracket = funcutils.constrArgsBracket(use_w_args, include_namespace=True, use_wrapper_class=True)
args_bracket_notypes = funcutils.constrArgsBracket(use_args, include_arg_type=False, cast_to_original=True, wrapper_to_pointer=True)
else:
args_bracket = funcutils.constrArgsBracket(use_w_args, include_namespace=True)
args_bracket_notypes = funcutils.constrArgsBracket(use_args, include_arg_type=False, cast_to_original=True)
args_bracket_nonames = funcutils.constrArgsBracket(use_args, include_namespace=True, include_arg_type=True, include_arg_name=False, add_namespace_to_loaded='my_ns')
# Generate declaration line:
if use_wrapper_return:
return_type = toWrapperType(class_name['short'], include_namespace=True)
else:
return_type = toAbstractType(class_name['short'], add_pointer=True, include_namespace=True)
func_def += return_type + ' ' + factory_name + args_bracket + '\n'
# Generate body
func_def += '{' + '\n'
if use_wrapper_return:
func_def += indent*' ' + 'return ' + return_type + '( new ' + class_name['long'] + args_bracket_notypes + ' );' + '\n'
else:
func_def += indent*' ' + 'return new ' + class_name['short'] + args_bracket_notypes + ';' + '\n'
func_def += '}' + 2*'\n'
# Add info to global dict with factory function info
info_dict = OrderedDict()
info_dict['name'] = factory_name
info_dict['args_bracket'] = args_bracket_nonames
if class_name['long'] not in gb.factory_info.keys():
gb.factory_info[class_name['long']] = []
gb.factory_info[class_name['long']].append( info_dict )
# Increment counter
counter += 1
# If no functions were generated, return nothing
if func_def == '':
reason = "No accepted constructors."
infomsg.NoFactoryFunctions(class_name['long_templ'], reason).printMessage()
return ''
# Encapsulate code in the correct namespace
namespaces = utils.getNamespaces(class_el)
n_indents = len(namespaces)
func_def_in_ns = ''
func_def_in_ns += utils.constrNamespace(namespaces, 'open')
func_def_in_ns += utils.addIndentation(func_def, n_indents*cfg.indent)
func_def_in_ns += utils.constrNamespace(namespaces, 'close')
# Encapsulate code in 'extern "C" {...}'
func_def_in_ns = 'extern "C"\n{\n' + func_def_in_ns + '}\n'
return_code = func_def_in_ns
if add_include_statements:
try:
original_header_fname = utils.getOriginalHeaderPath(class_el, full_path=True)
use_path = utils.shortenHeaderPath(original_header_fname)
include_statements.append( '#include "' + use_path + '"')
except exceptions.ReturnError as e:
reason = "No original header file found."
infomsg.NoIncludeStatementGenerated(class_name['long_templ'], reason).printMessage()
pass
include_statements.append( '#include "' + gb.new_header_files[class_name['long']]['wrapper_fullpath'] + '"' )
include_statements.append( '#include "' + os.path.join(gb.gambit_backend_incl_dir, gb.abstract_typedefs_fname + cfg.header_extension) + '"' )
include_statements.append( '#include "' + os.path.join(gb.gambit_backend_incl_dir, gb.wrapper_typedefs_fname + cfg.header_extension) + '"' )
include_statements = list( OrderedDict.fromkeys(include_statements) )
include_statements = utils.orderIncludeStatements(include_statements)
include_statements_code = '\n'.join(include_statements) + 2*'\n'
return_code = include_statements_code + return_code
return return_code
# ====== END: constrFactoryFunctionCode ========
# ====== constrWrapperFunction ========
def constrWrapperFunction(method_el, indent=cfg.indent, n_indents=0, remove_n_args=0, only_declaration=False, include_full_namespace=False):
# Check if this is an operator function
is_operator = False
if method_el.tag == 'OperatorMethod':
is_operator = True
# If operator, check that we have a name for it
if (is_operator) and (method_el.get('name') not in gb.operator_names.keys()):
raise Exception('No known name for the operator: %s -- Add an entry to the following dictionary: gb.operator_names' % method_el.get('name'))
# Function name
if is_operator:
func_name = 'operator' + method_el.get('name')
else:
func_name = method_el.get('name')
# Function return type
return_type_dict = utils.findType( gb.id_dict[method_el.get('returns')] )
return_el = return_type_dict['el']
pointerness = return_type_dict['pointerness']
is_ref = return_type_dict['is_reference']
return_kw = return_type_dict['cv_qualifiers']
return_kw_str = ' '.join(return_kw) + ' '*bool(len(return_kw))
return_type = return_type_dict['name'] + '*'*pointerness + '&'*is_ref
return_is_loaded_class = utils.isLoadedClass(return_el)
# Function arguments (get list of dicts with argument info)
args = funcutils.getArgs(method_el)
# Remove arguments when creating overloaded versions (for dealing with default argument values)
if remove_n_args > 0:
args = args[:-remove_n_args]
# Check constness (in the following sense: "double someFunction() const", i.e. a function that does not modify member variables.)
if ('const' in method_el.keys()) and (method_el.get('const')=='1'):
is_const = True
else:
is_const = False
# Construct wrapper function name
w_func_name = funcutils.constrWrapperName(method_el, include_full_namespace=include_full_namespace)
# if remove_n_args > 0:
# w_func_name += '_overload_' + str(remove_n_args)
# Choose wrapper return type
if return_is_loaded_class:
if (pointerness == 0) and (is_ref):
w_return_type = toAbstractType(return_type, include_namespace=True)
elif (pointerness == 0) and (not is_ref):
w_return_type = toAbstractType(return_type, include_namespace=True, add_pointer=True, remove_reference=True)
else:
w_return_type = toAbstractType(return_type, include_namespace=True)
else:
w_return_type = return_type
# Construct list of arguments for wrapper function
w_args = funcutils.constrWrapperArgs(args, add_ref=True)
# Construct bracket with input arguments for wrapper function
if only_declaration:
w_args_bracket = funcutils.constrArgsBracket(w_args, include_arg_name=False, include_namespace=True)
else:
w_args_bracket = funcutils.constrArgsBracket(w_args, include_namespace=True)
# Construct declaration line for wrapper function
w_func_line = funcutils.constrDeclLine(w_return_type, w_func_name, w_args_bracket, keywords=return_kw, is_const=is_const)
# Construct function body for wrapper function
if only_declaration:
pass
else:
w_func_body = funcutils.constrWrapperBody(return_type, func_name, args, return_is_loaded_class, keywords=return_kw)
# Combine code and add indentation
wrapper_code = ''
if only_declaration:
wrapper_code += utils.addIndentation(w_func_line, n_indents*indent) + ';\n'
else:
wrapper_code += utils.addIndentation(w_func_line, n_indents*indent) + '\n'
wrapper_code += utils.addIndentation(w_func_body, n_indents*indent) + '\n'
# Return result
return wrapper_code
# ====== END: constrWrapperFunction ========
# ====== constrVariableRefFunction ========
def constrVariableRefFunction(var_el, virtual=False, indent=cfg.indent, n_indents=0, only_declaration=False,
include_full_namespace=False, add_return_type_suffix=False):
func_code = ''
var_name = var_el.get('name')
var_type_dict = utils.findType( var_el )
var_type_name = var_type_dict['name']
pointerness = var_type_dict['pointerness']
is_ref = var_type_dict['is_reference']
var_kw = var_type_dict['cv_qualifiers']
var_array_limits = var_type_dict['array_limits']
is_array = var_type_dict['is_array']
var_array_limits_str = ''.join([ '[%i]' % i for i in var_array_limits ])
var_kw_str = ' '.join(var_kw) + ' '*bool(len(var_kw))
var_type = var_type_dict['name'] + '*'*pointerness + '&'*is_ref
# pointerness, is_ref = utils.pointerAndRefCheck(var_el)
ref_method_name = var_name + '_ref' + gb.code_suffix
if include_full_namespace:
namespaces = utils.getNamespaces(var_el)
if len(namespaces) > 0:
ref_method_name = '::'.join(namespaces) + '::' + ref_method_name
var_is_loaded_class = utils.isLoadedClass(var_el)
if (var_is_loaded_class) and (pointerness == 0):
return_type = toAbstractType(var_type)
elif (var_is_loaded_class) and (pointerness == 1) and (add_return_type_suffix):
return_type = toWrapperType(var_type, include_namespace=include_full_namespace)
var_type_name = toWrapperType(var_type_name, include_namespace=include_full_namespace)
else:
return_type = var_type
# If variable type is a known class, add '::' for absolute namespace.
if (not var_is_loaded_class) and utils.isKnownClass(var_el):
return_type = '::' + return_type
if (not is_ref) and (not is_array):
return_type = return_type + '&'
else:
pass
func_code += ' '*n_indents*indent
if virtual:
if is_array:
func_code += 'virtual ' + var_kw_str + return_type + ' (&' + ref_method_name + '())' + var_array_limits_str + ' =0;\n'
else:
func_code += 'virtual ' + var_kw_str + return_type + ' ' + ref_method_name + '() =0;\n'
else:
if is_array:
func_code += var_kw_str + return_type + ' (&' + ref_method_name + '())' + var_array_limits_str
else:
func_code += var_kw_str + return_type + ' ' + ref_method_name + '()'
if only_declaration:
func_code += ';\n'
else:
if (var_is_loaded_class) and (pointerness > 0):
wrapper_var_name = var_name + gb.code_suffix
func_code += '\n'
func_code += ' '*n_indents*indent + '{\n'
func_code += ' '*(n_indents+1)*indent + 'if (not ' + wrapper_var_name + ') { ' + wrapper_var_name + ' = new ' + var_type_name + '(' + var_name + ', true); }\n'
func_code += ' '*(n_indents+1)*indent + 'return ' + wrapper_var_name + ';\n'
func_code += ' '*n_indents*indent + '}\n'
else:
func_code += ' { return ' + var_name +'; }\n'
return func_code
# ====== END: constrVariableRefFunction ========
# ====== constrPtrCopyFunc ========
def constrPtrCopyFunc(class_el, abstr_class_name_short, class_name_short, virtual=False, indent=cfg.indent, n_indents=0, only_declaration=False, include_full_namespace=False):
func_name = 'pointer_copy' + gb.code_suffix
class_name = class_name_short
abstr_class_name = abstr_class_name_short
if include_full_namespace:
namespaces_with_self = utils.getNamespaces(class_el, include_self=True)
namespaces = utils.getNamespaces(class_el)
if len(namespaces_with_self) > 0:
func_name = '::'.join(namespaces_with_self) + '::' + func_name
if len(namespaces) > 0:
abstr_class_name = '::'.join(namespaces) + '::' + abstr_class_name
class_name = '::'.join(namespaces) + '::' + class_name
ptr_code = ''
if virtual:
ptr_code += ' '*cfg.indent*n_indents + 'virtual '+ abstr_class_name + '*' + ' ' + func_name + '() =0;\n'
else:
ptr_code += ' '*cfg.indent*n_indents + abstr_class_name + '*' + ' ' + func_name + '()'
if only_declaration:
ptr_code += ';\n'
else:
ptr_code += '\n'
ptr_code += ' '*cfg.indent*n_indents + '{\n'
ptr_code += ' '*cfg.indent*(n_indents+1) + abstr_class_name + '* new_ptr = new ' + class_name_short + '(*this);\n'
ptr_code += ' '*cfg.indent*(n_indents+1) + 'return new_ptr;\n'
ptr_code += ' '*cfg.indent*n_indents + '}\n'
return ptr_code
# ====== END: constrPtrCopyFunc ========
# ====== constrPtrAssignFunc ========
def constrPtrAssignFunc(class_el, abstr_class_name_short, class_name_short, virtual=False, indent=cfg.indent, n_indents=0, only_declaration=False, include_full_namespace=False):
func_name = 'pointer_assign' + gb.code_suffix
class_name = class_name_short
abstr_class_name = abstr_class_name_short
if include_full_namespace:
namespaces_with_self = utils.getNamespaces(class_el, include_self=True)
namespaces = utils.getNamespaces(class_el)
if len(namespaces_with_self) > 0:
func_name = '::'.join(namespaces_with_self) + '::' + func_name
if len(namespaces) > 0:
abstr_class_name = '::'.join(namespaces) + '::' + abstr_class_name
class_name = '::'.join(namespaces) + '::' + class_name
ptr_code = ''
if virtual:
ptr_code += ' '*cfg.indent*n_indents + 'virtual void ' + func_name + '(' + abstr_class_name + '*) =0;\n'
else:
ptr_code += ' '*cfg.indent*n_indents + 'void ' + func_name + '(' + abstr_class_name + '* in)'
if only_declaration:
ptr_code += ';\n'
else:
ptr_code += '\n'
ptr_code += ' '*cfg.indent*n_indents + '{\n'
ptr_code += ' '*cfg.indent*(n_indents+1) + gb.gambit_backend_namespace + '::' + class_name + '* wptr_temp = ' + abstr_class_name + '::get_wptr();\n'
ptr_code += ' '*cfg.indent*(n_indents+1) + '*this = *dynamic_cast<' + class_name_short + '*>(in);\n'
ptr_code += ' '*cfg.indent*(n_indents+1) + abstr_class_name_short + '::set_wptr(wptr_temp);\n'
ptr_code += ' '*cfg.indent*n_indents + '}\n'
return ptr_code
# ====== END: constrPtrAssignFunc ========
# ====== checkAssignmentOperator ========
def checkAssignmentOperator(class_el):
found_assignment_operator = False
is_artificial = False
# Get list of all class members
class_members = utils.getMemberElements(class_el, include_artificial=True)
# Look for assignment operator
for mem_el in class_members:
if (mem_el.tag == 'OperatorMethod') and (mem_el.get('name') == '='):
# Check that return type is either void or the class type itself (possibly as a reference)
return_type_dict = utils.findType(mem_el)
return_type = return_type_dict['name'] + '*'*return_type_dict['pointerness'] + '&'*return_type_dict['is_reference']
return_type_id = return_type_dict['id']
if (return_type == 'void') or (return_type_id == class_el.get('id')):
# Check that the only argument is another class instance
args = funcutils.getArgs(mem_el)
if (len(args) == 1) and (args[0]['id'] == class_el.get('id')):
found_assignment_operator = True
if ('artificial' in mem_el.keys()) and (mem_el.get('artificial')=='1'):
is_artificial = True
return found_assignment_operator, is_artificial
# ====== END: checkAssignmentOperator ========
# ====== checkCopyConstructor ========
def checkCopyConstructor(class_el, return_id=False):
found_copy_constructor = False
copy_constr_id = ''
# Get list of all class members
class_members = utils.getMemberElements(class_el, include_artificial=True)
# Look for copy constructor
for mem_el in class_members:
if (mem_el.tag == 'Constructor'):
if (mem_el.get('access') == 'protected') or (mem_el.get('access') == 'private'):
return found_copy_constructor, copy_constr_id
# Check that the only argument is another class instance
args = funcutils.getArgs(mem_el)
if (len(args) == 1) and (args[0]['id'] == class_el.get('id')):
found_copy_constructor = True
copy_constr_id = mem_el.get('id')
if return_id:
return found_copy_constructor, copy_constr_id
else:
return found_copy_constructor
# ====== END: checkCopyConstructor ========
# ====== toWrapperType ========
def toWrapperType(input_type_name, remove_reference=False, remove_pointers=False, include_namespace=False, include_global_namespace=False ):
type_name = input_type_name
# Search for '*' and '&'
n_pointers = type_name.count('*')
is_ref = bool('&' in type_name)
# Remove '*' and '&'
type_name = type_name.replace('*','').replace('&','')
# Split into namespace, short_type_name
namespace, short_type_name = utils.removeNamespace(type_name, return_namespace=True)
if include_global_namespace:
namespace = '::' + namespace
# Insert wrapper class prefix
short_type_name = gb.wrapper_class_prefix + short_type_name
# Add '*' and '&'
if remove_pointers:
pass
else:
short_type_name = short_type_name + '*'*n_pointers
if remove_reference:
pass
else:
short_type_name = short_type_name + '&'*is_ref
# Return result
if (include_namespace) and (namespace != ''):
return namespace + '::' + short_type_name
else:
return short_type_name
# ====== END: toWrapperType ========
# ====== toAbstractType ========
def toAbstractType(input_type_name, include_namespace=True, add_pointer=False, remove_reference=False, remove_pointers=False):
# FIXME:
# Should this function also translate template argument types?
# Example: TypeA<TypeB> --> Abstract__TypeA<Abstract__TypeB>
type_name = input_type_name
# Remove template bracket
type_name_notempl = utils.removeTemplateBracket(type_name)
# Search for '*' and '&'
n_pointers = type_name_notempl.count('*')
is_ref = bool('&' in type_name_notempl)
# Get namespace
namespace, type_name_short = utils.removeNamespace(type_name, return_namespace=True)
if is_ref and remove_reference:
type_name_short = type_name_short.replace('&','')
if (n_pointers > 0) and remove_pointers:
type_name_short = type_name_short.replace('*','')
if namespace == '':
type_name = gb.abstr_class_prefix + type_name_short
else:
type_name = (namespace+'::')*include_namespace + gb.abstr_class_prefix + type_name_short
if add_pointer:
if is_ref and not remove_reference:
type_name = type_name.rstrip('&') + '*&'
else:
type_name = type_name + '*'
# Return result
return type_name
# ====== END: toAbstractType ========
# ====== getClassNameDict ========
def getClassNameDict(class_el, abstract=False):
class_name = {}
xml_id = class_el.get('id')
if 'name' not in class_el.keys():
raise KeyError('XML element %s does not contain the key "name".' % (xml_id))
namespaces_list = utils.getNamespaces(class_el, include_self=True)
class_name['long_templ'] = '::'.join(namespaces_list)
class_name['long'] = class_name['long_templ'].split('<',1)[0]
class_name['short_templ'] = class_el.get('name')
class_name['short'] = class_name['short_templ'].split('<',1)[0]
if abstract:
abstr_class_name = {}
abstr_class_name['long_templ'] = getAbstractClassName(class_name['long_templ'], prefix=gb.abstr_class_prefix)
abstr_class_name['long'] = abstr_class_name['long_templ'].split('<',1)[0]
abstr_class_name['short_templ'] = getAbstractClassName(class_name['long_templ'], prefix=gb.abstr_class_prefix, short=True)
abstr_class_name['short'] = abstr_class_name['short_templ'].split('<',1)[0]
return abstr_class_name
else:
return class_name
# ====== END: getClassNameDict ========
# ====== constrWrapperDecl ========
def constrWrapperDecl(class_name, abstr_class_name, loaded_parent_classes, class_variables, class_functions, class_constructors, construct_assignment_operator, has_copy_constructor, indent=' '*cfg.indent):
decl_code = ''
short_wrapper_class_name = toWrapperType(class_name['short'])
wrapper_class_name = toWrapperType(class_name['long'], include_namespace=True)
# Construct inheritance line
inheritance_line = ''
for parent_dict in loaded_parent_classes:
inheritance_line += 'virtual '*parent_dict['virtual'] + parent_dict['access'] + ' ' + parent_dict['class_name']['short'] + ', '
inheritance_line = inheritance_line.rstrip(', ')
# If no other parent classes, add WrapperBase
if inheritance_line == '':
# inheritance_line = ' : public virtual WrapperBase'
inheritance_line = ' : public WrapperBase'
else:
inheritance_line = ' : ' + inheritance_line
# Class declaration line
decl_code += '\n'
decl_code += 'class ' + class_name['short'] + inheritance_line + '\n'
# Class body
decl_code += '{\n'
#
# Variables:
#
decl_code += 2*indent + '// Member variables: \n'
# Add a static function pointer for each factory function
decl_code += indent + 'public:\n'
decl_code += 2*indent + '// -- Static factory pointers: \n'
factory_counter = 0
for i, constr_el in enumerate(class_constructors):
# We need pointers for all the overloaded factory functions (generated due to default value arguments)
n_overloads = funcutils.numberOfDefaultArgs(constr_el)
# Identify arguments, translate argument type of loaded classes
# and construct the argument bracket
args = funcutils.getArgs(constr_el)
# One factory function pointer for each set of default arguments
for remove_n_args in range(n_overloads+1):
# Check that the constructor is acceptable
if funcutils.ignoreFunction(constr_el, limit_pointerness=True, remove_n_args=remove_n_args):
continue
if remove_n_args == 0:
use_args = args
else:
use_args = args[:-remove_n_args]
args_bracket = funcutils.constrArgsBracket(use_args, include_arg_name=False, include_arg_type=True, include_namespace=True)
# Factory pointer name
factory_ptr_name = '__factory' + str(factory_counter)
# Construct factory pointer code
decl_code += 2*indent + 'static ' + abstr_class_name['short'] + '* (*' + factory_ptr_name + ')' + args_bracket + ';\n'
# Increment factory counter
factory_counter += 1
# Add references to all public variables
decl_code += '\n'
decl_code += 2*indent + '// -- Other member variables: \n'
current_access = ''
for var_el in class_variables:
# Accessor
accessor = var_el.get('access')
if accessor != current_access:
decl_code += indent + accessor + ':\n'
current_access = accessor
# Variable name
var_name = var_el.get('name')
# Determine variable type
var_type_dict = utils.findType(var_el)
pointerness = var_type_dict['pointerness']
is_ref = var_type_dict['is_reference']
var_kw = var_type_dict['cv_qualifiers']
var_array_limits = var_type_dict['array_limits']
is_array = var_type_dict['is_array']
var_array_limits_str = ''.join(['[%i]' % i for i in var_array_limits])
var_kw_str = ' '.join(var_kw) + ' '*bool(len(var_kw))
var_type = var_type_dict['name'] + '*'*pointerness + '&'*is_ref
var_is_loaded_class = utils.isLoadedClass(var_el)
var_is_known_class = utils.isKnownClass(var_el)
# # FIXME: At the moment there are problems with member variables that are pointer-to-loaded-class. For now, skip them:
# if var_is_loaded_class and pointerness > 0:
# print('WARNING: The member variable %s is of a loaded type and has pointerness > 0. This BOSS cannot yet handle. Ignored for now...' % var_name)
# continue
if var_is_loaded_class:
use_var_type = var_type
if not is_ref:
use_var_type = var_type + '&'
decl_code += 2*indent + var_kw_str + use_var_type + ' ' + var_name + var_array_limits_str + ';\n'
else:
if var_is_known_class:
var_type = '::' + var_type
if is_ref:
use_var_type = var_type
else:
if not is_array:
use_var_type = var_type + '&'
else:
use_var_type = var_type
if is_array:
decl_code += 2*indent + var_kw_str + use_var_type + ' (&' + var_name +')' + var_array_limits_str + ';\n'
else:
decl_code += 2*indent + var_kw_str + use_var_type + ' ' + var_name + ';\n'
#
# Functions:
#
decl_code += '\n'
decl_code += 2*indent + '// Member functions: \n'
# Add wrappers for all member functions, including operator functions
# and overloaded versions of functions with default value arguments
current_access = ''
for func_el in class_functions:
# Accessor
accessor = func_el.get('access')
if accessor != current_access:
decl_code += indent + accessor + ':\n'
current_access = accessor
# Check if this is an operator function
is_operator = False
if func_el.tag == 'OperatorMethod':
is_operator = True
# Check if this function makes use of any loaded types
uses_loaded_type = funcutils.usesLoadedType(func_el)
# Function name
if is_operator:
func_name = 'operator' + func_el.get('name')
else:
func_name = func_el.get('name')
# Skip the assignment operator (we implement out own later on)
if func_name == 'operator=':
continue
# Check for const function
is_const = utils.isConstFunction(func_el)
# Determine return type
return_type_dict = utils.findType(func_el)
return_type_el = return_type_dict['el']
pointerness = return_type_dict['pointerness']
is_ref = return_type_dict['is_reference']
return_type_kw = return_type_dict['cv_qualifiers']
return_kw_str = ' '.join(return_type_kw) + ' '*bool(len(return_type_kw))
return_is_loaded = utils.isLoadedClass(return_type_el)
return_type = return_type_dict['name'] + '*'*pointerness + '&'*is_ref
# If return type is a known class, add '::' for absolute namespace.
if (not return_is_loaded) and utils.isKnownClass(return_type_el):
return_type = '::' + return_type
# If return-by-value, then a const qualifier on the return value is meaningless
# (will result in a compiler warning)
if (pointerness == 0) and (is_ref == False) and ('const' in return_type_kw):
return_kw_str = return_kw_str.replace('const', '')
# Arguments
args = funcutils.getArgs(func_el)
# One function for each set of default arguments
n_overloads = funcutils.numberOfDefaultArgs(func_el)
for remove_n_args in range(n_overloads+1):
# Check that the function is acceptable
if funcutils.ignoreFunction(func_el, remove_n_args=remove_n_args):
continue
if remove_n_args == 0:
use_args = args
else:
use_args = args[:-remove_n_args]
# Argument bracket
args_bracket = funcutils.constrArgsBracket(use_args, include_arg_name=True, include_arg_type=True, include_namespace=True)
# Name of function to call (in abstract class)
if is_operator:
if uses_loaded_type:
call_func_name = 'operator_' + gb.operator_names[func_el.get('name')] + gb.code_suffix
else:
call_func_name = 'operator' + func_el.get('name')
else:
# call_func_name = func_name + gb.code_suffix
if uses_loaded_type or (remove_n_args>0):
call_func_name = func_name + gb.code_suffix
else:
call_func_name = func_name
# Write declaration line
decl_code += 2*indent + return_kw_str + return_type + ' ' + func_name + args_bracket + is_const*' const' + ';\n'
decl_code += '\n'
#
# Add all constructors here...
#
# Add wrappers for all original constructors except the copy constructor
temp_code = ''
current_access = ''
for i, constr_el in enumerate(class_constructors):
# Accessor
accessor = constr_el.get('access')
if accessor != current_access:
temp_code += indent + accessor + ':\n'
current_access = accessor
# Identify arguments
args = funcutils.getArgs(constr_el)
factory_args = funcutils.constrWrapperArgs(args, add_ref=True)
# If default arguments are use, we need overloaded constructors to connect to the overloaded
# factory function pointers
n_overloads = funcutils.numberOfDefaultArgs(constr_el)
# One constructor for each set of default arguments
for remove_n_args in range(n_overloads+1):
# Check that the constructor is acceptable
if funcutils.ignoreFunction(constr_el, limit_pointerness=True, remove_n_args=remove_n_args):
continue
if remove_n_args == 0:
use_args = args
factory_use_args = factory_args
else:
use_args = args[:-remove_n_args]
factory_use_args = factory_args[:-remove_n_args]
args_bracket = funcutils.constrArgsBracket(use_args, include_arg_name=True, include_arg_type=True, include_namespace=True, use_wrapper_class=False)
temp_code += 2*indent + class_name['short'] + args_bracket + ';\n'
if temp_code != '':
decl_code += '\n'
decl_code += 2*indent + '// Wrappers for original constructors: \n'
decl_code += temp_code + '\n'
if current_access != 'public':
decl_code += indent + 'public:\n'
# Add special constructor based on abstract pointer
decl_code += 2*indent + '// Special pointer-based constructor: \n'
decl_code += 2*indent + class_name['short'] + '(' + abstr_class_name['short'] +'* in);\n'
# decl_code += 2*indent + class_name['short'] + '(const ' + abstr_class_name['long'] +'* in);\n'
# Add copy constructor
if has_copy_constructor:
decl_code += '\n'
decl_code += 2*indent + '// Copy constructor: \n'
decl_code += 2*indent + class_name['short'] + '(const ' + class_name['short'] +'& in);\n'
#
# Add assignment operator
#
if construct_assignment_operator:
decl_code += '\n'
decl_code += 2*indent + '// Assignment operator: \n'
decl_code += 2*indent + class_name['short'] + '& ' + 'operator=(const ' + class_name['short'] +'& in);\n'
#
# Add destructor
#
decl_code += '\n'
decl_code += 2*indent + '// Destructor: \n'
# decl_code += 2*indent + 'virtual ~' + class_name['short'] + '();\n'
decl_code += 2*indent + '~' + class_name['short'] + '();\n'
#
# Add get_BEptr function
#
decl_code += '\n'
# decl_code += indent + 'private:\n'
decl_code += 2*indent + '// Returns correctly casted pointer to Abstract class: \n'
decl_code += 2*indent + abstr_class_name['short'] +'* get_BEptr() const;\n'
# Close class body
decl_code += '\n'
decl_code += '};\n'
# Add namespace
namespace, class_name_short = utils.removeNamespace(class_name['long'], return_namespace=True)
if namespace == '':
namespace_list = []
else:
namespace_list = namespace.split('::')
n_indents = len(namespace_list)
decl_code_with_ns = ''
decl_code_with_ns += utils.constrNamespace(namespace_list,'open')
decl_code_with_ns += utils.addIndentation(decl_code, cfg.indent*n_indents)
decl_code_with_ns += utils.constrNamespace(namespace_list,'close')
# Return result
return decl_code_with_ns
# ====== END: constrWrapperDecl ========
# ====== constrWrapperDef ========
def constrWrapperDef(class_name, abstr_class_name, loaded_parent_classes, class_variables, class_functions, class_constructors, construct_assignment_operator, has_copy_constructor, indent=' '*cfg.indent, do_inline=False):
def_code = ''
short_wrapper_class_name = toWrapperType(class_name['short'])
wrapper_class_name = toWrapperType(class_name['long'], include_namespace=True)
# Functions:
def_code += '\n'
def_code += '// Member functions: \n'
# Add wrappers for all member functions, including operator functions
# and overloaded versions of functions with default value arguments
for func_el in class_functions:
# Check if this is an operator function
is_operator = False
if func_el.tag == 'OperatorMethod':
is_operator = True
# Check if this function makes use of any loaded types
uses_loaded_type = funcutils.usesLoadedType(func_el)
# Function name
if is_operator:
func_name = 'operator' + func_el.get('name')
else:
func_name = func_el.get('name')
# Skip the assignment operator (we implement out own later on)
if func_name == 'operator=':
continue
# Check for const function
is_const = utils.isConstFunction(func_el)
# Determine return type
return_type_dict = utils.findType(func_el)
return_type_el = return_type_dict['el']
pointerness = return_type_dict['pointerness']
is_ref = return_type_dict['is_reference']
return_type_kw = return_type_dict['cv_qualifiers']
return_kw_str = ' '.join(return_type_kw) + ' '*bool(len(return_type_kw))
return_is_loaded = utils.isLoadedClass(return_type_el)
return_type = return_type_dict['name'] + '*'*pointerness + '&'*is_ref
# If return type is a known class, add '::' for absolute namespace.
if (not return_is_loaded) and utils.isKnownClass(return_type_el):
return_type = '::' + return_type
# If return-by-value, then a const qualifier on the return value is meaningless
# (will result in a compiler warning)
if (pointerness == 0) and (is_ref == False) and ('const' in return_type_kw):
return_kw_str = return_kw_str.replace('const', '')
# Arguments
args = funcutils.getArgs(func_el)
# One function for each set of default arguments
n_overloads = funcutils.numberOfDefaultArgs(func_el)
for remove_n_args in range(n_overloads+1):
# Check that the function is acceptable
if funcutils.ignoreFunction(func_el, limit_pointerness=True, remove_n_args=remove_n_args):
continue
if remove_n_args == 0:
use_args = args
else:
use_args = args[:-remove_n_args]
# Arguments bracket
args_bracket = funcutils.constrArgsBracket(use_args, include_arg_name=True, include_arg_type=True, include_namespace=True)
# Name of function to call (in abstract class)
if is_operator:
if uses_loaded_type:
call_func_name = 'operator_' + gb.operator_names[func_el.get('name')] + gb.code_suffix
else:
call_func_name = 'operator' + func_el.get('name')
else:
if uses_loaded_type or (remove_n_args>0):
call_func_name = func_name + gb.code_suffix
else:
call_func_name = func_name
# Write declaration line
def_code += do_inline*'inline ' + return_kw_str + return_type + ' ' + class_name['short'] + '::' + func_name + args_bracket + is_const*' const' + '\n'
# Write function body
def_code += '{\n'
if return_type == 'void':
def_code += indent
else:
def_code += indent + 'return '
args_bracket_notypes = funcutils.constrArgsBracket(use_args, include_arg_name=True, include_arg_type=False, wrapper_to_pointer=True)
if return_is_loaded:
abs_return_type_simple = toAbstractType(return_type, include_namespace=True, remove_reference=True, remove_pointers=True)
return_type_simple = return_type.replace('*','').replace('&','')
if is_const:
get_BEptr_call = 'const_cast<const ' + abstr_class_name['short'] +'*>(get_BEptr())'
else:
get_BEptr_call = 'get_BEptr()'
# Return-by-reference
if is_ref:
if 'const' in return_type_kw:
def_code += 'const_cast<' + abs_return_type_simple + '&>(' + get_BEptr_call + '->' + call_func_name + args_bracket_notypes + ').get_init_wref();\n'
else:
def_code += get_BEptr_call + '->' + call_func_name + args_bracket_notypes + '.get_init_wref();\n'
# Return-by-pointer
elif (not is_ref) and (pointerness > 0):
if 'const' in return_type_kw:
def_code += 'const_cast<' + abs_return_type_simple + '*>(' + get_BEptr_call + '->' + call_func_name + args_bracket_notypes + ')->get_init_wptr();\n'
else:
def_code += get_BEptr_call + '->' + call_func_name + args_bracket_notypes + '->get_init_wptr();\n'
# Return-by-value
else:
if 'const' in return_type_kw:
# def_code += return_type + '( const_cast<' + abs_return_type_simple + '*>(' + get_BEptr_call + '->' + call_func_name + args_bracket_notypes + ')->get_init_wref() );\n'
def_code += return_type + '( const_cast<' + abs_return_type_simple + '*>(' + get_BEptr_call + '->' + call_func_name + args_bracket_notypes + ') );\n'
else:
# def_code += return_type + '( ' + get_BEptr_call + '->' + call_func_name + args_bracket_notypes + '->get_init_wref() );\n'
def_code += return_type + '( ' + get_BEptr_call + '->' + call_func_name + args_bracket_notypes + ' );\n'
else:
def_code += 'get_BEptr()->' + call_func_name + args_bracket_notypes + ';\n'
def_code += '}\n'
def_code += '\n'
#
# Add all constructors here...
#
# First generate some code common to all constructors
common_init_list_code = ''
common_constructor_body = ''
if gb.debug_mode:
common_constructor_body += indent + 'std::cerr << "DEBUG: " << this << " ' + short_wrapper_class_name + ' ctor" << std::endl;\n'
common_constructor_body += indent + 'get_BEptr()->set_wptr(this);\n'
common_constructor_body += indent + 'get_BEptr()->set_delete_wrapper(false);\n'
# mem_var_init_body = ''
has_loaded_class_mem_var = False
for var_el in class_variables:
# Get info
var_name = var_el.get('name')
var_type_dict = utils.findType(var_el)
var_type_name = var_type_dict['name']
var_type_el = var_type_dict['el']
pointerness = var_type_dict['pointerness']
is_ref = var_type_dict['is_reference']
var_type = var_type_dict['name'] + '*'*pointerness + '&'*is_ref
var_is_loaded_class = utils.isLoadedClass(var_type_el)
# wrapper_type_name = toWrapperType(var_type, remove_reference=True, remove_pointers=True, include_namespace=True)
var_abstr_class_name = getClassNameDict(var_type_el, abstract=True)
# var_wrapper_base_class_name = 'WrapperBase<' + var_abstr_class_name['long'] + '>'
# # FIXME: At the moment there are problems with member variables that are pointer-to-loaded-class. For now, skip them:
# if var_is_loaded_class and pointerness > 0:
# print('WARNING: The member variable %s is of a loaded type and has pointerness > 0. This BOSS cannot yet handle. Ignored for now...' % var_name)
# continue
# Construct common initialization list
if var_is_loaded_class:
if pointerness == 0:
common_init_list_code += indent + var_name + '( get_BEptr()->' + var_name + '_ref' + gb.code_suffix + '().get_init_wref()),\n'
elif pointerness == 1:
common_init_list_code += indent + var_name + '( get_BEptr()->' + var_name + '_ref' + gb.code_suffix + '()->get_init_wptr()),\n'
# common_init_list_code += indent + var_name + '(wrapperbase::BEptr->' + var_name + '_ref' + gb.code_suffix + '()),\n'
else:
raise Exception('The BOSS wrapper class system cannot presently handle member variables that have a pointerness > 1')
else:
common_init_list_code += indent + var_name + '( get_BEptr()->' + var_name + '_ref' + gb.code_suffix + '()),\n'
# Clean up initialization list
if common_init_list_code != '':
common_init_list_code = common_init_list_code.rstrip(',\n') + '\n'
# Add wrappers for all original constructors except the copy constructor
temp_code = ''
factory_counter = 0
for i, constr_el in enumerate(class_constructors):
# Identify arguments
args = funcutils.getArgs(constr_el)
factory_args = funcutils.constrWrapperArgs(args, add_ref=True)
# If default arguments are used, we need overloaded constructors to connect to the overloaded
# factory function pointers
n_overloads = funcutils.numberOfDefaultArgs(constr_el)
# One constructor for each set of default arguments
for remove_n_args in range(n_overloads+1):
# Check that the constructor is acceptable
if funcutils.ignoreFunction(constr_el, limit_pointerness=True, remove_n_args=remove_n_args):
continue
if remove_n_args == 0:
use_args = args
factory_use_args = factory_args
else:
use_args = args[:-remove_n_args]
factory_use_args = factory_args[:-remove_n_args]
args_bracket = funcutils.constrArgsBracket(use_args, include_arg_name=True, include_arg_type=True, include_namespace=True, use_wrapper_class=False)
args_bracket_notypes = funcutils.constrArgsBracket(use_args, include_arg_name=True, include_arg_type=False, wrapper_to_pointer=False)
factory_args_bracket = funcutils.constrArgsBracket(factory_use_args, include_arg_name=False, include_arg_type=True, include_namespace=True)
# Factory pointer name
factory_ptr_name = '__factory' + str(factory_counter)
temp_code += 'inline ' + class_name['short'] + '::' + class_name['short'] + args_bracket + ' :\n'
parent_class_init_list = ''
# parent_class_init_list += indent + 'WrapperBase(' + factory_ptr_name + args_bracket_notypes + '),\n'
for parent_dict in loaded_parent_classes:
parent_class_init_list += indent + parent_dict['class_name']['short'] + '(' + factory_ptr_name + args_bracket_notypes + '),\n'
if parent_class_init_list == '':
parent_class_init_list += indent + 'WrapperBase(' + factory_ptr_name + args_bracket_notypes + '),\n'
if common_init_list_code != '':
temp_code += parent_class_init_list + common_init_list_code
else:
temp_code += parent_class_init_list.rstrip(',\n') + '\n'
temp_code += '{\n'
temp_code += common_constructor_body
temp_code += '}\n'
temp_code += '\n'
# Increment factory counter
factory_counter += 1
if temp_code != '':
def_code += '\n'
def_code += '// Wrappers for original constructors: \n'
def_code += temp_code
# Add special constructor based on abstract class pointer.
def_code += '// Special pointer-based constructor: \n'
def_code += do_inline*'inline ' + class_name['short'] + '::' + class_name['short'] + '(' + abstr_class_name['short'] +'* in) :\n'
parent_class_init_list = ''
# parent_class_init_list += indent + 'WrapperBase(in),\n'
for parent_dict in loaded_parent_classes:
parent_class_init_list += indent + parent_dict['class_name']['short'] + '(in),\n'
if parent_class_init_list == '':
parent_class_init_list += indent + 'WrapperBase(in),\n'
if common_init_list_code != '':
def_code += parent_class_init_list + common_init_list_code
else:
def_code += parent_class_init_list.rstrip(',\n') + '\n'
def_code += '{\n'
def_code += common_constructor_body
def_code += '}\n'
# # Const version of constructor from abstract class pointer
# def_code += do_inline*'inline ' + class_name['long'] + '::' + class_name['short'] + '(const ' + abstr_class_name['long'] +'* in) :\n'
# parent_class_init_list = ''
# for parent_dict in loaded_parent_classes:
# parent_class_init_list += indent + parent_dict['class_name']['short'] + '(in),\n'
# if parent_class_init_list == '':
# parent_class_init_list += indent + 'WrapperBase(in),\n'
# if common_init_list_code != '':
# def_code += parent_class_init_list + common_init_list_code
# else:
# def_code += parent_class_init_list.rstrip(',\n') + '\n'
# def_code += '{\n'
# def_code += common_constructor_body
# def_code += '}\n'
# Add copy constructor
if has_copy_constructor:
def_code += '\n'
def_code += '// Copy constructor: \n'
def_code += do_inline*'inline ' + class_name['short'] + '::' + class_name['short'] + '(const ' + class_name['short'] +'& in) :\n'
parent_class_init_list = ''
# parent_class_init_list += indent + 'WrapperBase(in.get_BEptr()->pointer_copy' + gb.code_suffix + '()),\n'
for parent_dict in loaded_parent_classes:
parent_class_init_list += indent + parent_dict['class_name']['short'] + '(in.get_BEptr()->pointer_copy' + gb.code_suffix + '()),\n'
if parent_class_init_list == '':
parent_class_init_list += indent + 'WrapperBase(in.get_BEptr()->pointer_copy' + gb.code_suffix + '()),\n'
if common_init_list_code != '':
def_code += parent_class_init_list + common_init_list_code
else:
def_code += parent_class_init_list.rstrip(',\n') + '\n'
def_code += '{\n'
def_code += common_constructor_body
def_code += '}\n'
#
# Add assignment operator
#
if construct_assignment_operator:
def_code += '\n'
def_code += '// Assignment operator: \n'
def_code += do_inline*'inline ' + class_name['short'] + '& ' + class_name['short'] + '::operator=(const ' + class_name['short'] +'& in)\n'
def_code += '{\n'
def_code += indent + 'if (this != &in)\n'
def_code += indent + '{\n'
def_code += 2*indent + 'get_BEptr()->pointer_assign' + gb.code_suffix + '(in.get_BEptr());\n'
def_code += indent + '}\n'
def_code += indent + 'return *this;\n'
def_code += '}\n\n'
#
# Add destructor
#
def_code += '\n'
def_code += '// Destructor: \n'
def_code += do_inline*'inline ' + class_name['short'] + '::~' + class_name['short'] + '()\n'
def_code += '{\n'
if gb.debug_mode:
def_code += indent + 'std::cerr << "DEBUG: " << this << " ' + short_wrapper_class_name + ' dtor (BEGIN)" << std::endl;\n'
def_code += indent + 'if (get_BEptr() != 0)\n'
def_code += indent + '{\n'
def_code += 2*indent + 'get_BEptr()->set_delete_wrapper(false);\n'
def_code += 2*indent + 'if (can_delete_BEptr())\n'
def_code += 2*indent + '{\n'
def_code += 3*indent + 'delete BEptr;\n'
def_code += 3*indent + 'BEptr = 0;\n'
def_code += 2*indent + '}\n'
def_code += indent + '}\n'
def_code += indent + 'set_delete_BEptr(false);\n'
if gb.debug_mode:
def_code += indent + 'std::cerr << "DEBUG: " << this << " ' + short_wrapper_class_name + ' dtor (END)" << std::endl;\n'
def_code += '}\n'
#
# Add get_BEptr function
#
def_code += '\n'
def_code += '// Returns correctly casted pointer to Abstract class: \n'
def_code += do_inline*'inline ' + abstr_class_name['short'] +'* ' + class_name['long'] + '::get_BEptr() const\n'
def_code += '{\n'
def_code += indent + 'return dynamic_cast<' + abstr_class_name['short'] + '*>(BEptr);\n'
def_code += '}\n'
# Add namespace
namespace, class_name_short = utils.removeNamespace(class_name['long'], return_namespace=True)
if namespace == '':
namespace_list = []
else:
namespace_list = namespace.split('::')
n_indents = len(namespace_list)
def_code_with_ns = ''
def_code_with_ns += utils.constrNamespace(namespace_list,'open')
def_code_with_ns += utils.addIndentation(def_code, cfg.indent*n_indents)
def_code_with_ns += utils.constrNamespace(namespace_list,'close')
# Return
return def_code_with_ns
# ====== END: constrWrapperDef ========
# ====== pureVirtualMembers ========
def pureVirtualMembers(class_el):
# Return a list with the names of all pure virtual member functions of a class.
check_member_elements = utils.getMemberElements(class_el)
pure_virtual_members = []
for mem_el in check_member_elements:
if mem_el.tag in ['Constructor', 'Destructor', 'Method', 'OperatorMethod']:
if ('pure_virtual' in mem_el.keys()) and (mem_el.get('pure_virtual')=='1'):
pure_virtual_members.append(mem_el.get('name'))
return pure_virtual_members
# ====== END: pureVirtualMembers ========
# ====== generateWrapperHeaderCode ========
# Generate a header file with a GAMBIT wrapper class.
def generateWrapperHeaderCode(class_el, class_name, abstr_class_name, namespaces,
short_abstr_class_fname,
construct_assignment_operator, has_copy_constructor,
copy_constructor_id=''):
# Useful variables
indent = ' '*cfg.indent
# Useful lists
class_variables = []
class_functions = utils.getMemberFunctions(class_el, include_artificial=False, include_inherited=cfg.wrap_inherited_members,
only_accepted=True, limit_pointerness=True, include_operators=True)
class_constructors = []
class_members = utils.getMemberElements(class_el, include_artificial=False)
class_members_full = utils.getMemberElements(class_el, include_artificial=True)
for mem_el in class_members:
if (mem_el.tag in ('Field', 'Variable')) and (mem_el.get('access') == 'public'):
if isAcceptedMemberVariable(mem_el):
class_variables.append(mem_el)
else:
pass
for mem_el in class_members_full:
# Skip the copy constructor
if has_copy_constructor and (mem_el.get('id') == copy_constructor_id):
continue
# Store constructor if acceptable
if (mem_el.tag == 'Constructor') and (mem_el.get('access') == 'public'):
class_constructors.append(mem_el)
# Create a list of dicts with info on the (loaded) parent classes
loaded_parent_classes = utils.getParentClasses(class_el, only_loaded_classes=True)
#
# Start code generation
#
decl_code = constrWrapperDecl(class_name, abstr_class_name, loaded_parent_classes, class_variables, class_functions, class_constructors, construct_assignment_operator, has_copy_constructor, indent=indent)
def_code = constrWrapperDef(class_name, abstr_class_name, loaded_parent_classes, class_variables, class_functions, class_constructors, construct_assignment_operator, has_copy_constructor, indent=indent, do_inline=True)
# Insert tags for the GAMBIT namespace
decl_code = '\n__START_GAMBIT_NAMESPACE__\n' + decl_code + '\n__END_GAMBIT_NAMESPACE__\n'
def_code = '\n__START_GAMBIT_NAMESPACE__\n' + def_code + '\n__END_GAMBIT_NAMESPACE__\n'
# Insert include statements needed by GAMBIT
backend_undef_incl_statement = '#include "' + os.path.join(gb.gambit_backend_incl_dir, 'backend_undefs.hpp') + '"\n'
identification_incl_statement = '#include "' + 'identification.hpp' + '"\n'
decl_code = identification_incl_statement + decl_code + '\n' + backend_undef_incl_statement
def_code = identification_incl_statement + def_code + '\n' + backend_undef_incl_statement
#
# Add #include statements for the declaration code
#
decl_code_include_statements = []
# - Header where NULL is defined
decl_code_include_statements.append( '#include <cstddef>' )
# - If debug_mode, include <iostream> for some output
if gb.debug_mode:
decl_code_include_statements.append( '#include <iostream>' )
# - Header with forward declarations to all wrapper classes
decl_code_include_statements.append( '#include "' + gb.frwd_decls_wrp_fname + cfg.header_extension + '"')
# - Base class for all wrapper classes
decl_code_include_statements.append( '#include "' + os.path.join(gb.gambit_backend_incl_dir, 'wrapperbase.hpp') + '"')
# - Abstract class for the original class
decl_code_include_statements.append( '#include "' + gb.new_header_files[class_name['long']]['abstract'] + '"' )
# - Wrapper parent classes
for parent_dict in loaded_parent_classes:
decl_code_include_statements.append('#include "' + gb.new_header_files[ parent_dict['class_name']['long'] ]['wrapper_decl'] + '"')
# - Any other types (excluding the current wrapper class)
decl_code_include_statements += utils.getIncludeStatements(class_el, convert_loaded_to='wrapper_decl', exclude_types=[class_name], use_full_path=False, forward_declared='exclude')
# Remove duplicates and construct code
decl_code_include_statements = list( OrderedDict.fromkeys(decl_code_include_statements) )
decl_code_include_statements = utils.orderIncludeStatements(decl_code_include_statements)
decl_include_statements_code = '\n'.join(decl_code_include_statements) + 2*'\n'
decl_code = decl_include_statements_code + decl_code
#
# Add #include statements for the definition code
#
def_code_include_statements = []
# - Any other types (excluding the current wrapper class)
def_code_include_statements += utils.getIncludeStatements(class_el, convert_loaded_to='wrapper_decl', exclude_types=[class_name], use_full_path=False, forward_declared='include')
# Remove duplicates and construct code
def_code_include_statements = list( OrderedDict.fromkeys(def_code_include_statements) )
def_code_include_statements = utils.orderIncludeStatements(def_code_include_statements)
def_include_statements_code = '\n'.join(def_code_include_statements) + 2*'\n'
def_code = def_include_statements_code + def_code
# Return code
return decl_code, def_code
# ====== END: generateWrapperHeaderCode ========
# ====== findClassNamePosition ========
# Find the position of a class name
def findClassNamePosition(class_el, file_content_nocomments):
class_name = getClassNameDict(class_el)
# Find the index of the \n after the first line of the class declaration
line_number = int(class_el.get('line'))
newline_pos = utils.findNewLinePos(file_content_nocomments, line_number)
# Find position of class name
search_limit = newline_pos
while search_limit > -1:
class_name_pos = file_content_nocomments[:search_limit].rfind(class_name['short'])
pre_char = file_content_nocomments[class_name_pos-1]
post_char = file_content_nocomments[class_name_pos+len(class_name['short'])]
if (pre_char in [' ','\n','\t']) and (post_char in [' ', ':', '\n', '<', '{']):
break
else:
search_limit = class_name_pos
return class_name_pos
# ====== END: findClassNamePosition ========
# ====== isAcceptedMemberVariable ========
def isAcceptedMemberVariable(mem_el):
is_accepted = True
if not utils.isAcceptedType(mem_el):
reason = "Non-accepted type."
infomsg.IgnoredMemberVariable(mem_el.get('name'), reason).printMessage()
is_accepted = False
return is_accepted
# Should this member be ditched?
if 'name' in mem_el.keys():
namespaces_list = utils.getNamespaces(mem_el, include_self=True)
full_name = '::'.join(namespaces_list)
if full_name in cfg.ditch:
is_accepted = False
return is_accepted
# BOSS cannot yet handle member variables that are pointer-to-loaded-class.
type_dict = utils.findType(mem_el)
type_name = type_dict['name']
pointerness = type_dict['pointerness']
if utils.isLoadedClass(mem_el) and pointerness > 0:
reason = "BOSS cannot yet handle member variables of type pointer-to-loaded-class."
infomsg.IgnoredMemberVariable(mem_el.get('name'), reason).printMessage()
is_accepted = False
return is_accepted
return is_accepted
# ====== END: isAcceptedMemberVariable ========
Updated on 2022-08-03 at 12:58:00 +0000