예제 #1
0
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
예제 #2
0
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
예제 #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