예제 #1
0
def constrAbstractClassHeaderCode(class_el,
                                  class_name,
                                  abstr_class_name,
                                  namespaces,
                                  is_template,
                                  has_copy_constructor,
                                  construct_assignment_operator,
                                  abstr_class_fname,
                                  file_for_gambit=False):

    if file_for_gambit:
        abstr_class_fname = abstr_class_fname + '.FOR_GAMBIT'

    class_decl = ''

    # Add include statements
    ilude_statements = []
    include_statements = [
        '#include "' +
        os.path.join(gb.gambit_backend_incl_dir, 'abstractbase.hpp') + '"'
    ]
    include_statements += [
        '#include "' + gb.frwd_decls_abs_fname + cfg.header_extension + '"'
    ]
    include_statements += [
        '#include "' + gb.frwd_decls_wrp_fname + cfg.header_extension + '"'
    ]
    include_statements += utils.getIncludeStatements(
        class_el,
        convert_loaded_to='wrapper_decl',
        exclude_types=[class_name],
        include_parents=True,
        use_full_path=False,
        forward_declared='include')
    include_statements += ['#include <cstddef>']
    if gb.debug_mode or file_for_gambit:
        include_statements += ['#include <iostream>']
    include_statements_code = '\n'.join(include_statements) + 2 * '\n'
    class_decl += include_statements_code

    # # Add include statement for the enum declaration header. Put this inside a #ifndef ... #endif block
    # # to avoid multiple declaration when the abstract class header is included from the original class header.
    # enum_include_statement_code  = ''
    # enum_include_statement_code += '#ifndef ENUMS_DECLARED\n'
    # enum_include_statement_code += '#define ENUMS_DECLARED\n'
    # enum_include_statement_code += '#include "' + gb.enum_decls_wrp_fname + cfg.header_extension + '"\n'
    # # enum_include_statement_code += '#include "' + os.path.join(gb.backend_types_basedir, gb.gambit_backend_name_full, gb.enum_decls_wrp_fname + cfg.header_extension) + '"\n'
    # enum_include_statement_code += '#endif\n'
    # enum_include_statement_code += '\n'
    # class_decl += enum_include_statement_code

    # Add the the code for the abstract class
    if (is_template == True) and (class_name['long'] in templ_spec_done):
        pass
    elif (is_template == True) and (class_name['long'] not in templ_spec_done):
        class_decl += classutils.constrAbstractClassDecl(
            class_el,
            class_name,
            abstr_class_name,
            namespaces,
            indent=cfg.indent,
            file_for_gambit=file_for_gambit,
            template_types=spec_template_types,
            construct_assignment_operator=construct_assignment_operator)
        class_decl += '\n'
    else:
        class_decl += classutils.constrAbstractClassDecl(
            class_el,
            class_name,
            abstr_class_name,
            namespaces,
            indent=cfg.indent,
            file_for_gambit=file_for_gambit,
            construct_assignment_operator=construct_assignment_operator)
        class_decl += '\n'

    # - Register code
    gb.new_code[abstr_class_fname]['code_tuples'].append((-1, class_decl))
예제 #2
0
def generateClassMemberInterface(class_el, class_name, abstr_class_name,
                                 namespaces, original_file_name,
                                 original_file_content_nocomments,
                                 original_class_file_el, extras_src_file_name):

    # Find class name position in the original file
    class_name_pos = classutils.findClassNamePosition(
        class_el, original_file_content_nocomments)

    # Create lists of all public, 'non-artificial' members of the class
    member_methods = []
    member_variables = []
    member_operators = []
    if 'members' in class_el.keys():
        for mem_id in class_el.get('members').split():
            el = gb.id_dict[mem_id]
            if not 'artificial' in el.keys():
                if el.get('access') == 'public':
                    if (el.tag == 'Method'
                        ):  # and (not funcutils.ignoreFunction(el)):
                        member_methods.append(el)
                    elif (el.tag == 'OperatorMethod'
                          ):  #and (not funcutils.ignoreFunction(el)):
                        if funcutils.usesNativeType(el):
                            member_operators.append(el)
                    elif (el.tag in ('Field', 'Variable')):
                        if classutils.isAcceptedMemberVariable(el):
                            member_variables.append(el)

    # Determine insert position
    rel_pos_start, rel_pos_end = utils.getBracketPositions(
        original_file_content_nocomments[class_name_pos:], delims=['{', '}'])
    class_body_start = class_name_pos + rel_pos_start
    class_body_end = class_name_pos + rel_pos_end
    insert_pos = class_body_end

    # Generate code for wrapper functions for each each member function.
    # A declaration goes into the original class header,
    # while implementations are put in a new source file.

    declaration_code = '\n'
    implementation_code = '\n'
    current_access = None
    for method_el in member_methods:

        # We need to generate as many overloaded versions as there are arguments with default values
        n_overloads = funcutils.numberOfDefaultArgs(method_el)

        # Check for native types
        uses_native_type = funcutils.usesNativeType(method_el)

        # If no native types are used and no arguments have default values, we don't need a wrapper
        if (not uses_native_type) and (n_overloads == 0):
            continue

        # Generate wrapper code
        for remove_n_args in range(n_overloads + 1):

            # Check that function is acceptable
            if funcutils.ignoreFunction(method_el,
                                        remove_n_args=remove_n_args):
                continue

            if (remove_n_args == 0) and (not uses_native_type):
                continue

            # The declaration is put inside the original class
            method_access = method_el.get('access')
            if method_access != current_access:
                declaration_code += ' ' * (
                    len(namespaces) + 1) * cfg.indent + method_access + ':\n'
                current_access = method_access
            declaration_code += classutils.constrWrapperFunction(
                method_el,
                indent=cfg.indent,
                n_indents=len(namespaces) + 2,
                remove_n_args=remove_n_args,
                only_declaration=True)
            declaration_code += '\n'

            # The implementation goes into a new source file
            implementation_code += classutils.constrWrapperFunction(
                method_el,
                indent=cfg.indent,
                n_indents=0,
                remove_n_args=remove_n_args,
                include_full_namespace=True)
            implementation_code += 2 * '\n'

    # - Register code
    gb.new_code[original_file_name]['code_tuples'].append(
        (insert_pos, declaration_code))
    gb.new_code[extras_src_file_name]['code_tuples'].append(
        (-1, implementation_code))

    # Generate code for each member operator
    operator_declaration_code = '\n'
    operator_implementation_code = '\n'
    for operator_el in member_operators:
        operator_access = operator_el.get('access')
        if operator_access != current_access:
            operator_declaration_code += ' ' * (
                len(namespaces) + 1) * cfg.indent + operator_access + ':\n'
            current_access = operator_access

        # If default arguments are used, we need several overloads
        n_overloads = funcutils.numberOfDefaultArgs(operator_el)
        for remove_n_args in range(n_overloads + 1):

            # Put declaration in original class
            operator_declaration_code += classutils.constrWrapperFunction(
                operator_el,
                indent=cfg.indent,
                n_indents=len(namespaces) + 2,
                remove_n_args=remove_n_args,
                only_declaration=True)
            operator_declaration_code += '\n'

            # Put implementation in a new source file
            operator_implementation_code += classutils.constrWrapperFunction(
                operator_el,
                indent=cfg.indent,
                n_indents=0,
                remove_n_args=remove_n_args,
                include_full_namespace=True)
            operator_implementation_code += 2 * '\n'

    # - Register code
    gb.new_code[original_file_name]['code_tuples'].append(
        (insert_pos, operator_declaration_code))
    gb.new_code[extras_src_file_name]['code_tuples'].append(
        (-1, operator_implementation_code))

    # Generate a reference-returning method for each (public) member variable:
    ref_func_declaration_code = ''
    ref_func_implementation_code = ''
    if len(member_variables) > 0:
        n_indents = len(namespaces)
        ref_func_declaration_code += '\n'
        ref_func_declaration_code += ' ' * cfg.indent * (n_indents +
                                                         1) + 'public:\n'
        for var_el in member_variables:

            # Put declaration in original code
            ref_func_declaration_code += classutils.constrVariableRefFunction(
                var_el,
                virtual=False,
                indent=cfg.indent,
                n_indents=n_indents + 2,
                only_declaration=True,
                add_return_type_suffix=True)
            ref_func_declaration_code += '\n'

            # Put implementation in a new source file
            ref_func_implementation_code += classutils.constrVariableRefFunction(
                var_el,
                virtual=False,
                indent=cfg.indent,
                n_indents=0,
                include_full_namespace=True,
                add_return_type_suffix=True)
            ref_func_implementation_code += '\n'

    # - Register code
    if ref_func_declaration_code != '':
        gb.new_code[original_file_name]['code_tuples'].append(
            (insert_pos, ref_func_declaration_code))
        gb.new_code[extras_src_file_name]['code_tuples'].append(
            (-1, ref_func_implementation_code))

    # Generate pointer-based copy and assignment functions

    # 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.NoPointerCopyAndAssignmentFunctions(class_name['long_templ'],
                                                    reason).printMessage()
    else:

        n_indents = len(namespaces)
        ptr_declaration_code = '\n'
        ptr_implementation_code = '\n'

        ptr_declaration_code += ' ' * cfg.indent * (n_indents +
                                                    1) + 'public:\n'
        ptr_declaration_code += classutils.constrPtrCopyFunc(
            class_el,
            abstr_class_name['short'],
            class_name['short'],
            virtual=False,
            indent=cfg.indent,
            n_indents=n_indents + 2,
            only_declaration=True)
        ptr_declaration_code += '\n'

        ptr_declaration_code += ' ' * cfg.indent * (
            n_indents + 2) + 'using ' + abstr_class_name[
                'short'] + '::pointer_assign' + gb.code_suffix + ';\n'
        ptr_declaration_code += classutils.constrPtrAssignFunc(
            class_el,
            abstr_class_name['short'],
            class_name['short'],
            virtual=False,
            indent=cfg.indent,
            n_indents=n_indents + 2,
            only_declaration=True)

        ptr_implementation_code += '#include "' + os.path.join(
            gb.backend_types_basedir, gb.gambit_backend_name_full,
            'identification.hpp') + '"\n'
        ptr_implementation_code += '\n'
        ptr_implementation_code += classutils.constrPtrCopyFunc(
            class_el,
            abstr_class_name['short'],
            class_name['short'],
            virtual=False,
            indent=cfg.indent,
            n_indents=0,
            include_full_namespace=True)
        ptr_implementation_code += '\n'
        ptr_implementation_code += classutils.constrPtrAssignFunc(
            class_el,
            abstr_class_name['short'],
            class_name['short'],
            virtual=False,
            indent=cfg.indent,
            n_indents=0,
            include_full_namespace=True)
        ptr_implementation_code += '\n'
        ptr_implementation_code += '#include "' + os.path.join(
            gb.gambit_backend_incl_dir, 'backend_undefs.hpp') + '"\n'

        # - Generate include statements for the new source file
        include_statements = []
        include_statements += utils.getIncludeStatements(
            class_el,
            convert_loaded_to='none',
            input_element='class',
            use_full_path=True,
            forward_declared='only')
        include_statements += utils.getIncludeStatements(
            class_el,
            convert_loaded_to='wrapper',
            input_element='class',
            use_full_path=True,
            forward_declared='exclude')
        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) + '"')

        if utils.isHeader(original_class_file_el):
            use_path = utils.shortenHeaderPath(original_file_name)
            include_statements.append('#include "' + use_path + '"')

        include_statements = list(OrderedDict.fromkeys(include_statements))
        include_statements_code = '\n'.join(include_statements) + '\n'

        # - Register the code
        gb.new_code[original_file_name]['code_tuples'].append(
            (insert_pos, ptr_declaration_code))

        gb.new_code[extras_src_file_name]['code_tuples'].append(
            (0, include_statements_code))
        gb.new_code[extras_src_file_name]['code_tuples'].append(
            (-1, ptr_implementation_code))
예제 #3
0
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