def getArgs(func_el): # # Returns a list with one dict per argument. # Each dict contains the following keywords: # # 'name', 'type', 'kw', 'id', 'native', 'fundamental', 'enumeration', 'loaded_class', # 'known_class', 'type_namespaces', 'default', 'function_pointer' # args = [] argc = 1 for sub_el in func_el.getchildren(): if sub_el.tag == 'Argument': arg_dict = OrderedDict() if 'name' in sub_el.keys(): arg_dict['name'] = sub_el.get('name') else: arg_dict['name'] = 'arg_' + str(argc) argc += 1 arg_type_dict = utils.findType(sub_el) pointerness = arg_type_dict['pointerness'] is_ref = arg_type_dict['is_reference'] arg_kw = arg_type_dict['cv_qualifiers'] arg_id = arg_type_dict['id'] arg_type_el = arg_type_dict['el'] is_func_ptr = arg_type_dict['is_function_pointer'] arg_type = arg_type_dict['name'] + '*'*pointerness + '&'*is_ref arg_dict['type'] = arg_type arg_dict['kw'] = arg_kw arg_dict['id'] = arg_id arg_dict['function_pointer'] = is_func_ptr arg_dict['native'] = utils.isNative(arg_type_el) arg_dict['fundamental'] = utils.isFundamental(arg_type_el) arg_dict['enumeration'] = utils.isEnumeration(arg_type_el) arg_dict['loaded_class'] = utils.isLoadedClass(arg_type_el) arg_dict['known_class'] = utils.isKnownClass(arg_type_el) arg_dict['type_namespaces'] = utils.getNamespaces(arg_type_el) if 'default' in sub_el.keys(): arg_dict['default'] = True else: arg_dict['default'] = False args.append(arg_dict) return args
def getFunctionNameDict(func_el): func_name = OrderedDict() # Check that the 'name' XML entry exists. xml_id = func_el.get('id') if 'name' not in func_el.keys(): raise KeyError('XML element %s does not contain the key "name".' % (xml_id)) # Get information about the return type. return_type_dict = utils.findType(func_el) 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 # Get information about the arguments args = getArgs(func_el) # # Start filling the name dict # func_name['short_templ'] = func_el.get('name') namespaces_list = utils.getNamespaces(func_el, include_self=True) func_name['long_templ'] = '::'.join(namespaces_list) func_name['short'], template_bracket = utils.removeTemplateBracket( func_name['short_templ'], return_bracket=True) func_name['long'], template_bracket = utils.removeTemplateBracket( func_name['long_templ'], return_bracket=True) # Construct argument bracket args_bracket = constrArgsBracket(args, include_arg_name=False, include_arg_type=True, include_namespace=True) func_name['long_templ_args'] = func_name['long_templ'] + args_bracket # Add return type func_name['long_templ_return_args'] = return_type + ' ' + func_name[ 'long_templ_args'] return func_name
def constrExternFuncDecl(func_el): extern_decl = '' return_type_dict = utils.findType( gb.id_dict[func_el.get('returns')] ) return_type = return_type_dict['name'] + '*'*return_type_dict['pointerness'] + '&'*return_type_dict['is_reference'] func_name = getFunctionNameDict(func_el) namespaces = utils.getNamespaces(func_el) n_indents = len(namespaces) extern_decl += utils.constrNamespace(namespaces, 'open') extern_decl += ' '*cfg.indent*n_indents + 'extern ' + return_type + ' ' + func_name['short_templ_args'] + ';\n' extern_decl += utils.constrNamespace(namespaces, 'close') return extern_decl
def constrWrapperName(func_el, include_full_namespace=True): # Check if this is an operator function is_operator = False if func_el.tag == 'OperatorMethod': is_operator = True func_name_short = func_el.get('name') if is_operator: w_func_name = 'operator_' + gb.operator_names[func_name_short] + gb.code_suffix else: w_func_name = func_name_short + gb.code_suffix if include_full_namespace: namespaces = utils.getNamespaces(func_el) if len(namespaces) > 0: w_func_name = '::'.join(namespaces) + '::' + w_func_name return w_func_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