def generate_cxx(module_name, code, specs=None, optimizations=None, module_dir=None): '''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) ''' pm, ir, renamings, docstrings = front_middle_end(module_name, code, optimizations, module_dir) # 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(ir, specs, renamings, types) specs.to_docstrings(docstrings) check_exports(ir, specs, renamings) 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 = renamings.get(function_name, 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 = HasArgument(internal_func_name).visit(ir) 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 = renamings.get(function_name, function_name) arguments_types = [pytype_to_ctype(t) for t in signature] arguments_names = HasArgument(internal_func_name).visit(ir) 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
def generate_cxx(module_name, code, specs=None, optimizations=None, module_dir=None): '''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) ''' pm, ir, renamings, docstrings = front_middle_end(module_name, code, optimizations, module_dir) # 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, renamings, types) specs.to_docstrings(docstrings) check_exports(ir, specs, renamings) 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 = renamings.get(function_name, 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 = HasArgument(internal_func_name).visit(ir) 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 = renamings.get(function_name, function_name) arguments_types = [pytype_to_ctype(t) for t in signature] arguments_names = HasArgument(internal_func_name).visit(ir) 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