file modules/funcparse.py
[No description available]
Namespaces
Name |
---|
modules |
modules::funcparse |
Source code
###############################
# #
# Function parsing for BOSS #
# #
###############################
from __future__ import print_function
from collections import OrderedDict
import os
import modules.active_cfg as active_cfg
exec("import configs." + active_cfg.module_name + " as cfg")
import modules.gb as gb
import modules.utils as utils
import modules.funcutils as funcutils
import modules.classutils as classutils
import modules.infomsg as infomsg
#
# Module-level globals
#
# ====== run ========
# Main function for parsing functions
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 = utils.orderIncludeStatements(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()
#
# End loop over functions
#
# ====== END: run ========
# ====== generateFunctionWrapperClassVersion ========
# Function for generating a source file containing wrapper
# functions that make use of the wrapper classes.
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
# ====== END: generateFunctionWrapperClassVersion ========
Updated on 2022-08-03 at 12:58:21 +0000