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 usesLoadedType(func_el): uses_loaded_type = False return_type_dict = utils.findType(func_el) return_is_loaded = utils.isLoadedClass( return_type_dict['el'] ) args = getArgs(func_el) is_arg_loaded = [arg_dict['loaded_class'] for arg_dict in args] if (return_is_loaded) or (True in is_arg_loaded): uses_loaded_type = True return uses_loaded_type
def usesNativeType(func_el): uses_native_type = False return_type_dict = utils.findType(func_el) return_is_native = utils.isNative( return_type_dict['el'] ) args = getArgs(func_el) is_arg_native = [arg_dict['native'] for arg_dict in args] if (return_is_native) or (True in is_arg_native): uses_native_type = True return uses_native_type
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 generateFunctionWrapperClassVersion(func_el, wr_func_name, namespaces, n_overloads): new_code = '' # Check if this function makes use of any loaded types uses_loaded_type = funcutils.usesLoadedType(func_el) # Function name func_name = func_el.get('name') # Determine 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_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_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_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): if 'const' in return_type_kw: return_type_kw.remove('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] # Argument bracket args_bracket = funcutils.constrArgsBracket(use_args, include_arg_name=True, include_arg_type=True, include_namespace=True, use_wrapper_class=True) # Name of original function to call call_func_name = func_name # Convert return type if loaded class if utils.isLoadedClass(return_el): wrapper_return_type = classutils.toWrapperType( return_type, remove_reference=True) else: wrapper_return_type = return_type # Write declaration line new_code += return_kw_str + wrapper_return_type + ' ' + wr_func_name + args_bracket + '\n' # Write function body indent = ' ' * cfg.indent new_code += '{\n' if return_type == 'void': new_code += indent else: new_code += indent + 'return ' # args_bracket_notypes = funcutils.constrArgsBracket(use_args, include_arg_name=True, include_arg_type=False, wrapper_to_pointer=True) args_bracket_notypes = funcutils.constrArgsBracket( use_args, include_arg_name=True, include_arg_type=False, cast_to_original=True, wrapper_to_pointer=True) if return_is_loaded: abs_return_type_simple = classutils.toAbstractType( return_type, include_namespace=True, remove_reference=True, remove_pointers=True) wrapper_return_type_simple = wrapper_return_type.replace( '*', '').replace('&', '') if is_ref: # Return-by-reference new_code += 'reference_returner< ' + wrapper_return_type_simple + ', ' + abs_return_type_simple + ' >( ' + call_func_name + args_bracket_notypes + ' );\n' elif (not is_ref) and (pointerness > 0): # Return-by-pointer new_code += 'pointer_returner< ' + wrapper_return_type_simple + ', ' + abs_return_type_simple + ' >( ' + call_func_name + args_bracket_notypes + ' );\n' else: # Return-by-value new_code += wrapper_return_type + '( ' + call_func_name + args_bracket_notypes + ' );\n' else: new_code += call_func_name + args_bracket_notypes + ';\n' new_code += '}\n' new_code += '\n' # Add 'extern "C" {...}' block new_code = 'extern "C"\n{\n' + new_code + '}\n' return new_code
def ignoreFunction(func_el, limit_pointerness=False, remove_n_args=0, print_warning=True): # TODO: When BOSS starts accepting template functions, add a check for the template arguments import modules.classutils as classutils func_name = getFunctionNameDict(func_el) # Should this function be ditched? if func_name['long_templ_args'] in cfg.ditch: return True # Ignore templated functions (BOSS cannot deal with that yet...) if utils.isTemplateFunction(func_el): if print_warning: reason = "Templated function. BOSS cannot deal with this yet." infomsg.IgnoredFunction(func_name['long_templ_args'], reason).printMessage() return True # Check if this is an operator function is_operator = False if func_el.tag == 'OperatorMethod': is_operator = True # Check function return type if 'returns' in func_el.keys(): return_type_dict = utils.findType(func_el) return_type = return_type_dict['name'] + '*'*return_type_dict['pointerness'] + '&'*return_type_dict['is_reference'] return_el = return_type_dict['el'] if not utils.isAcceptedType(return_el): if print_warning: reason = "Non-accepted return type '%s'." % return_type infomsg.IgnoredFunction(is_operator*'operator'+func_name['long_templ_args'], reason).printMessage() return True # Check argument types arg_types_accepted = True args = getArgs(func_el) use_n_args = len(args) - remove_n_args if remove_n_args > 0: args = args[:-remove_n_args] for arg_dict in args: arg_type_name = arg_dict['type'] arg_el = gb.id_dict[arg_dict['id']] # Find out if argument type is base type of any accepted type is_parent_of_accepted= False if utils.isNative(arg_el): arg_class_name = classutils.getClassNameDict(arg_el) if arg_class_name['long_templ'] in gb.parents_of_loaded_classes: is_parent_of_accepted = True if arg_dict['function_pointer']: if print_warning: reason = "Function pointer type argument, '%s'." % arg_dict['name'] infomsg.IgnoredFunction(is_operator*'operator'+func_name['long_templ_args'], reason).printMessage() arg_types_accepted = False break if (not utils.isAcceptedType(arg_el)): # and (not is_parent_of_accepted): if print_warning: reason = "Non-accepted argument type '%s'." % arg_type_name infomsg.IgnoredFunction(is_operator*'operator'+func_name['long_templ_args'], reason).printMessage() arg_types_accepted = False break if limit_pointerness == True: if utils.isLoadedClass(arg_el): if ('**' in arg_type_name) or ('*&' in arg_type_name): if print_warning: reason = "Argument of type pointer-to-pointer/reference-to-pointer to loaded class, '%s'." % arg_type_name infomsg.IgnoredFunction(is_operator*'operator'+func_name['long_templ_args'], reason).printMessage() arg_types_accepted = False break if (not arg_types_accepted): return True # Function accepted (i.e. should *not* be ignored) return False
def createFrontendHeader(function_xml_files_dict): # Read all xml files utils.xmlFilesToDicts(function_xml_files_dict.values()) # # Generate typedefs for loaded classes, from ::BACKENDNAME_SAFE_VERSION::class_name # to ::Gambit::Backends::BACKENDNAME_SAFE_VERSION::class_name # outer_namespace_list = ['Gambit', 'Backends', gb.gambit_backend_name_full] typedef_code = '' typedef_code += utils.constrNamespace(outer_namespace_list, 'open', indent=cfg.indent) # Loop over all classes for class_name in gb.classes_done: if not class_name['long'] in gb.factory_info.keys(): continue else: class_typedef_code = '' class_namespace, class_name_short = utils.removeNamespace( class_name['long'], return_namespace=True) if class_namespace == '': class_typedef_code += 'typedef ::' + gb.gambit_backend_name_full + '::' + class_name[ 'long'] + ' ' + class_name['short'] + ';\n' else: class_namespace_list = class_namespace.split('::') class_typedef_code += utils.constrNamespace( class_namespace_list, 'open', indent=cfg.indent) class_typedef_code += ' ' * cfg.indent * len( class_namespace_list ) + 'typedef ::' + gb.gambit_backend_name_full + '::' + class_name[ 'long'] + ' ' + class_name['short'] + ';\n' class_typedef_code += utils.constrNamespace( class_namespace_list, 'close', indent=cfg.indent) class_typedef_code = utils.addIndentation(class_typedef_code, 3 * cfg.indent) typedef_code += class_typedef_code typedef_code += utils.constrNamespace(outer_namespace_list, 'close', indent=cfg.indent) # # Generate code for all the BE_FUNCTION macros # be_function_macro_code = '' for i, func_name in enumerate(gb.functions_done): # Set useful variables xml_file = function_xml_files_dict[func_name['long_templ_args']] # If new xml file, initialise global dicts if xml_file != gb.xml_file_name: gb.xml_file_name = xml_file utils.initGlobalXMLdicts(xml_file, id_and_name_only=True) # Get wrapper function element tree = ET.parse(xml_file) root = tree.getroot() wr_func_el = None for el in root.findall('Function'): if el.get('name') == gb.wr_func_names[i]: wr_func_el = el if wr_func_el is None: continue # Get information about the return type. return_type_dict = utils.findType(wr_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 # Construct argument bracket args = funcutils.getArgs(wr_func_el) args_bracket = funcutils.constrArgsBracket(args, include_arg_name=False, include_arg_type=True, include_namespace=True) # Get mangled symbol # symbol = wr_func_el.get('mangled') symbol = wr_func_el.get('name') be_function_macro_code += 'BE_FUNCTION(' be_function_macro_code += func_name['short'] + ', ' be_function_macro_code += return_type + ', ' be_function_macro_code += args_bracket + ', ' be_function_macro_code += '"' + symbol + '"' + ', ' be_function_macro_code += '"' + func_name['short'] + '"' + ')\n' # # Generate code for the frontend header # frontend_content = '' # - Comment at beginning backend_name_and_version = cfg.gambit_backend_name + ' ' + cfg.gambit_backend_version frontend_content += '//\n' frontend_content += '// Frontend header generated by BOSS for GAMBIT backend %s.\n' % ( backend_name_and_version) frontend_content += '//\n' # - Include statement for the identification header frontend_content += '\n' frontend_content += '#include "' + os.path.join( gb.gambit_backend_incl_dir, gb.backend_types_basedir, gb.gambit_backend_name_full, 'identification.hpp') + '"\n' # - LOAD_LIBRARY macro frontend_content += '\n' frontend_content += 'LOAD_LIBRARY\n' # - Class typedefs frontend_content += '\n' frontend_content += typedef_code # - BE_FUNCTION macros frontend_content += '\n' frontend_content += '// Functions\n' frontend_content += be_function_macro_code # - Descriptions of different things that can go into a frontend header frontend_content += '// Variables\n' frontend_content += '\n' frontend_content += '// Initialisation function (dependencies)\n' frontend_content += '\n' frontend_content += '// Convenience functions (registration)\n' frontend_content += '\n' frontend_content += '// Initialisation function (definition)\n' frontend_content += 'BE_INI_FUNCTION{} END_BE_INI_FUNCTION\n' frontend_content += '\n' frontend_content += '// Convenience functions (definitions)\n' # - Include statement for backend_undefs.hpp frontend_content += '\n' frontend_content += '// End\n' frontend_content += '#include "' + os.path.join( gb.gambit_backend_incl_dir, 'backend_undefs.hpp') + '"\n' # Write to file f = open(gb.frontend_path, 'w') f.write(frontend_content) f.close()