Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
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()