def cxx_generator(module_name, code, specs=None, optimizations=None): '''python + pythran spec -> c++ code''' pm = PassManager(module_name) # font end ir = ast.parse(code) # parse openmp directive pm.apply(GatherOMPData, ir) # avoid conflicts with cxx keywords renamings = pm.apply(NormalizeIdentifiers, ir) check_syntax(ir) # middle-end if not optimizations: optimizations = default_optimization_sequence else: optimizations = [parse_optimization(optim) for optim in optimizations] refine(pm, ir, optimizations) # back-end content = pm.dump(Cxx, ir) if specs is None: class Generable: def __init__(self, content): self.content = content def generate(self): return "\n".join("\n".join(l for l in s.generate()) for s in self.content) mod = Generable(content) else: # uniform typing for fname, signatures in specs.items(): if not isinstance(signatures, tuple): specs[fname] = (signatures,) mod = BoostPythonModule(module_name) mod.use_private_namespace = False # very low value for max_arity leads to various bugs max_arity = max(4, max(max(map(len, s)) for s in specs.itervalues())) mod.add_to_preamble([Define("BOOST_PYTHON_MAX_ARITY", max_arity)]) mod.add_to_preamble(content) mod.add_to_init([Statement( 'boost::python::numeric::array::set_module_and_type("numpy", "ndarray")')]) mod.add_to_init([Statement( 'boost::python::implicitly_convertible<std::string,' + 'pythonic::core::string>()')]) for function_name, signatures in specs.iteritems(): internal_function_name = renamings.get(function_name, function_name) for sigid, signature in enumerate(signatures): numbered_function_name = "{0}{1}".format( internal_function_name, sigid) arguments_types = [pytype_to_ctype(t) for t in signature] arguments = ["a{0}".format(i) for i in xrange(len(arguments_types))] specialized_fname = "__{0}::{1}::type{2}".format( module_name, internal_function_name, "<{0}>".format( ", ".join(arguments_types)) if arguments_types else "") result_type = ("typename std::remove_reference" + "<typename {0}::result_type>::type".format( specialized_fname)) mod.add_to_init([Statement("python_to_pythran<{0}>()".format( t)) for t in extract_all_constructed_types(signature)]) mod.add_to_init([Statement( "pythran_to_python<{0}>()".format(result_type))]) mod.add_function( FunctionBody( FunctionDeclaration( Value( result_type, numbered_function_name), [Value(t, a) for t, a in zip( arguments_types, arguments)]), Block([Statement("return {0}()({1})".format( '__{0}::{1}'.format( module_name, internal_function_name), ', '.join(arguments)))]) ), function_name ) return mod
def generate_cxx(module_name, code, specs=None, optimizations=None): '''python + pythran spec -> c++ code returns a BoostPythonModule object ''' pm = PassManager(module_name) # front end ir, renamings = frontend.parse(pm, code) # middle-end optimizations = (optimizations or cfg.get('pythran', 'optimizations').split()) optimizations = map(_parse_optimization, optimizations) refine(pm, ir, optimizations) # back-end content = pm.dump(Cxx, ir) # instanciate the meta program if specs is None: class Generable: def __init__(self, content): self.content = content def __str__(self): return str(self.content) generate = __str__ mod = Generable(content) else: # uniform typing for fname, signatures in specs.items(): if not isinstance(signatures, tuple): specs[fname] = (signatures,) mod = BoostPythonModule(module_name) mod.use_private_namespace = False # very low value for max_arity leads to various bugs min_val = 2 specs_max = [max(map(len, s)) for s in specs.itervalues()] max_arity = max([min_val] + specs_max) mod.add_to_preamble([Define("BOOST_PYTHON_MAX_ARITY", max_arity)]) mod.add_to_preamble([Define("BOOST_SIMD_NO_STRICT_ALIASING", "1")]) mod.add_to_preamble([Include("pythonic/core.hpp")]) mod.add_to_preamble([Include("pythonic/python/core.hpp")]) mod.add_to_preamble(map(Include, _extract_specs_dependencies(specs))) mod.add_to_preamble(content.body) mod.add_to_init([ Line('#ifdef PYTHONIC_TYPES_NDARRAY_HPP\nimport_array()\n#endif')]) # topologically sorted exceptions based on the inheritance hierarchy. # needed because otherwise boost python register_exception handlers # do not catch exception type in the right way # (first valid exception is selected) # Inheritance has to be taken into account in the registration order. exceptions = nx.DiGraph() for function_name, v in functions.iteritems(): for mname, symbol in v: if isinstance(symbol, ConstExceptionIntr): exceptions.add_node( getattr(sys.modules[mname], function_name)) # add edges based on class relationships for n in exceptions: if n.__base__ in exceptions: exceptions.add_edge(n.__base__, n) sorted_exceptions = nx.topological_sort(exceptions) mod.add_to_init([ # register exception only if they can be raise from C++ world to # Python world. Preprocessors variables are set only if deps # analysis detect that this exception can be raised Line('#ifdef PYTHONIC_BUILTIN_%s_HPP\n' 'boost::python::register_exception_translator<' 'pythonic::types::%s>(&pythonic::translate_%s);\n' '#endif' % (n.__name__.upper(), n.__name__, n.__name__) ) for n in sorted_exceptions]) for function_name, signatures in specs.iteritems(): internal_func_name = renamings.get(function_name, function_name) for sigid, signature in enumerate(signatures): numbered_function_name = "{0}{1}".format(internal_func_name, sigid) arguments_types = [pytype_to_ctype(t) for t in signature] has_arguments = HasArgument(internal_func_name).visit(ir) arguments = ["a{0}".format(i) for i in xrange(len(arguments_types))] name_fmt = pythran_ward + "{0}::{1}::type{2}" args_list = ", ".join(arguments_types) specialized_fname = name_fmt.format(module_name, internal_func_name, "<{0}>".format(args_list) if has_arguments else "") result_type = ("typename std::remove_reference" + "<typename {0}::result_type>::type".format( specialized_fname)) mod.add_to_init( [Statement("pythonic::python_to_pythran<{0}>()".format(t)) for t in _extract_all_constructed_types(signature)]) mod.add_to_init([Statement( "pythonic::pythran_to_python<{0}>()".format(result_type))]) mod.add_function( FunctionBody( FunctionDeclaration( Value( result_type, numbered_function_name), [Value(t, a) for t, a in zip(arguments_types, arguments)]), Block([Statement("return {0}()({1})".format( pythran_ward + '{0}::{1}'.format( module_name, internal_func_name), ', '.join(arguments)))]) ), function_name ) # call __init__() to execute top-level statements init_call = '::'.join([pythran_ward + module_name, '__init__()()']) mod.add_to_init([Statement(init_call)]) return mod
def generate_cxx(module_name, code, specs=None, optimizations=None): '''python + pythran spec -> c++ code returns a BoostPythonModule object ''' pm = PassManager(module_name) # font end ir = ast.parse(code) # parse openmp directive pm.apply(GatherOMPData, ir) # avoid conflicts with cxx keywords renamings = pm.apply(NormalizeIdentifiers, ir) check_syntax(ir) # middle-end optimizations = (optimizations or cfg.get('pythran', 'optimizations').split()) optimizations = map(_parse_optimization, optimizations) refine(pm, ir, optimizations) # back-end content = pm.dump(Cxx, ir) if not specs: # Match "None" AND empty specs class Generable: def __init__(self, content): self.content = content def generate(self): return "\n".join("\n".join(l for l in s.generate()) for s in self.content) mod = Generable(content) else: # uniform typing for fname, signatures in specs.items(): if not isinstance(signatures, tuple): specs[fname] = (signatures,) mod = BoostPythonModule(module_name) mod.use_private_namespace = False # very low value for max_arity leads to various bugs max_arity = max(4, max(max(map(len, s)) for s in specs.itervalues())) mod.add_to_preamble([Define("BOOST_PYTHON_MAX_ARITY", max_arity)]) mod.add_to_preamble([Define("BOOST_SIMD_NO_STRICT_ALIASING", "1")]) mod.add_to_preamble(content) mod.add_to_init([ Statement('import_array()'), Statement('boost::python::implicitly_convertible<std::string,' + 'pythonic::core::string>()')] ) for function_name, signatures in specs.iteritems(): internal_func_name = renamings.get(function_name, function_name) for sigid, signature in enumerate(signatures): numbered_function_name = "{0}{1}".format(internal_func_name, sigid) arguments_types = [pytype_to_ctype(t) for t in signature] has_arguments = HasArgument(internal_func_name).visit(ir) arguments = ["a{0}".format(i) for i in xrange(len(arguments_types))] name_fmt = pythran_ward + "{0}::{1}::type{2}" args_list = ", ".join(arguments_types) specialized_fname = name_fmt.format(module_name, internal_func_name, "<{0}>".format(args_list) if has_arguments else "") result_type = ("typename std::remove_reference" + "<typename {0}::result_type>::type".format( specialized_fname)) mod.add_to_init( [Statement("python_to_pythran<{0}>()".format(t)) for t in _extract_all_constructed_types(signature)]) mod.add_to_init([Statement( "pythran_to_python<{0}>()".format(result_type))]) mod.add_function( FunctionBody( FunctionDeclaration( Value( result_type, numbered_function_name), [Value(t, a) for t, a in zip(arguments_types, arguments)]), Block([Statement("return {0}()({1})".format( pythran_ward + '{0}::{1}'.format( module_name, internal_func_name), ', '.join(arguments)))]) ), function_name ) return mod
def generate_cxx(module_name, code, specs=None, optimizations=None): '''python + pythran spec -> c++ code returns a BoostPythonModule object ''' pm = PassManager(module_name) # front end ir, renamings = frontend.parse(pm, code) # middle-end optimizations = (optimizations or cfg.get('pythran', 'optimizations').split()) optimizations = map(_parse_optimization, optimizations) refine(pm, ir, optimizations) # back-end content = pm.dump(Cxx, ir) # instanciate the meta program if specs is None: class Generable: def __init__(self, content): self.content = content def __str__(self): return str(self.content) generate = __str__ mod = Generable(content) else: # uniform typing for fname, signatures in specs.items(): if not isinstance(signatures, tuple): specs[fname] = (signatures, ) mod = BoostPythonModule(module_name) mod.use_private_namespace = False # very low value for max_arity leads to various bugs min_val = 2 specs_max = [max(map(len, s)) for s in specs.itervalues()] max_arity = max([min_val] + specs_max) mod.add_to_preamble([Define("BOOST_PYTHON_MAX_ARITY", max_arity)]) mod.add_to_preamble([Define("BOOST_SIMD_NO_STRICT_ALIASING", "1")]) mod.add_to_preamble([Include("pythonic/core.hpp")]) mod.add_to_preamble([Include("pythonic/python/core.hpp")]) mod.add_to_preamble(map(Include, _extract_specs_dependencies(specs))) mod.add_to_preamble(content.body) mod.add_to_init([ Line('#ifdef PYTHONIC_TYPES_NDARRAY_HPP\nimport_array()\n#endif') ]) # topologically sorted exceptions based on the inheritance hierarchy. # needed because otherwise boost python register_exception handlers # do not catch exception type in the right way # (first valid exception is selected) # Inheritance has to be taken into account in the registration order. exceptions = nx.DiGraph() for function_name, v in functions.iteritems(): for mname, symbol in v: if isinstance(symbol, ConstExceptionIntr): exceptions.add_node( getattr(sys.modules[mname], function_name)) # add edges based on class relationships for n in exceptions: if n.__base__ in exceptions: exceptions.add_edge(n.__base__, n) sorted_exceptions = nx.topological_sort(exceptions) mod.add_to_init([ # register exception only if they can be raise from C++ world to # Python world. Preprocessors variables are set only if deps # analysis detect that this exception can be raised Line('#ifdef PYTHONIC_BUILTIN_%s_HPP\n' 'boost::python::register_exception_translator<' 'pythonic::types::%s>(&pythonic::translate_%s);\n' '#endif' % (n.__name__.upper(), n.__name__, n.__name__)) for n in sorted_exceptions ]) for function_name, signatures in specs.iteritems(): internal_func_name = renamings.get(function_name, function_name) for sigid, signature in enumerate(signatures): numbered_function_name = "{0}{1}".format( internal_func_name, sigid) arguments_types = [pytype_to_ctype(t) for t in signature] has_arguments = HasArgument(internal_func_name).visit(ir) arguments = [ "a{0}".format(i) for i in xrange(len(arguments_types)) ] name_fmt = pythran_ward + "{0}::{1}::type{2}" args_list = ", ".join(arguments_types) specialized_fname = name_fmt.format( module_name, internal_func_name, "<{0}>".format(args_list) if has_arguments else "") result_type = ("typename std::remove_reference" + "<typename {0}::result_type>::type".format( specialized_fname)) mod.add_to_init([ Statement("pythonic::python_to_pythran<{0}>()".format(t)) for t in _extract_all_constructed_types(signature) ]) mod.add_to_init([ Statement("pythonic::pythran_to_python<{0}>()".format( result_type)) ]) mod.add_function( FunctionBody( FunctionDeclaration( Value(result_type, numbered_function_name), [ Value(t, a) for t, a in zip(arguments_types, arguments) ]), Block([ Statement("return {0}()({1})".format( pythran_ward + '{0}::{1}'.format( module_name, internal_func_name), ', '.join(arguments))) ])), function_name) # call __init__() to execute top-level statements init_call = '::'.join([pythran_ward + module_name, '__init__()()']) mod.add_to_init([Statement(init_call)]) return mod