Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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