From 799bf36be96229b9a4b5189b2108b89124c585c0 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Sat, 30 Oct 2010 21:20:56 -0700 Subject: [PATCH] Basic cython.inline --- Cython/Build/Inline.py | 74 ++++++++++++++++++++++++++++++++++++++++ Cython/Build/__init__.py | 0 Cython/Shadow.py | 12 +++++++ 3 files changed, 86 insertions(+) create mode 100644 Cython/Build/Inline.py create mode 100644 Cython/Build/__init__.py diff --git a/Cython/Build/Inline.py b/Cython/Build/Inline.py new file mode 100644 index 00000000..a0b27f59 --- /dev/null +++ b/Cython/Build/Inline.py @@ -0,0 +1,74 @@ +import tempfile +import sys, os, re + +try: + import hashlib +except ImportError: + import md5 as hashlib + +from distutils.dist import Distribution +from distutils.core import Extension +from Cython.Distutils import build_ext + +code_cache = {} + +def get_type(arg): + py_type = type(arg) + # TODO: numpy + # TODO: extension types + if py_type in [list, tuple, dict, str]: + return py_type.__name__ + elif py_type is float: + return 'double' + elif py_type is int: + return 'long' + else: + return 'object' + +# TODO: use locals/globals for unbound variables +def cython_inline(code, types='aggressive', lib_dir=os.path.expanduser('~/.cython/inline'), **kwds): + _, pyx_file = tempfile.mkstemp('.pyx') + arg_names = kwds.keys() + arg_names.sort() + arg_sigs = tuple((get_type(kwds[arg]), arg) for arg in arg_names) + key = code, arg_sigs + module = code_cache.get(key) + if not module: + module_body, extract_func_code = extract_bodies(code) + params = ', '.join('%s %s' % a for a in arg_sigs) + module_code = """ +%(module_body)s +def __invoke(%(params)s): +%(func_body)s + """ % locals() + open(pyx_file, 'w').write(module_code) + module = "_" + hashlib.md5(code + str(arg_sigs)).hexdigest() + extension = Extension( + name = module, + sources=[pyx_file]) + build_extension = build_ext(Distribution()) + build_extension.finalize_options() + build_extension.extensions = [extension] + build_extension.build_temp = os.path.dirname(pyx_file) + if lib_dir not in sys.path: + sys.path.append(lib_dir) + build_extension.build_lib = lib_dir + build_extension.run() + code_cache[key] = module + arg_list = [kwds[arg] for arg in arg_names] + return __import__(module).__invoke(*arg_list) + +module_statement = re.compile(r'^((cdef +(extern|class))|cimport|(from .+ cimport)|(from .+ import +[*]))') +def extract_func_code(code): + module = [] + function = [] + # TODO: string literals, backslash + current = function + for line in code.split('\n'): + if not line.startswith(' '): + if module_statement.match(line): + current = module + else: + current = function + current.append(line) + return '\n'.join(module), ' ' + '\n '.join(function) diff --git a/Cython/Build/__init__.py b/Cython/Build/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/Cython/Shadow.py b/Cython/Shadow.py index d7dd186d..72b864bd 100644 --- a/Cython/Shadow.py +++ b/Cython/Shadow.py @@ -1,11 +1,23 @@ +# cython.* namespace for pure mode. + compiled = False def empty_decorator(x): return x +# Function decorators + def locals(**arg_types): return empty_decorator +def inline(f, *args, **kwds): + if isinstance(f, basestring): + from Cython.Build.Inline import cython_inline + return cython_inline(f, *args, **kwds) + else: + assert len(args) == len(kwds) == 0 + return f + # Special functions def cdiv(a, b): -- 2.26.2