def generateFactoryFunctions(class_el, class_name, is_template): # If class contains pure virtual members, do not generate any factory functions if class_name['long_templ'] in gb.contains_pure_virtual_members: reason = "Contains pure virtual member functions." infomsg.NoFactoryFunctions(class_name['long_templ'], reason).printMessage() return # Generate factory file content factory_file_content = '' if is_template: spec_template_types = utils.getSpecTemplateTypes(class_el) factory_file_content += classutils.constrFactoryFunctionCode( class_el, class_name, indent=cfg.indent, template_types=spec_template_types, skip_copy_constructors=True, use_wrapper_return=False, use_wrapper_args=True) else: factory_file_content += classutils.constrFactoryFunctionCode( class_el, class_name, indent=cfg.indent, skip_copy_constructors=True, use_wrapper_return=False, use_wrapper_args=True) factory_file_content += '\n' # If no file content has been generated (no public constructors), return without doing anything if factory_file_content.strip() == '': return # Generate factory file name dir_name = gb.boss_output_dir factory_file_name = os.path.join( dir_name, gb.factory_file_prefix + class_name['short'] + cfg.source_extension) # Register code if factory_file_name not in gb.new_code.keys(): gb.new_code[factory_file_name] = { 'code_tuples': [], 'add_include_guard': False } gb.new_code[factory_file_name]['code_tuples'].append( (-1, factory_file_content)) # Register that this class has a factory file gb.class_factory_file_dict[class_name['long_templ']] = factory_file_name
def run(): # Clear the module-level dict that keeps track of include statements includes.clear() # # Loop over all classes # for class_name_long, class_el in gb.loaded_classes_in_xml.items(): # Clear all info messages infomsg.clearInfoMessages() # Generate dicts with different variations of the class name class_name = classutils.getClassNameDict(class_el) abstr_class_name = classutils.getClassNameDict(class_el, abstract=True) # Print current class print print ' ' + utils.modifyText( 'Class:', 'underline') + ' ' + class_name['long_templ'] # Check if this is a template class is_template = utils.isTemplateClass(class_el) # Make list of all types used in this class all_types_in_class = utils.getAllTypesInClass(class_el, include_parents=True) # Set a bunch of generally useful variables original_class_file_el = gb.id_dict[class_el.get('file')] original_file_name = original_class_file_el.get('name') original_file_name_base = os.path.basename(original_file_name) original_class_file_dir = os.path.split(original_file_name)[0] extras_src_file_name = os.path.join( gb.boss_output_dir, gb.general_src_file_prefix + class_name['short'] + cfg.source_extension) short_abstr_class_fname = gb.new_header_files[ class_name['long']]['abstract'] abstr_class_fname = os.path.join(gb.boss_output_dir, short_abstr_class_fname) # namespaces = class_name['long'].split('::')[:-1] namespaces = utils.getNamespaces(class_el, include_self=False) has_namespace = bool(len(namespaces)) has_copy_constructor, copy_constructor_id = classutils.checkCopyConstructor( class_el, return_id=True) has_assignment_operator, assignment_is_artificial = classutils.checkAssignmentOperator( class_el) if has_assignment_operator and assignment_is_artificial: construct_assignment_operator = True else: construct_assignment_operator = False # Register paths of original files in global dict gb.original_file_paths[original_file_name_base] = original_file_name # Read content of original class file f = open(original_file_name, 'r') original_file_content = f.read() f.close() original_file_content_nocomments = utils.removeComments( original_file_content, insert_blanks=True) # Prepare entries in gb.new_code and includes if abstr_class_fname not in gb.new_code.keys(): gb.new_code[abstr_class_fname] = { 'code_tuples': [], 'add_include_guard': True } gb.new_code[abstr_class_fname + '.FOR_GAMBIT'] = { 'code_tuples': [], 'add_include_guard': True } if original_file_name not in gb.new_code.keys(): gb.new_code[original_file_name] = { 'code_tuples': [], 'add_include_guard': False } if original_file_name not in includes.keys(): includes[original_file_name] = [] if extras_src_file_name not in gb.new_code.keys(): gb.new_code[extras_src_file_name] = { 'code_tuples': [], 'add_include_guard': False } # Treat the first specialization of a template class differently if is_template and class_name['long'] not in template_done: template_bracket, template_types = utils.getTemplateBracket( class_el) empty_templ_class_decl = '' empty_templ_class_decl += classutils.constrEmptyTemplClassDecl( abstr_class_name['short'], namespaces, template_bracket, indent=cfg.indent) empty_templ_class_decl += classutils.constrTemplForwDecl( class_name['short'], namespaces, template_bracket, indent=cfg.indent) gb.new_code[abstr_class_fname]['code_tuples'].append( (0, empty_templ_class_decl)) # Get template arguments for specialization, # and check that they are acceptable if is_template and class_name['long'] not in templ_spec_done: spec_template_types = utils.getSpecTemplateTypes(class_el) for template_type in spec_template_types: if (template_type not in gb.accepted_types): raise Exception("The template specialization type '" + template_type + "' for class " + class_name['long'] + " is not among accepted types.") # # For the backend: Construct code for the abstract class header file and register it # constrAbstractClassHeaderCode(class_el, class_name, abstr_class_name, namespaces, is_template, has_copy_constructor, construct_assignment_operator, abstr_class_fname, file_for_gambit=False) # # For GAMBIT: Construct code for the abstract class header file and register it # constrAbstractClassHeaderCode(class_el, class_name, abstr_class_name, namespaces, is_template, has_copy_constructor, construct_assignment_operator, abstr_class_fname, file_for_gambit=True) # # Add abstract class to inheritance list of original class # addAbsClassToInheritanceList(class_el, class_name, abstr_class_name, is_template, original_file_name, original_file_content_nocomments) # # Generate code for #include statements in orginal header/source file # addIncludesToOriginalClassFile(class_el, namespaces, is_template, original_file_name, original_file_content_nocomments, original_file_content, short_abstr_class_fname) # # Generate additional member functions in the original class: # - Abstract class versions of member functions that make use of loaded types. # - Extra versions of functions that use default value arguments. # - Functions for returning references to public member variables. # Declarations go in the original class header while implementations go in a separate source file. # generateClassMemberInterface(class_el, class_name, abstr_class_name, namespaces, original_file_name, original_file_content_nocomments, original_class_file_el, extras_src_file_name) # # Generate factory functions source file # generateFactoryFunctions(class_el, class_name, is_template) # # Generate a header containing the GAMBIT wrapper class # generateWrapperHeader(class_el, class_name, abstr_class_name, namespaces, short_abstr_class_fname, construct_assignment_operator, has_copy_constructor, copy_constructor_id) # # Construct utility functions for dealing with pointer-to-wrapper from Abstract class. # ('wrapper_creator', 'wrapper_deleter', 'set_delete_BEptr') # constrWrapperUtils(class_name) # # Add typedef to 'abstracttypedefs.hpp' # addAbstractTypedefs(abstr_class_name, namespaces) # # Add typedef to 'wrappertypdefs.hpp' # addWrapperTypedefs(class_name, namespaces) # # Add include guards to the original headers # gb.new_code[original_file_name]['add_include_guard'] = True gb.new_code[original_file_name]['include_guard_prefix'] = 'boss' # # Keep track of classes done # gb.classes_done.append(class_name) if is_template: if class_name['long'] not in template_done: template_done.append(class_name['long']) if class_name['long'] not in templ_spec_done: templ_spec_done.append(class_name['long']) print
def run(): # # Loop over all functions # for func_name_full, func_el in gb.func_dict.items(): # Clear all info messages infomsg.clearInfoMessages() # Number of functions done func_i = len(gb.functions_done) # Generate dict with different variations of the function name func_name = funcutils.getFunctionNameDict(func_el) # Print current function print print ' ' + utils.modifyText( 'Function:', 'underline') + ' ' + func_name['long_templ_args'] # Check if this function is accepted if funcutils.ignoreFunction(func_el): continue # Function namespace namespaces = utils.getNamespaces(func_el) has_namespace = bool(len(namespaces)) # Check if this is a template function is_template = utils.isTemplateFunction(func_el) # If template function, figure out template variables if is_template == True: template_bracket, template_types = utils.getTemplateBracket( func_el) spec_template_types = utils.getSpecTemplateTypes(func_el) print 'TEMPLATE: ', template_bracket, template_types, spec_template_types # # Generate extra source file with overloaded and wrapper class versions # # Construct a wrapper function name, eg "someFunction__BOSS_7" wr_func_name = func_el.get('name') + gb.code_suffix + '_' + str( gb.symbol_name_counter) gb.symbol_name_counter += 1 # New source file name new_source_file_name = gb.function_files_prefix + func_el.get( 'name') + cfg.source_extension new_source_file_path = os.path.join(gb.boss_output_dir, new_source_file_name) # Get include statements include_statements = [] # - Generate include statements based on the types used in the function include_statements += utils.getIncludeStatements( func_el, convert_loaded_to='none', input_element='function') include_statements += utils.getIncludeStatements( func_el, convert_loaded_to='wrapper', input_element='function', use_full_path=True) 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) + '"') # - Then check if we have a header file for the function in question. # If not, declare the original function as 'extern' file_el = gb.id_dict[func_el.get('file')] has_function_header = utils.isHeader(file_el) if has_function_header: header_full_path = file_el.get('name') use_path = utils.shortenHeaderPath(header_full_path) include_statements.append('#include "' + use_path + '"') # Add include statement for gambit/Backends/function_return_utils.hpp include_statements.append('#include "' + os.path.join( gb.gambit_backend_incl_dir, 'function_return_utils.hpp') + '"') include_statements = list(OrderedDict.fromkeys(include_statements)) include_statements_code = '\n'.join(include_statements) + 2 * '\n' # If no header file is found for the original function, generate 'extern' declaration extern_declaration = '' if not has_function_header: extern_declaration += funcutils.constrExternFuncDecl(func_el) extern_declaration += '\n' # If we have access to the function header, we can implement one overloaded versions # to account for default value arguments. if has_function_header: n_overloads = funcutils.numberOfDefaultArgs(func_el) else: n_overloads = 0 # # Generate code for wrapper class version # # # Register the wrapper name # func_name['wr_name'] = wr_func_name # Construct wrapper function code wrapper_code = generateFunctionWrapperClassVersion( func_el, wr_func_name, namespaces, n_overloads) wrapper_code = utils.addIndentation(wrapper_code, len(namespaces) * cfg.indent) wrapper_code += '\n' # Prepare element in gb.new_code if new_source_file_path not in gb.new_code.keys(): gb.new_code[new_source_file_path] = { 'code_tuples': [], 'add_include_guard': False } # Define code string n_indents = len(namespaces) new_code = 2 * '\n' # - Add include statements new_code += include_statements_code # - Add extern function declaration new_code += extern_declaration # - Construct the beginning of the namespaces new_code += utils.constrNamespace(namespaces, 'open') # - Add code for 'wrapper' version new_code += wrapper_code # - Construct the closing of the namespaces new_code += utils.constrNamespace(namespaces, 'close') new_code += '\n' # Register new code in return_code_dict insert_pos = -1 # end of file # return_code_dict[new_source_file_path]['code_tuples'].append( (insert_pos, new_code) ) gb.new_code[new_source_file_path]['code_tuples'].append( (insert_pos, new_code)) # Register that this function has a source file gb.function_file_dict[ func_name['long_templ_args']] = new_source_file_path # # Keep track of functions done # gb.functions_done.append(func_name) gb.wr_func_names.append(wr_func_name) print