Exemplo n.º 1
0
 def visit_Name(self, node):
     if node.id in self.local_names:
         return cxxid(node.id)
     elif node.id in self.global_declarations:
         return "{0}()".format(cxxid(node.id))
     else:
         return cxxid(node.id)
Exemplo n.º 2
0
    def visit_FunctionDef(self, node):

        self.fname = cxxid(node.name)
        tmp = self.prepare_functiondef_context(node)
        operator_body, formal_types, formal_args = tmp

        tmp = self.prepare_types(node)
        dflt_argv, dflt_argt, result_type, callable_type, pure_type = tmp

        # a function has a call operator to be called
        # and a default constructor to create instances
        fscope = "type{0}::".format(
            "<{0}>".format(", ".join(formal_types)) if formal_types else "")
        ffscope = "{0}::{1}".format(self.fname, fscope)

        operator_declaration = [
            templatize(
                make_const_function_declaration(
                    self, node, "typename {0}result_type".format(fscope),
                    "operator()", formal_types, formal_args, dflt_argv),
                formal_types, dflt_argt),
            EmptyStatement()
        ]
        operator_signature = make_const_function_declaration(
            self, node, "typename {0}result_type".format(ffscope),
            "{0}::operator()".format(self.fname), formal_types, formal_args)
        ctx = CachedTypeVisitor(self.lctx)
        operator_local_declarations = ([
            Statement("{0} {1}".format(
                self.types[self.local_names[k]].generate(ctx), cxxid(k)))
            for k in self.ldecls
        ])
        dependent_typedefs = ctx.typedefs()
        operator_definition = FunctionBody(
            templatize(operator_signature, formal_types),
            Block(dependent_typedefs + operator_local_declarations +
                  operator_body))

        ctx = CachedTypeVisitor()
        extra_typedefs = ([
            Typedef(Value(t.generate(ctx), t.name))
            for t in self.types[node][1]
        ] + [Typedef(Value(result_type.generate(ctx), "result_type"))])
        extra_typedefs = ctx.typedefs() + extra_typedefs
        return_declaration = [
            templatize(Struct("type", extra_typedefs), formal_types, dflt_argt)
        ]
        topstruct = Struct(self.fname, [callable_type, pure_type] +
                           return_declaration + operator_declaration)

        return [topstruct], [operator_definition]
Exemplo n.º 3
0
    def visit_Module(self, node):
        """ Build a compilation unit. """
        # build all types
        header_deps = sorted(self.dependencies)
        headers = [Include('/'.join(["pythonic", "include"] +
                                    [cxxid(x) for x in t]) + ".hpp")
                   for t in header_deps]
        headers += [Include('/'.join(["pythonic"] + [cxxid(x) for x in t])
                            + ".hpp")
                    for t in header_deps]

        decls_n_defns = list(filter(None, (self.visit(stmt) for stmt in
                                    node.body)))
        decls, defns = zip(*decls_n_defns) if decls_n_defns else ([], [])

        nsbody = [s for ls in decls + defns for s in ls]
        ns = Namespace(pythran_ward + self.passmanager.module_name, nsbody)
        self.result = CompilationUnit(headers + [ns])
Exemplo n.º 4
0
    def prepare_functiondef_context(self, node):
        # prepare context and visit function body
        fargs = node.args.args

        formal_args = [cxxid(arg.id) for arg in fargs]
        formal_types = ["argument_type" + str(i) for i in range(len(fargs))]

        local_decls = set(self.gather(LocalNodeDeclarations, node))
        self.local_names = {sym.id: sym for sym in local_decls}
        self.local_names.update({arg.id: arg for arg in fargs})

        self.lctx = CachedTypeVisitor()

        self.ldecls = {n.id for n in local_decls}
        body = [self.visit(stmt) for stmt in node.body]
        return body, formal_types, formal_args
Exemplo n.º 5
0
def has_argument(module, fname):
    '''Checks if a given function has arguments'''
    for n in module.body:
        if isinstance(n, ast.FunctionDef) and n.name == fname:
            return [cxxid(arg.id) for arg in n.args.args]
    return []
Exemplo n.º 6
0
def generate_cxx(module_name,
                 code,
                 specs=None,
                 optimizations=None,
                 module_dir=None,
                 report_times=False):
    '''python + pythran spec -> c++ code
    returns a PythonModule object and an error checker

    the error checker can be used to print more detailed info on the origin of
    a compile error (e.g. due to bad typing)

    '''
    if specs:
        entry_points = set(specs.keys())
    else:
        entry_points = None

    pm, ir, docstrings = front_middle_end(module_name,
                                          code,
                                          optimizations,
                                          module_dir,
                                          report_times=report_times,
                                          entry_points=entry_points)

    # back-end
    content = pm.dump(Cxx, ir)

    # instantiate the meta program
    if specs is None:

        class Generable(object):
            def __init__(self, content):
                self.content = content

            def __str__(self):
                return str(self.content)

            generate = __str__

        mod = Generable(content)

        def error_checker():
            tog.typecheck(ir)

    else:

        # uniform typing
        if isinstance(specs, dict):
            specs = Spec(specs, {})

        def error_checker():
            types = tog.typecheck(ir)
            check_specs(specs, types)

        specs.to_docstrings(docstrings)
        check_exports(pm, ir, specs)

        if isinstance(code, bytes):
            code_bytes = code
        else:
            code_bytes = code.encode('ascii', 'ignore')
        metainfo = {
            'hash': hashlib.sha256(code_bytes).hexdigest(),
            'version': __version__,
            'date': datetime.now()
        }

        mod = PythonModule(module_name, docstrings, metainfo)
        mod.add_to_includes(
            Include("pythonic/core.hpp"),
            Include("pythonic/python/core.hpp"),
            # FIXME: only include these when needed
            Include("pythonic/types/bool.hpp"),
            Include("pythonic/types/int.hpp"),
            Line("#ifdef _OPENMP\n#include <omp.h>\n#endif"))
        mod.add_to_includes(
            *[Include(inc) for inc in _extract_specs_dependencies(specs)])
        mod.add_to_includes(*content.body)
        mod.add_to_includes(Include("pythonic/python/exception_handler.hpp"), )

        def warded(module_name, internal_name):
            return pythran_ward + '{0}::{1}'.format(module_name, internal_name)

        for function_name, signatures in specs.functions.items():
            internal_func_name = cxxid(function_name)
            # global variables are functions with no signatures :-)
            if not signatures:
                mod.add_global_var(
                    function_name,
                    "{}()()".format(warded(module_name, internal_func_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]
                arguments_names = has_argument(ir, function_name)
                arguments = [
                    n for n, _ in zip(arguments_names, 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 arguments_names else "")
                result_type = "typename %s::result_type" % specialized_fname
                mod.add_pyfunction(
                    FunctionBody(
                        FunctionDeclaration(
                            Value(result_type, numbered_function_name), [
                                Value(t + '&&', a)
                                for t, a in zip(arguments_types, arguments)
                            ]),
                        Block([
                            Statement("""
                            PyThreadState *_save = PyEval_SaveThread();
                            try {{
                                auto res = {0}()({1});
                                PyEval_RestoreThread(_save);
                                return res;
                            }}
                            catch(...) {{
                                PyEval_RestoreThread(_save);
                                throw;
                            }}
                            """.format(warded(module_name, internal_func_name),
                                       ', '.join(arguments)))
                        ])), function_name, arguments_types, signature)

        for function_name, signature in specs.capsules.items():
            internal_func_name = cxxid(function_name)

            arguments_types = [pytype_to_ctype(t) for t in signature]
            arguments_names = has_argument(ir, function_name)
            arguments = [n for n, _ in zip(arguments_names, 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 arguments_names else "")
            result_type = "typename %s::result_type" % specialized_fname
            docstring = spec_to_string(function_name, signature)
            mod.add_capsule(
                FunctionBody(
                    FunctionDeclaration(Value(result_type, function_name), [
                        Value(t, a) for t, a in zip(arguments_types, arguments)
                    ]),
                    Block([
                        ReturnStatement("{0}()({1})".format(
                            warded(module_name, internal_func_name),
                            ', '.join(arguments)))
                    ])), function_name, docstring)

    return mod, error_checker
Exemplo n.º 7
0
    def visit_FunctionDef(self, node):
        tmp = self.prepare_functiondef_context(node)
        operator_body, formal_types, formal_args = tmp

        tmp = self.prepare_types(node)
        dflt_argv, dflt_argt, result_type, callable_type, pure_type = tmp

        # a generator has a call operator that returns the iterator
        next_name = "__generator__{0}".format(cxxid(node.name))
        instanciated_next_name = "{0}{1}".format(
            next_name,
            "<{0}>".format(", ".join(formal_types)) if formal_types else "")

        operator_body.append(
            Statement("{}: return result_type()".format(
                CxxGenerator.FinalStatement)))

        next_declaration = [
            FunctionDeclaration(Value("result_type", "next"), []),
            EmptyStatement()
        ]  # empty statement to force a comma ...

        # the constructors
        next_constructors = [
            FunctionBody(FunctionDeclaration(Value("", next_name), []),
                         Line(': pythonic::yielder() {}'))
        ]
        if formal_types:
            # If all parameters have a default value, we don't need default
            # constructor
            if dflt_argv and all(dflt_argv):
                next_constructors = list()
            next_constructors.append(
                FunctionBody(
                    make_function_declaration(self, node, "", next_name,
                                              formal_types, formal_args,
                                              dflt_argv),
                    Line(": {0} {{ }}".format(", ".join(
                        ["pythonic::yielder()"] +
                        ["{0}({0})".format(arg) for arg in formal_args])))))

        next_iterator = [
            FunctionBody(FunctionDeclaration(Value("void", "operator++"), []),
                         Block([Statement("next()")])),
            FunctionBody(
                FunctionDeclaration(
                    Value(
                        "typename {0}::result_type".format(
                            instanciated_next_name), "operator*"),
                    [], "const"),
                Block([ReturnStatement(CxxGenerator.StateValue)])),
            FunctionBody(
                FunctionDeclaration(
                    Value(
                        "pythonic::types::generator_iterator<{0}>".format(
                            next_name), "begin"), []),
                Block([
                    Statement("next()"),
                    ReturnStatement("pythonic::types::generator_iterator<{0}>"
                                    "(*this)".format(next_name))
                ])),
            FunctionBody(
                FunctionDeclaration(
                    Value(
                        "pythonic::types::generator_iterator<{0}>".format(
                            next_name), "end"), []),
                Block([
                    ReturnStatement(
                        "pythonic::types::generator_iterator<{0}>()".format(
                            next_name))
                ]))
        ]
        next_signature = templatize(
            FunctionDeclaration(
                Value(
                    "typename {0}::result_type".format(instanciated_next_name),
                    "{0}::next".format(instanciated_next_name)), []),
            formal_types)

        next_body = operator_body
        # the dispatch table at the entry point
        next_body.insert(
            0,
            Statement("switch({0}) {{ {1} }}".format(
                CxxGenerator.StateHolder,
                " ".join("case {0}: goto {1};".format(num, where)
                         for (num, where) in sorted(self.yields.values(),
                                                    key=lambda x: x[0])))))

        ctx = CachedTypeVisitor(self.lctx)
        next_members = ([
            Statement("{0} {1}".format(ft, fa))
            for (ft, fa) in zip(formal_types, formal_args)
        ] + [
            Statement("{0} {1}".format(
                self.types[self.local_names[k]].generate(ctx), k))
            for k in self.ldecls
        ] + [
            Statement("{0} {1}".format(v, k))
            for k, v in self.extra_declarations
        ] + [
            Statement("typename {0}::result_type {1}".format(
                instanciated_next_name, CxxGenerator.StateValue))
        ])

        extern_typedefs = [
            Typedef(Value(t.generate(ctx), t.name))
            for t in self.types[node][1]
        ]
        iterator_typedef = [
            Typedef(
                Value(
                    "pythonic::types::generator_iterator<{0}>".format(
                        "{0}<{1}>".format(next_name, ", ".join(formal_types)
                                          ) if formal_types else next_name),
                    "iterator")),
            Typedef(Value(result_type.generate(ctx), "value_type"))
        ]
        result_typedef = [
            Typedef(Value(result_type.generate(ctx), "result_type"))
        ]
        extra_typedefs = (ctx.typedefs() + extern_typedefs + iterator_typedef +
                          result_typedef)

        next_struct = templatize(
            Struct(
                next_name, extra_typedefs + next_members + next_constructors +
                next_iterator + next_declaration, "pythonic::yielder"),
            formal_types)
        next_definition = FunctionBody(next_signature, Block(next_body))

        operator_declaration = [
            templatize(
                make_const_function_declaration(self, node,
                                                instanciated_next_name,
                                                "operator()", formal_types,
                                                formal_args, dflt_argv),
                formal_types, dflt_argt),
            EmptyStatement()
        ]
        operator_signature = make_const_function_declaration(
            self, node, instanciated_next_name,
            "{0}::operator()".format(cxxid(node.name)), formal_types,
            formal_args)
        operator_definition = FunctionBody(
            templatize(operator_signature, formal_types),
            Block([
                ReturnStatement("{0}({1})".format(instanciated_next_name,
                                                  ", ".join(formal_args)))
            ]))

        topstruct_type = templatize(Struct("type", extra_typedefs),
                                    formal_types)
        topstruct = Struct(cxxid(node.name),
                           [topstruct_type, callable_type, pure_type] +
                           operator_declaration)

        return [next_struct, topstruct], [next_definition, operator_definition]
Exemplo n.º 8
0
 def visit_Module(self, node):
     for n in node.body:
         if isinstance(n, ast.FunctionDef) and n.name == self.fname:
             return [cxxid(arg.id) for arg in n.args.args]
     return []