pax_global_header00006660000000000000000000000064123132324230014505gustar00rootroot0000000000000052 comment=0e6e38ec890d83f17b16c06ed86eaffea6507d23 cython-0.20.1+git90-g0e6e38e/000077500000000000000000000000001231323242300152455ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/.gitignore000066400000000000000000000003641231323242300172400ustar00rootroot00000000000000*.pyc *.pyo __pycache__ *.so *.o *.egg *.egg-info Cython/Compiler/*.c Cython/Plex/*.c Cython/Runtime/refnanny.c Cython/Tempita/*.c Tools/*.elc BUILD/ build/ !tests/build/ dist/ .gitrev .coverage *.orig *.rej *.dep *.swp *~ tags TAGS .tox cython-0.20.1+git90-g0e6e38e/.hgignore000066400000000000000000000003231231323242300170460ustar00rootroot00000000000000syntax: glob *.pyc *.pyo __pycache__ *.egg *.egg-info Cython/Compiler/*.c Cython/Plex/*.c Cython/Runtime/refnanny.c BUILD/ build/ dist/ .git/ .gitrev .coverage *.orig *.rej *.dep *.swp *.so *.o *~ tags TAGS cython-0.20.1+git90-g0e6e38e/.hgtags000066400000000000000000000050261231323242300165260ustar00rootroot00000000000000966abe58538dfbdaccd53bd970d4998c78ea522e 0.9.6.14 67ee5a34bfc662e4e3cf989c2c8bf78a412ae8f4 0.9.8rc1 16a746d969e2654112fc0dc081690b891c496977 Version-0.9.8 a09347d7b470290076b983aef98707921445a038 0.9.8.1 82084a7b654e2a133ab64ceb47e03d6e7a204990 0.9.9.2.beta a89b05b78236a27a654f3004bdffc7b8a56311a7 0.10 ef9d2c680684d0df7d81f529cda29e9e1741f575 cython-0.10.1 92baafe0edf3cea00deb7ce1e31e337bb485af1a 0.10.2 cdf889c30e7a7053de20bae3a578dad09ebcbdf5 0.10.3 59c67af0674bd93c5fd8958e08c76a9dab9aae37 sage-cythonizes a4abf0156540db4d3ebaa95712b65811c43c5acb 0.11-beta 838a6b7cae62e01dc0ce663cccab1f93f649fdbd 0.11.rc 4497f635d5fdbd38ebb841be4869fbfa2bbfdbb6 0.11.1.alpha 7bc36a0f81723117a19f92ffde1676a0884fef65 0.11.1.beta 6454db601984145f38e28d34176fca8a3a22329c 0.11.1 af6f1bed8cd40a2edefb57d3eacbc9274a8788b4 0.11.2.rc1 15ad532e2127840ae09dfbe46ccc80ac8c562f99 0.11.2 eb00d00a73c13b6aa8b440fe07cd7acb52a060e8 0.11.3.rc0 7c695fe49fd6912f52d995fe512d66baacf90ee6 0.11.3 4208042ceeae634f5c0999b8ab75f69faf46b6db 0.12.alpha0 e77827f09af67560aa82a18feab778f71ca0a9d3 0.12.rc0 fae19937e4945c59a5d9d62c63f1c3b09046c3a3 0.12 e90c522631ae06f2170a751fb256cdea0e50fb21 0.12.1 5ac2eaefcdc9c3a7a9c29a0bb8c3e4c6c016c64c 0.13.beta0 14957f635a379c97d9966097276313e43491ed96 0.13.beta1 32c957267b3ba3140fba4d1947fa98484d5e956b 0.13 ef9d2c680684d0df7d81f529cda29e9e1741f575 0.10.1 16a746d969e2654112fc0dc081690b891c496977 0.9.8 16a746d969e2654112fc0dc081690b891c496977 Version-0.9.8 0000000000000000000000000000000000000000 Version-0.9.8 ef9d2c680684d0df7d81f529cda29e9e1741f575 cython-0.10.1 0000000000000000000000000000000000000000 cython-0.10.1 59c67af0674bd93c5fd8958e08c76a9dab9aae37 sage-cythonizes 0000000000000000000000000000000000000000 sage-cythonizes 478f57be445d18fe294db849d7ad317fe7d7658f 0.14.alpha0 31b531a6c45b2c34ae5a1af8a2c09f152adea60d 0.14.beta1 7fa84cb6d3d75eb3d015aeeb60bf8b642171fe93 0.14.beta2 7fa84cb6d3d75eb3d015aeeb60bf8b642171fe93 0.14.beta2 8412b39fbc3eb709a543e2f1e95c0c8881ea9ed4 0.14.beta2 a6b9f0a6d02d23fc3d3a9d0587867faa3afb2fcd 0.14.rc0 15bf34c9387444e262acb1de594405444dd571a4 0.14 5320ddd8c3a60d00e0513f9f70d6846cd449409b 0.17.beta1 275fb550c1d802da3df35ebae41e04eadc60e49e 0.17.2 b0faba6967e74f652286a0de6d02d736845b0708 0.17.3 c1a18ab6b0808e87f68d2f9d914c01934510aef5 0.18b1 9a11631e0edb0394b17554cde8bec5d4784117e4 0.18rc1 76f33728e8534e698267e097cf603ea59ade6f30 0.18 4f782ac7b3fdf3b4408bbf9f2ed4c38f31e60920 0.19b1 52beb5b16df5b8a92bb6c8c47faf42370d73cb0f 0.19b2 4818f5b68eb4b4ea6ad7e415f6672b491e2461bc 0.19rc1 48407fa3f3c9da84ab3dc103a6a2b1ca4c1beb2a 0.19 cython-0.20.1+git90-g0e6e38e/.travis.yml000066400000000000000000000003261231323242300173570ustar00rootroot00000000000000language: python python: - 2.6 - 2.7 - 3.2 - 3.3 # - pypy branches: only: - master install: pip install . script: CFLAGS=-O0 python runtests.py -vv matrix: allow_failures: - python: pypy cython-0.20.1+git90-g0e6e38e/CHANGES.rst000066400000000000000000001077541231323242300170650ustar00rootroot00000000000000================ Cython Changelog ================ 0.20.2 =================== Features added -------------- * Some optimisations for set/frozenset instantiation. * Support for C++ unordered_set and unordered_map. Bugs fixed ---------- * Compiler crash on readonly properties in "binding" mode. * Auto-encoding with ``c_string_encoding=ascii`` failed in Py3.3. * Crash when subtyping freelist enabled Cython extension types with Python classes that use ``__slots__``. * Freelist usage is restricted to CPython to avoid problems with other Python implementations. * Memory leak in memory views when copying overlapping, contiguous slices. * Format checking when requesting non-contiguous buffers from ``cython.array`` objects was disabled in Py3. * C++ destructor calls in extension types could fail to compile in clang. * Buffer format validation failed for sequences of strings in structs. * Docstrings on extension type attributes in .pxd files were rejected. 0.20.1 (2014-02-11) =================== Bugs fixed ---------- * Build error under recent MacOS-X versions where ``isspace()`` could not be resolved by clang. * List/Tuple literals multiplied by more than one factor were only multiplied by the last factor instead of all. * Lookups of special methods (specifically for context managers) could fail in Python <= 2.6/3.1. * Local variables were erroneously appended to the signature introspection of Cython implemented functions with keyword-only arguments under Python 3. * In-place assignments to variables with inferred Python builtin/extension types could fail with type errors if the result value type was incompatible with the type of the previous value. * The C code generation order of cdef classes, closures, helper code, etc. was not deterministic, thus leading to high code churn. * Type inference could fail to deduce C enum types. * Type inference could deduce unsafe or inefficient types from integer assignments within a mix of inferred Python variables and integer variables. 0.20 (2014-01-18) ================= Features added -------------- * Support for CPython 3.4. * Support for calling C++ template functions. * ``yield`` is supported in ``finally`` clauses. * The C code generated for finally blocks is duplicated for each exit case to allow for better optimisations by the C compiler. * Cython tries to undo the Python optimisationism of assigning a bound method to a local variable when it can generate better code for the direct call. * Constant Python float values are cached. * String equality comparisons can use faster type specific code in more cases than before. * String/Unicode formatting using the '%' operator uses a faster C-API call. * ``bytearray`` has become a known type and supports coercion from and to C strings. Indexing, slicing and decoding is optimised. Note that this may have an impact on existing code due to type inference. * Using ``cdef basestring stringvar`` and function arguments typed as ``basestring`` is now meaningful and allows assigning exactly ``str`` and ``unicode`` objects, but no subtypes of these types. * Support for the ``__debug__`` builtin. * Assertions in Cython compiled modules are disabled if the running Python interpreter was started with the "-O" option. * Some types that Cython provides internally, such as functions and generators, are now shared across modules if more than one Cython implemented module is imported. * The type inference algorithm works more fine granular by taking the results of the control flow analysis into account. * A new script in ``bin/cythonize`` provides a command line frontend to the cythonize() compilation function (including distutils build). * The new extension type decorator ``@cython.no_gc_clear`` prevents objects from being cleared during cyclic garbage collection, thus making sure that object attributes are kept alive until deallocation. * During cyclic garbage collection, attributes of extension types that cannot create reference cycles due to their type (e.g. strings) are no longer considered for traversal or clearing. This can reduce the processing overhead when searching for or cleaning up reference cycles. * Package compilation (i.e. ``__init__.py`` files) now works, starting with Python 3.3. * The cython-mode.el script for Emacs was updated. Patch by Ivan Andrus. * An option common_utility_include_dir was added to cythonize() to save oft-used utility code once in a separate directory rather than as part of each generated file. * ``unraisable_tracebacks`` directive added to control printing of tracebacks of unraisable exceptions. Bugs fixed ---------- * Abstract Python classes that subtyped a Cython extension type failed to raise an exception on instantiation, and thus ended up being instantiated. * ``set.add(a_tuple)`` and ``set.discard(a_tuple)`` failed with a TypeError in Py2.4. * The PEP 3155 ``__qualname__`` was incorrect for nested classes and inner classes/functions declared as ``global``. * Several corner cases in the try-finally statement were fixed. * The metaclass of a Python class was not inherited from its parent class(es). It is now extracted from the list of base classes if not provided explicitly using the Py3 ``metaclass`` keyword argument. In Py2 compilation mode, a ``__metaclass__`` entry in the class dict will still take precedence if not using Py3 metaclass syntax, but only *after* creating the class dict (which may have been done by a metaclass of a base class, see PEP 3115). It is generally recommended to use the explicit Py3 syntax to define metaclasses for Python types at compile time. * The automatic C switch statement generation behaves more safely for heterogeneous value types (e.g. mixing enum and char), allowing for a slightly wider application and reducing corner cases. It now always generates a 'default' clause to avoid C compiler warnings about unmatched enum values. * Fixed a bug where class hierarchies declared out-of-order could result in broken generated code. * Fixed a bug which prevented overriding const methods of C++ classes. * Fixed a crash when converting Python objects to C++ strings fails. Other changes ------------- * In Py3 compilation mode, Python2-style metaclasses declared by a ``__metaclass__`` class dict entry are ignored. * In Py3.4+, the Cython generator type uses ``tp_finalize()`` for safer cleanup instead of ``tp_del()``. 0.19.2 (2013-10-13) =================== Features added -------------- Bugs fixed ---------- * Some standard declarations were fixed or updated, including the previously incorrect declaration of ``PyBuffer_FillInfo()`` and some missing bits in ``libc.math``. * Heap allocated subtypes of ``type`` used the wrong base type struct at the C level. * Calling the unbound method dict.keys/value/items() in dict subtypes could call the bound object method instead of the unbound supertype method. * "yield" wasn't supported in "return" value expressions. * Using the "bint" type in memory views lead to unexpected results. It is now an error. * Assignments to global/closure variables could catch them in an illegal state while deallocating the old value. Other changes ------------- 0.19.1 (2013-05-11) =================== Features added -------------- * Completely empty C-API structs for extension type slots (protocols like number/mapping/sequence) are no longer generated into the C code. * Docstrings that directly follow a public/readonly attribute declaration in a cdef class will be used as docstring of the auto-generated property. This fixes ticket 206. * The automatic signature documentation tries to preserve more semantics of default arguments and argument types. Specifically, ``bint`` arguments now appear as type ``bool``. * A warning is emitted when negative literal indices are found inside of a code section that disables ``wraparound`` handling. This helps with fixing invalid code that might fail in the face of future compiler optimisations. * Constant folding for boolean expressions (and/or) was improved. * Added a build_dir option to cythonize() which allows one to place the generated .c files outside the source tree. Bugs fixed ---------- * ``isinstance(X, type)`` failed to get optimised into a call to ``PyType_Check()``, as done for other builtin types. * A spurious "from datetime cimport *" was removed from the "cpython" declaration package. This means that the "datetime" declarations (added in 0.19) are no longer available directly from the "cpython" namespace, but only from "cpython.datetime". This is the correct way of doing it because the declarations refer to a standard library module, not the core CPython C-API itself. * The C code for extension types is now generated in topological order instead of source code order to avoid C compiler errors about missing declarations for subtypes that are defined before their parent. * The ``memoryview`` type name no longer shows up in the module dict of modules that use memory views. This fixes trac ticket 775. * Regression in 0.19 that rejected valid C expressions from being used in C array size declarations. * In C++ mode, the C99-only keyword ``restrict`` could accidentally be seen by the GNU C++ compiler. It is now specially handled for both GCC and MSVC. * Testing large (> int) C integer values for their truth value could fail due to integer wrap-around. Other changes ------------- 0.19 (2013-04-19) ================= Features added -------------- * New directives ``c_string_type`` and ``c_string_encoding`` to more easily and automatically convert between C strings and the different Python string types. * The extension type flag ``Py_TPFLAGS_HAVE_VERSION_TAG`` is enabled by default on extension types and can be disabled using the ``type_version_tag`` compiler directive. * EXPERIMENTAL support for simple Cython code level line tracing. Enabled by the "linetrace" compiler directive. * Cython implemented functions make their argument and return type annotations available through the ``__annotations__`` attribute (PEP 3107). * Access to non-cdef module globals and Python object attributes is faster. * ``Py_UNICODE*`` coerces from and to Python unicode strings. This is helpful when talking to Windows APIs, which use compatible wchar_t arrays for strings. Note that the ``Py_UNICODE`` type is otherwise deprecated as of CPython 3.3. * ``isinstance(obj, basestring)`` is optimised. In Python 3 it only tests for instances of ``str`` (i.e. Py2 ``unicode``). * The ``basestring`` builtin is mapped to ``str`` (i.e. Py2 ``unicode``) when compiling the generated C code under Python 3. * Closures use freelists, which can speed up their creation quite substantially. This is also visible for short running generator expressions, for example. * A new class decorator ``@cython.freelist(N)`` creates a static freelist of N instances for an extension type, thus avoiding the costly allocation step if possible. This can speed up object instantiation by 20-30% in suitable scenarios. Note that freelists are currently only supported for base types, not for types that inherit from others. * Fast extension type instantiation using the ``Type.__new__(Type)`` idiom has gained support for passing arguments. It is also a bit faster for types defined inside of the module. * The Python2-only dict methods ``.iter*()`` and ``.view*()`` (requires Python 2.7) are automatically mapped to the equivalent keys/values/items methods in Python 3 for typed dictionaries. * Slicing unicode strings, lists and tuples is faster. * list.append() is faster on average. * ``raise Exception() from None`` suppresses the exception context in Py3.3. * Py3 compatible ``exec(tuple)`` syntax is supported in Py2 code. * Keyword arguments are supported for cdef functions. * External C++ classes can be declared nogil. Patch by John Stumpo. This fixes trac ticket 805. Bugs fixed ---------- * 2-value slicing of unknown objects passes the correct slice when the ``getitem`` protocol is used instead of the ``getslice`` protocol (especially in Python 3), i.e. ``None`` values for missing bounds instead of ``[0,maxsize]``. It is also a bit faster in some cases, e.g. for constant bounds. This fixes trac ticket 636. * Cascaded assignments of None values to extension type variables failed with a ``TypeError`` at runtime. * The ``__defaults__`` attribute was not writable for Cython implemented functions. * Default values of keyword-only arguments showed up in ``__defaults__`` instead of ``__kwdefaults__`` (which was not implemented). Both are available for Cython implemented functions now, as specified in Python 3.x. * ``yield`` works inside of ``with gil`` sections. It previously lead to a crash. This fixes trac ticket 803. * Static methods without explicitly named positional arguments (e.g. having only ``*args``) crashed when being called. This fixes trac ticket 804. * ``dir()`` without arguments previously returned an unsorted list, which now gets sorted as expected. * ``dict.items()``, ``dict.keys()`` and ``dict.values()`` no longer return lists in Python 3. * Exiting from an ``except-as`` clause now deletes the exception in Python 3 mode. * The declarations of ``frexp()`` and ``ldexp()`` in ``math.pxd`` were incorrect. Other changes ------------- 0.18 (2013-01-28) ================= Features added -------------- * Named Unicode escapes ("\N{...}") are supported. * Python functions/classes provide the special attribute "__qualname__" as defined by PEP 3155. * Added a directive ``overflowcheck`` which raises an OverflowException when arithmetic with C ints overflow. This has a modest performance penalty, but is much faster than using Python ints. * Calls to nested Python functions are resolved at compile time. * Type inference works across nested functions. * ``py_bytes_string.decode(...)`` is optimised. * C ``const`` declarations are supported in the language. Bugs fixed ---------- * Automatic C++ exception mapping didn't work in nogil functions (only in "with nogil" blocks). Other changes ------------- 0.17.4 (2013-01-03) =================== Bugs fixed ---------- * Garbage collection triggered during deallocation of container classes could lead to a double-deallocation. 0.17.3 (2012-12-14) =================== Features added -------------- Bugs fixed ---------- * During final interpreter cleanup (with types cleanup enabled at compile time), extension types that inherit from base types over more than one level that were cimported from other modules could lead to a crash. * Weak-reference support in extension types (with a ``cdef __weakref__`` attribute) generated incorrect deallocation code. * In CPython 3.3, converting a Unicode character to the Py_UNICODE type could fail to raise an overflow for non-BMP characters that do not fit into a wchar_t on the current platform. * Negative C integer constants lost their longness suffix in the generated C code. Other changes ------------- 0.17.2 (2012-11-20) =================== Features added -------------- * ``cythonize()`` gained a best effort compile mode that can be used to simply ignore .py files that fail to compile. Bugs fixed ---------- * Replacing an object reference with the value of one of its cdef attributes could generate incorrect C code that accessed the object after deleting its last reference. * C-to-Python type coercions during cascaded comparisons could generate invalid C code, specifically when using the 'in' operator. * "obj[1,]" passed a single integer into the item getter instead of a tuple. * Cyclic imports at module init time did not work in Py3. * The names of C++ destructors for template classes were built incorrectly. * In pure mode, type casts in Cython syntax and the C ampersand operator are now rejected. Use the pure mode replacements instead. * In pure mode, C type names and the sizeof() function are no longer recognised as such and can be used as normal Python names. * The extended C level support for the CPython array type was declared too late to be used by user defined classes. * C++ class nesting was broken. * Better checking for required nullary constructors for stack-allocated C++ instances. * Remove module docstring in no-docstring mode. * Fix specialization for varargs function signatures. * Fix several compiler crashes. Other changes ------------- * An experimental distutils script for compiling the CPython standard library was added as Tools/cystdlib.py. 0.17.1 (2012-09-26) =================== Features added -------------- Bugs fixed ---------- * A reference leak was fixed in the new dict iteration code when the loop target was not a plain variable but an unpacked tuple. * Memory views did not handle the special case of a NULL buffer strides value, as allowed by PEP3118. Other changes ------------- 0.17 (2012-09-01) ================= Features added -------------- * Alpha quality support for compiling and running Cython generated extension modules in PyPy (through cpyext). Note that this requires at least PyPy 1.9 and in many cases also adaptations in user code, especially to avoid borrowed references when no owned reference is being held directly in C space (a reference in a Python list or dict is not enough, for example). See the documentation on porting Cython code to PyPy. * "yield from" is supported (PEP 380) and a couple of minor problems with generators were fixed. * C++ STL container classes automatically coerce from and to the equivalent Python container types on typed assignments and casts. Note that the data in the containers is copied during this conversion. * C++ iterators can now be iterated over using "for x in cpp_container" whenever cpp_container has begin() and end() methods returning objects satisfying the iterator pattern (that is, it can be incremented, dereferenced, and compared (for non-equality)). * cdef classes can now have C++ class members (provided a zero-argument constructor exists) * A new cpython.array standard cimport file allows to efficiently talk to the stdlib array.array data type in Python 2. Since CPython does not export an official C-API for this module, it receives special casing by the compiler in order to avoid setup overhead on user side. In Python 3, both buffers and memory views on the array type already worked out of the box with earlier versions of Cython due to the native support for the buffer interface in the Py3 array module. * Fast dict iteration is now enabled optimistically also for untyped variables when the common iteration methods are used. * The unicode string processing code was adapted for the upcoming CPython 3.3 (PEP 393, new Unicode buffer layout). * Buffer arguments and memory view arguments in Python functions can be declared "not None" to raise a TypeError on None input. * c(p)def functions in pure mode can specify their return type with "@cython.returns()". * Automatic dispatch for fused functions with memoryview arguments * Support newaxis indexing for memoryviews * Support decorators for fused functions Bugs fixed ---------- * Old-style Py2 imports did not work reliably in Python 3.x and were broken in Python 3.3. Regardless of this fix, it's generally best to be explicit about relative and global imports in Cython code because old-style imports have a higher overhead. To this end, "from __future__ import absolute_import" is supported in Python/Cython 2.x code now (previous versions of Cython already used it when compiling Python 3 code). * Stricter constraints on the "inline" and "final" modifiers. If your code does not compile due to this change, chances are these modifiers were previously being ignored by the compiler and can be removed without any performance regression. * Exceptions are always instantiated while raising them (as in Python), instead of risking to instantiate them in potentially unsafe situations when they need to be handled or otherwise processed. * locals() properly ignores names that do not have Python compatible types (including automatically inferred types). * Some garbage collection issues of memory views were fixed. * numpy.pxd compiles in Python 3 mode. * Several C compiler warnings were fixed. * Several bugs related to memoryviews and fused types were fixed. * Several bug-fixes and improvements related to cythonize(), including ccache-style caching. Other changes ------------- * libc.string provides a convenience declaration for const uchar in addition to const char. * User declared char* types are now recognised as such and auto-coerce to and from Python bytes strings. * callable() and next() compile to more efficient C code. * list.append() is faster on average. * Modules generated by @cython.inline() are written into the directory pointed to by the environment variable CYTHON_CACHE_DIR if set. 0.16 (2012-04-21) ================= Features added -------------- * Enhancements to Cython's function type (support for weak references, default arguments, code objects, dynamic attributes, classmethods, staticmethods, and more) * Fused Types - Template-like support for functions and methods CEP 522 (docs) * Typed views on memory - Support for efficient direct and indirect buffers (indexing, slicing, transposing, ...) CEP 517 (docs) * super() without arguments * Final cdef methods (which translate into direct calls on known instances) Bugs fixed ---------- * fix alignment handling for record types in buffer support Other changes ------------- * support default arguments for closures * search sys.path for pxd files * support C++ template casting * faster traceback building and faster generator termination * support inplace operators on indexed buffers * allow nested prange sections 0.15.1 (2011-09-19) =================== Features added -------------- Bugs fixed ---------- Other changes ------------- 0.15 (2011-08-05) ================= Features added -------------- * Generators (yield) - Cython has full support for generators, generator expressions and PEP 342 coroutines. * The nonlocal keyword is supported. * Re-acquiring the gil: with gil - works as expected within a nogil context. * OpenMP support: prange. * Control flow analysis prunes dead code and emits warnings and errors about uninitialised variables. * Debugger command cy set to assign values of expressions to Cython variables and cy exec counterpart $cy_eval(). * Exception chaining PEP 3134. * Relative imports PEP 328. * Improved pure syntax including cython.cclass, cython.cfunc, and cython.ccall. * The with statement has its own dedicated and faster C implementation. * Support for del. * Boundschecking directives implemented for builtin Python sequence types. * Several updates and additions to the shipped standard library .pxd files. * Forward declaration of types is no longer required for circular references. Bugs fixed ---------- Other changes ------------- * Uninitialized variables are no longer initialized to None and accessing them has the same semantics as standard Python. * globals() now returns a read-only dict of the Cython module's globals, rather than the globals of the first non-Cython module in the stack * Many C++ exceptions are now special cased to give closer Python counterparts. This means that except+ functions that formerly raised generic RuntimeErrors may raise something else such as ArithmeticError. * The inlined generator expressions (introduced in Cython 0.13) were disabled in favour of full generator expression support. This breaks code that previously used them inside of cdef functions (usage in def functions continues to work) and induces a performance regression for cases that continue to work but that were previously inlined. We hope to reinstate this feature in the near future. 0.14.1 (2011-02-04) =================== Features added -------------- * The gdb debugging support was extended to include all major Cython features, including closures. * raise MemoryError() is now safe to use as Cython replaces it with the correct C-API call. Bugs fixed ---------- Other changes ------------- * Decorators on special methods of cdef classes now raise a compile time error rather than being ignored. * In Python 3 language level mode (-3 option), the 'str' type is now mapped to 'unicode', so that cdef str s declares a Unicode string even when running in Python 2. 0.14 (2010-12-14) ================= Features added -------------- * Python classes can now be nested and receive a proper closure at definition time. * Redefinition is supported for Python functions, even within the same scope. * Lambda expressions are supported in class bodies and at the module level. * Metaclasses are supported for Python classes, both in Python 2 and Python 3 syntax. The Python 3 syntax (using a keyword argument in the type declaration) is preferred and optimised at compile time. * "final" extension classes prevent inheritance in Python space. This feature is available through the new "cython.final" decorator. In the future, these classes may receive further optimisations. * "internal" extension classes do not show up in the module dictionary. This feature is available through the new "cython.internal" decorator. * Extension type inheritance from builtin types, such as "cdef class MyUnicode(unicode)", now works without further external type redeclarations (which are also strongly discouraged now and continue to issue a warning). * GDB support. http://docs.cython.org/src/userguide/debugging.html * A new build system with support for inline distutils directives, correct dependency tracking, and parallel compilation. http://wiki.cython.org/enhancements/distutils_preprocessing * Support for dynamic compilation at runtime via the new cython.inline function and cython.compile decorator. http://wiki.cython.org/enhancements/inline * "nogil" blocks are supported when compiling pure Python code by writing "with cython.nogil". * Iterating over arbitrary pointer types is now supported, as is an optimized version of the in operator, e.g. x in ptr[a:b]. Bugs fixed ---------- * In parallel assignments, the right side was evaluated in reverse order in 0.13. This could result in errors if it had side effects (e.g. function calls). * In some cases, methods of builtin types would raise a SystemError instead of an AttributeError when called on None. Other changes ------------- * Constant tuples are now cached over the lifetime of an extension module, just like CPython does. Constant argument tuples of Python function calls are also cached. * Closures have tightened to include exactly the names used in the inner functions and classes. Previously, they held the complete locals of the defining function. * The builtin "next()" function in Python 2.6 and later is now implemented internally and therefore available in all Python versions. This makes it the preferred and portable way of manually advancing an iterator. * In addition to the previously supported inlined generator expressions in 0.13, "sorted(genexpr)" can now be used as well. Typing issues were fixed in "sum(genexpr)" that could lead to invalid C code being generated. Other known issues with inlined generator expressions were also fixed that make upgrading to 0.14 a strong recommendation for code that uses them. Note that general generators and generator expressions continue to be not supported. * Inplace arithmetic operators now respect the cdivision directive and are supported for complex types. * Typing a variable as type "complex" previously gave it the Python object type. It now uses the appropriate C/C++ double complex type. A side-effect is that assignments and typed function parameters now accept anything that Python can coerce to a complex, including integers and floats, and not only complex instances. * Large integer literals pass through the compiler in a safer way. To prevent truncation in C code, non 32-bit literals are turned into Python objects if not used in a C context. This context can either be given by a clear C literal suffix such as "UL" or "LL" (or "L" in Python 3 code), or it can be an assignment to a typed variable or a typed function argument, in which case it is up to the user to take care of a sufficiently large value space of the target. * Python functions are declared in the order they appear in the file, rather than all being created at module creation time. This is consistent with Python and needed to support, for example, conditional or repeated declarations of functions. In the face of circular imports this may cause code to break, so a new --disable-function-redefinition flag was added to revert to the old behavior. This flag will be removed in a future release, so should only be used as a stopgap until old code can be fixed. 0.13 (2010-08-25) ================= Features added -------------- * Closures are fully supported for Python functions. Cython supports inner functions and lambda expressions. Generators and generator expressions are not supported in this release. * Proper C++ support. Cython knows about C++ classes, templates and overloaded function signatures, so that Cython code can interact with them in a straight forward way. * Type inference is enabled by default for safe C types (e.g. double, bint, C++ classes) and known extension types. This reduces the need for explicit type declarations and can improve the performance of untyped code in some cases. There is also a verbose compile mode for testing the impact on user code. * Cython's for-in-loop can iterate over C arrays and sliced pointers. The type of the loop variable will be inferred automatically in this case. * The Py_UNICODE integer type for Unicode code points is fully supported, including for-loops and 'in' tests on unicode strings. It coerces from and to single character unicode strings. Note that untyped for-loop variables will automatically be inferred as Py_UNICODE when iterating over a unicode string. In most cases, this will be much more efficient than yielding sliced string objects, but can also have a negative performance impact when the variable is used in a Python context multiple times, so that it needs to coerce to a unicode string object more than once. If this happens, typing the loop variable as unicode or object will help. * The built-in functions any(), all(), sum(), list(), set() and dict() are inlined as plain for loops when called on generator expressions. Note that generator expressions are not generally supported apart from this feature. Also, tuple(genexpr) is not currently supported - use tuple([listcomp]) instead. * More shipped standard library declarations. The python_* and stdlib/stdio .pxd files have been deprecated in favor of clib.* and cpython[.*] and may get removed in a future release. * Pure Python mode no longer disallows non-Python keywords like 'cdef', 'include' or 'cimport'. It also no longer recognises syntax extensions like the for-from loop. * Parsing has improved for Python 3 syntax in Python code, although not all features are correctly supported. The missing Python 3 features are being worked on for the next release. * from __future__ import print_function is supported in Python 2.6 and later. Note that there is currently no emulation for earlier Python versions, so code that uses print() with this future import will require at least Python 2.6. * New compiler directive language_level (valid values: 2 or 3) with corresponding command line options -2 and -3 requests source code compatibility with Python 2.x or Python 3.x respectively. Language level 3 currently enforces unicode literals for unprefixed string literals, enables the print function (requires Python 2.6 or later) and keeps loop variables in list comprehensions from leaking. * Loop variables in set/dict comprehensions no longer leak into the surrounding scope (following Python 2.7). List comprehensions are unchanged in language level 2. * print >> stream Bugs fixed ---------- Other changes ------------- * The availability of type inference by default means that Cython will also infer the type of pointers on assignments. Previously, code like this:: cdef char* s = ... untyped_variable = s would convert the char* to a Python bytes string and assign that. This is no longer the case and no coercion will happen in the example above. The correct way of doing this is through an explicit cast or by typing the target variable, i.e. :: cdef char* s = ... untyped_variable1 = s untyped_variable2 = s cdef object py_object = s cdef bytes bytes_string = s * bool is no longer a valid type name by default. The problem is that it's not clear whether bool should refer to the Python type or the C++ type, and expecting one and finding the other has already led to several hard-to-find bugs. Both types are available for importing: you can use from cpython cimport bool for the Python bool type, and from libcpp cimport bool for the C++ type. bool is still a valid object by default, so one can still write bool(x). * ``__getsegcount__`` is now correctly typed to take a ``Py_size_t*`` rather than an ``int*``. 0.12.1 (2010-02-02) =================== Features added -------------- * Type inference improvements. * There have been several bug fixes and improvements to the type inferencer. * Notably, there is now a "safe" mode enabled by setting the infer_types directive to None. (The None here refers to the "default" mode, which will be the default in 0.13.) This safe mode limits inference to Python object types and C doubles, which should speed up execution without affecting any semantics such as integer overflow behavior like infer_types=True might. There is also an infer_types.verbose option which allows one to see what types are inferred. * The boundscheck directive works for lists and tuples as well as buffers. * len(s) and s.decode("encoding") are efficiently supported for char* s. * Cython's INLINE macro has been renamed to CYTHON_INLINE to reduce conflict and has better support for the MSVC compiler on Windows. It is no longer clobbered if externally defined. * Revision history is now omitted from the source package, resulting in a 85% size reduction. Running make repo will download the history and turn the directory into a complete Mercurial working repository. * Cython modules don't need to be recompiled when the size of an external type grows. (A warning, rather than an error, is produced.) This should be helpful for binary distributions relying on NumPy. Bugs fixed ---------- * Several other bugs and minor improvements have been made. This release should be fully backwards compatible with 0.12. Other changes ------------- 0.12 (2009-11-23) ================= Features added -------------- * Type inference with the infer_types directive * Seamless C++ complex support * Fast extension type instantiation using the normal Python meme obj = MyType.__new__(MyType) * Improved support for Py3.1 * Cython now runs under Python 3.x using the 2to3 tool * unittest support for doctests in Cython modules * Optimised handling of C strings (char*): for c in cstring[2:50] and cstring.decode() * Looping over c pointers: for i in intptr[:50]. * pyximport improvements * cython_freeze improvements Bugs fixed ---------- * Many bug fixes Other changes ------------- * Many other optimisation, e.g. enumerate() loops, parallel swap assignments (a,b = b,a), and unicode.encode() * More complete numpy.pxd 0.11.2 (2009-05-20) =================== Features added -------------- * There's now native complex floating point support! C99 complex will be used if complex.h is included, otherwise explicit complex arithmetic working on all C compilers is used. [Robert Bradshaw] :: cdef double complex a = 1 + 0.3j cdef np.ndarray[np.complex128_t, ndim=2] arr = \ np.zeros(10, np.complex128) * Cython can now generate a main()-method for embedding of the Python interpreter into an executable (see #289) [Robert Bradshaw] * @wraparound directive (another way to disable arr[idx] for negative idx) [Dag Sverre Seljebotn] * Correct support for NumPy record dtypes with different alignments, and "cdef packed struct" support [Dag Sverre Seljebotn] * @callspec directive, allowing custom calling convention macros [Lisandro Dalcin] Bugs fixed ---------- Other changes ------------- * Bug fixes and smaller improvements. For the full list, see [1]. cython-0.20.1+git90-g0e6e38e/COPYING.txt000066400000000000000000000006641231323242300171240ustar00rootroot00000000000000The original Pyrex code as of 2006-04 is licensed under the following license: "Copyright stuff: Pyrex is free of restrictions. You may use, redistribute, modify and distribute modified versions." ------------------ Cython, which derives from Pyrex, is licensed under the Apache 2.0 Software License. More precisely, all modifications and new code made to go from Pyrex to Cython are so licensed. See LICENSE.txt for more details. cython-0.20.1+git90-g0e6e38e/Cython/000077500000000000000000000000001231323242300165115ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Cython/Build/000077500000000000000000000000001231323242300175505ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Cython/Build/BuildExecutable.py000066400000000000000000000102761231323242300231710ustar00rootroot00000000000000""" Compile a Python script into an executable that embeds CPython and run it. Requires CPython to be built as a shared library ('libpythonX.Y'). Basic usage: python cythonrun somefile.py [ARGS] """ DEBUG = True import sys import os from distutils import sysconfig def get_config_var(name, default=''): return sysconfig.get_config_var(name) or default INCDIR = sysconfig.get_python_inc() LIBDIR1 = get_config_var('LIBDIR') LIBDIR2 = get_config_var('LIBPL') PYLIB = get_config_var('LIBRARY') PYLIB_DYN = get_config_var('LDLIBRARY') if PYLIB_DYN == PYLIB: # no shared library PYLIB_DYN = '' else: PYLIB_DYN = os.path.splitext(PYLIB_DYN[3:])[0] # 'lib(XYZ).so' -> XYZ CC = get_config_var('CC', os.environ.get('CC', '')) CFLAGS = get_config_var('CFLAGS') + ' ' + os.environ.get('CFLAGS', '') LINKCC = get_config_var('LINKCC', os.environ.get('LINKCC', CC)) LINKFORSHARED = get_config_var('LINKFORSHARED') LIBS = get_config_var('LIBS') SYSLIBS = get_config_var('SYSLIBS') EXE_EXT = sysconfig.get_config_var('EXE') def _debug(msg, *args): if DEBUG: if args: msg = msg % args sys.stderr.write(msg + '\n') def dump_config(): _debug('INCDIR: %s', INCDIR) _debug('LIBDIR1: %s', LIBDIR1) _debug('LIBDIR2: %s', LIBDIR2) _debug('PYLIB: %s', PYLIB) _debug('PYLIB_DYN: %s', PYLIB_DYN) _debug('CC: %s', CC) _debug('CFLAGS: %s', CFLAGS) _debug('LINKCC: %s', LINKCC) _debug('LINKFORSHARED: %s', LINKFORSHARED) _debug('LIBS: %s', LIBS) _debug('SYSLIBS: %s', SYSLIBS) _debug('EXE_EXT: %s', EXE_EXT) def runcmd(cmd, shell=True): if shell: cmd = ' '.join(cmd) _debug(cmd) else: _debug(' '.join(cmd)) try: import subprocess except ImportError: # Python 2.3 ... returncode = os.system(cmd) else: returncode = subprocess.call(cmd, shell=shell) if returncode: sys.exit(returncode) def clink(basename): runcmd([LINKCC, '-o', basename + EXE_EXT, basename+'.o', '-L'+LIBDIR1, '-L'+LIBDIR2] + [PYLIB_DYN and ('-l'+PYLIB_DYN) or os.path.join(LIBDIR1, PYLIB)] + LIBS.split() + SYSLIBS.split() + LINKFORSHARED.split()) def ccompile(basename): runcmd([CC, '-c', '-o', basename+'.o', basename+'.c', '-I' + INCDIR] + CFLAGS.split()) def cycompile(input_file, options=()): from Cython.Compiler import Version, CmdLine, Main options, sources = CmdLine.parse_command_line(list(options or ()) + ['--embed', input_file]) _debug('Using Cython %s to compile %s', Version.version, input_file) result = Main.compile(sources, options) if result.num_errors > 0: sys.exit(1) def exec_file(program_name, args=()): runcmd([os.path.abspath(program_name)] + list(args), shell=False) def build(input_file, compiler_args=(), force=False): """ Build an executable program from a Cython module. Returns the name of the executable file. """ basename = os.path.splitext(input_file)[0] exe_file = basename + EXE_EXT if not force and os.path.abspath(exe_file) == os.path.abspath(input_file): raise ValueError("Input and output file names are the same, refusing to overwrite") if (not force and os.path.exists(exe_file) and os.path.exists(input_file) and os.path.getmtime(input_file) <= os.path.getmtime(exe_file)): _debug("File is up to date, not regenerating %s", exe_file) return exe_file cycompile(input_file, compiler_args) ccompile(basename) clink(basename) return exe_file def build_and_run(args): """ Build an executable program from a Cython module and runs it. Arguments after the module name will be passed verbatimely to the program. """ cy_args = [] last_arg = None for i, arg in enumerate(args): if arg.startswith('-'): cy_args.append(arg) elif last_arg in ('-X', '--directive'): cy_args.append(arg) else: input_file = arg args = args[i+1:] break last_arg = arg else: raise ValueError('no input file provided') program_name = build(input_file, cy_args) exec_file(program_name, args) if __name__ == '__main__': build_and_run(sys.argv[1:]) cython-0.20.1+git90-g0e6e38e/Cython/Build/Cythonize.py000066400000000000000000000153201231323242300220770ustar00rootroot00000000000000#!/usr/bin/env python import os import shutil import tempfile from distutils.core import setup from Cython.Build.Dependencies import cythonize, extended_iglob from Cython.Utils import is_package_dir from Cython.Compiler import Options try: import multiprocessing parallel_compiles = int(multiprocessing.cpu_count() * 1.5) except ImportError: multiprocessing = None parallel_compiles = 0 class _FakePool(object): def map_async(self, func, args): from itertools import imap for _ in imap(func, args): pass def close(self): pass def terminate(self): pass def join(self): pass def parse_directives(option, name, value, parser): dest = option.dest old_directives = dict(getattr(parser.values, dest, Options.directive_defaults)) directives = Options.parse_directive_list( value, relaxed_bool=True, current_settings=old_directives) setattr(parser.values, dest, directives) def parse_options(option, name, value, parser): dest = option.dest options = dict(getattr(parser.values, dest, {})) for opt in value.split(','): if '=' in opt: n, v = opt.split('=', 1) v = v.lower() not in ('false', 'f', '0', 'no') else: n, v = opt, True options[n] = v setattr(parser.values, dest, options) def find_package_base(path): base_dir, package_path = os.path.split(path) while os.path.isfile(os.path.join(base_dir, '__init__.py')): base_dir, parent = os.path.split(base_dir) package_path = '%s/%s' % (parent, package_path) return base_dir, package_path def cython_compile(path_pattern, options): pool = None paths = map(os.path.abspath, extended_iglob(path_pattern)) try: for path in paths: if options.build_inplace: base_dir = path while not os.path.isdir(base_dir) or is_package_dir(base_dir): base_dir = os.path.dirname(base_dir) else: base_dir = None if os.path.isdir(path): # recursively compiling a package paths = [os.path.join(path, '**', '*.%s' % ext) for ext in ('py', 'pyx')] else: # assume it's a file(-like thing) paths = [path] ext_modules = cythonize( paths, nthreads=options.parallel, exclude_failures=options.keep_going, exclude=options.excludes, compiler_directives=options.directives, force=options.force, quiet=options.quiet, **options.options) if ext_modules and options.build: if len(ext_modules) > 1 and options.parallel > 1: if pool is None: try: pool = multiprocessing.Pool(options.parallel) except OSError: pool = _FakePool() pool.map_async(run_distutils, [ (base_dir, [ext]) for ext in ext_modules]) else: run_distutils((base_dir, ext_modules)) except: if pool is not None: pool.terminate() raise else: if pool is not None: pool.close() pool.join() def run_distutils(args): base_dir, ext_modules = args script_args = ['build_ext', '-i'] cwd = os.getcwd() temp_dir = None try: if base_dir: os.chdir(base_dir) temp_dir = tempfile.mkdtemp(dir=base_dir) script_args.extend(['--build-temp', temp_dir]) setup( script_name='setup.py', script_args=script_args, ext_modules=ext_modules, ) finally: if base_dir: os.chdir(cwd) if temp_dir and os.path.isdir(temp_dir): shutil.rmtree(temp_dir) def parse_args(args): from optparse import OptionParser parser = OptionParser(usage='%prog [options] [sources and packages]+') parser.add_option('-X', '--directive', metavar='NAME=VALUE,...', dest='directives', type=str, action='callback', callback=parse_directives, default={}, help='set a compiler directive') parser.add_option('-s', '--option', metavar='NAME=VALUE', dest='options', type=str, action='callback', callback=parse_options, default={}, help='set a cythonize option') parser.add_option('-3', dest='python3_mode', action='store_true', help='use Python 3 syntax mode by default') parser.add_option('-x', '--exclude', metavar='PATTERN', dest='excludes', action='append', default=[], help='exclude certain file patterns from the compilation') parser.add_option('-b', '--build', dest='build', action='store_true', help='build extension modules using distutils') parser.add_option('-i', '--inplace', dest='build_inplace', action='store_true', help='build extension modules in place using distutils (implies -b)') parser.add_option('-j', '--parallel', dest='parallel', metavar='N', type=int, default=parallel_compiles, help=('run builds in N parallel jobs (default: %d)' % parallel_compiles or 1)) parser.add_option('-f', '--force', dest='force', action='store_true', help='force recompilation') parser.add_option('-q', '--quiet', dest='quiet', action='store_true', help='be less verbose during compilation') parser.add_option('--lenient', dest='lenient', action='store_true', help='increase Python compatibility by ignoring some compile time errors') parser.add_option('-k', '--keep-going', dest='keep_going', action='store_true', help='compile as much as possible, ignore compilation failures') options, args = parser.parse_args(args) if not args: parser.error("no source files provided") if options.build_inplace: options.build = True if multiprocessing is None: options.parallel = 0 if options.python3_mode: options.options['language_level'] = 3 return options, args def main(args=None): options, paths = parse_args(args) if options.lenient: # increase Python compatibility by ignoring compile time errors Options.error_on_unknown_names = False Options.error_on_uninitialized = False for path in paths: cython_compile(path, options) if __name__ == '__main__': main() cython-0.20.1+git90-g0e6e38e/Cython/Build/Dependencies.py000066400000000000000000001031411231323242300225100ustar00rootroot00000000000000import cython from Cython import __version__ import re, os, sys, time try: from glob import iglob except ImportError: # Py2.4 from glob import glob as iglob try: import gzip gzip_open = gzip.open gzip_ext = '.gz' except ImportError: gzip_open = open gzip_ext = '' import shutil import subprocess try: import hashlib except ImportError: import md5 as hashlib try: from io import open as io_open except ImportError: from codecs import open as io_open try: from os.path import relpath as _relpath except ImportError: # Py<2.6 def _relpath(path, start=os.path.curdir): if not path: raise ValueError("no path specified") start_list = os.path.abspath(start).split(os.path.sep) path_list = os.path.abspath(path).split(os.path.sep) i = len(os.path.commonprefix([start_list, path_list])) rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] if not rel_list: return os.path.curdir return os.path.join(*rel_list) from distutils.extension import Extension from Cython import Utils from Cython.Utils import cached_function, cached_method, path_exists, find_root_package_dir from Cython.Compiler.Main import Context, CompilationOptions, default_options join_path = cached_function(os.path.join) if sys.version_info[0] < 3: # stupid Py2 distutils enforces str type in list of sources _fs_encoding = sys.getfilesystemencoding() if _fs_encoding is None: _fs_encoding = sys.getdefaultencoding() def encode_filename_in_py2(filename): if isinstance(filename, unicode): return filename.encode(_fs_encoding) return filename else: def encode_filename_in_py2(filename): return filename basestring = str def extended_iglob(pattern): if '**/' in pattern: seen = set() first, rest = pattern.split('**/', 1) if first: first = iglob(first+'/') else: first = [''] for root in first: for path in extended_iglob(join_path(root, rest)): if path not in seen: seen.add(path) yield path for path in extended_iglob(join_path(root, '*', '**/' + rest)): if path not in seen: seen.add(path) yield path else: for path in iglob(pattern): yield path @cached_function def file_hash(filename): path = os.path.normpath(filename.encode("UTF-8")) m = hashlib.md5(str(len(path)) + ":") m.update(path) f = open(filename, 'rb') try: data = f.read(65000) while data: m.update(data) data = f.read(65000) finally: f.close() return m.hexdigest() def parse_list(s): """ >>> parse_list("a b c") ['a', 'b', 'c'] >>> parse_list("[a, b, c]") ['a', 'b', 'c'] >>> parse_list('a " " b') ['a', ' ', 'b'] >>> parse_list('[a, ",a", "a,", ",", ]') ['a', ',a', 'a,', ','] """ if s[0] == '[' and s[-1] == ']': s = s[1:-1] delimiter = ',' else: delimiter = ' ' s, literals = strip_string_literals(s) def unquote(literal): literal = literal.strip() if literal[0] in "'\"": return literals[literal[1:-1]] else: return literal return [unquote(item) for item in s.split(delimiter) if item.strip()] transitive_str = object() transitive_list = object() distutils_settings = { 'name': str, 'sources': list, 'define_macros': list, 'undef_macros': list, 'libraries': transitive_list, 'library_dirs': transitive_list, 'runtime_library_dirs': transitive_list, 'include_dirs': transitive_list, 'extra_objects': list, 'extra_compile_args': transitive_list, 'extra_link_args': transitive_list, 'export_symbols': list, 'depends': transitive_list, 'language': transitive_str, } @cython.locals(start=long, end=long) def line_iter(source): if isinstance(source, basestring): start = 0 while True: end = source.find('\n', start) if end == -1: yield source[start:] return yield source[start:end] start = end+1 else: for line in source: yield line class DistutilsInfo(object): def __init__(self, source=None, exn=None): self.values = {} if source is not None: for line in line_iter(source): line = line.strip() if line != '' and line[0] != '#': break line = line[1:].strip() if line[:10] == 'distutils:': line = line[10:] ix = line.index('=') key = str(line[:ix].strip()) value = line[ix+1:].strip() type = distutils_settings[key] if type in (list, transitive_list): value = parse_list(value) if key == 'define_macros': value = [tuple(macro.split('=')) for macro in value] self.values[key] = value elif exn is not None: for key in distutils_settings: if key in ('name', 'sources'): continue value = getattr(exn, key, None) if value: self.values[key] = value def merge(self, other): if other is None: return self for key, value in other.values.items(): type = distutils_settings[key] if type is transitive_str and key not in self.values: self.values[key] = value elif type is transitive_list: if key in self.values: all = self.values[key] for v in value: if v not in all: all.append(v) else: self.values[key] = value return self def subs(self, aliases): if aliases is None: return self resolved = DistutilsInfo() for key, value in self.values.items(): type = distutils_settings[key] if type in [list, transitive_list]: new_value_list = [] for v in value: if v in aliases: v = aliases[v] if isinstance(v, list): new_value_list += v else: new_value_list.append(v) value = new_value_list else: if value in aliases: value = aliases[value] resolved.values[key] = value return resolved def apply(self, extension): for key, value in self.values.items(): type = distutils_settings[key] if type in [list, transitive_list]: getattr(extension, key).extend(value) else: setattr(extension, key, value) @cython.locals(start=long, q=long, single_q=long, double_q=long, hash_mark=long, end=long, k=long, counter=long, quote_len=long) def strip_string_literals(code, prefix='__Pyx_L'): """ Normalizes every string literal to be of the form '__Pyx_Lxxx', returning the normalized code and a mapping of labels to string literals. """ new_code = [] literals = {} counter = 0 start = q = 0 in_quote = False hash_mark = single_q = double_q = -1 code_len = len(code) while True: if hash_mark < q: hash_mark = code.find('#', q) if single_q < q: single_q = code.find("'", q) if double_q < q: double_q = code.find('"', q) q = min(single_q, double_q) if q == -1: q = max(single_q, double_q) # We're done. if q == -1 and hash_mark == -1: new_code.append(code[start:]) break # Try to close the quote. elif in_quote: if code[q-1] == u'\\': k = 2 while q >= k and code[q-k] == u'\\': k += 1 if k % 2 == 0: q += 1 continue if code[q] == quote_type and (quote_len == 1 or (code_len > q + 2 and quote_type == code[q+1] == code[q+2])): counter += 1 label = "%s%s_" % (prefix, counter) literals[label] = code[start+quote_len:q] full_quote = code[q:q+quote_len] new_code.append(full_quote) new_code.append(label) new_code.append(full_quote) q += quote_len in_quote = False start = q else: q += 1 # Process comment. elif -1 != hash_mark and (hash_mark < q or q == -1): new_code.append(code[start:hash_mark+1]) end = code.find('\n', hash_mark) counter += 1 label = "%s%s_" % (prefix, counter) if end == -1: end_or_none = None else: end_or_none = end literals[label] = code[hash_mark+1:end_or_none] new_code.append(label) if end == -1: break start = q = end # Open the quote. else: if code_len >= q+3 and (code[q] == code[q+1] == code[q+2]): quote_len = 3 else: quote_len = 1 in_quote = True quote_type = code[q] new_code.append(code[start:q]) start = q q += quote_len return "".join(new_code), literals dependancy_regex = re.compile(r"(?:^from +([0-9a-zA-Z_.]+) +cimport)|" r"(?:^cimport +([0-9a-zA-Z_.]+)\b)|" r"(?:^cdef +extern +from +['\"]([^'\"]+)['\"])|" r"(?:^include +['\"]([^'\"]+)['\"])", re.M) def normalize_existing(base_path, rel_paths): return normalize_existing0(os.path.dirname(base_path), tuple(set(rel_paths))) @cached_function def normalize_existing0(base_dir, rel_paths): normalized = [] for rel in rel_paths: path = join_path(base_dir, rel) if path_exists(path): normalized.append(os.path.normpath(path)) else: normalized.append(rel) return normalized def resolve_depends(depends, include_dirs): include_dirs = tuple(include_dirs) resolved = [] for depend in depends: path = resolve_depend(depend, include_dirs) if path is not None: resolved.append(path) return resolved @cached_function def resolve_depend(depend, include_dirs): if depend[0] == '<' and depend[-1] == '>': return None for dir in include_dirs: path = join_path(dir, depend) if path_exists(path): return os.path.normpath(path) return None @cached_function def package(filename): dir = os.path.dirname(os.path.abspath(str(filename))) if dir != filename and path_exists(join_path(dir, '__init__.py')): return package(dir) + (os.path.basename(dir),) else: return () @cached_function def fully_qualified_name(filename): module = os.path.splitext(os.path.basename(filename))[0] return '.'.join(package(filename) + (module,)) @cached_function def parse_dependencies(source_filename): # Actual parsing is way to slow, so we use regular expressions. # The only catch is that we must strip comments and string # literals ahead of time. fh = Utils.open_source_file(source_filename, "rU", error_handling='ignore') try: source = fh.read() finally: fh.close() distutils_info = DistutilsInfo(source) source, literals = strip_string_literals(source) source = source.replace('\\\n', ' ').replace('\t', ' ') # TODO: pure mode cimports = [] includes = [] externs = [] for m in dependancy_regex.finditer(source): cimport_from, cimport, extern, include = m.groups() if cimport_from: cimports.append(cimport_from) elif cimport: cimports.append(cimport) elif extern: externs.append(literals[extern]) else: includes.append(literals[include]) return cimports, includes, externs, distutils_info class DependencyTree(object): def __init__(self, context, quiet=False): self.context = context self.quiet = quiet self._transitive_cache = {} def parse_dependencies(self, source_filename): return parse_dependencies(source_filename) @cached_method def included_files(self, filename): # This is messy because included files are textually included, resolving # cimports (but not includes) relative to the including file. all = set() for include in self.parse_dependencies(filename)[1]: include_path = join_path(os.path.dirname(filename), include) if not path_exists(include_path): include_path = self.context.find_include_file(include, None) if include_path: if '.' + os.path.sep in include_path: include_path = os.path.normpath(include_path) all.add(include_path) all.update(self.included_files(include_path)) elif not self.quiet: print("Unable to locate '%s' referenced from '%s'" % (filename, include)) return all @cached_method def cimports_and_externs(self, filename): # This is really ugly. Nested cimports are resolved with respect to the # includer, but includes are resolved with respect to the includee. cimports, includes, externs = self.parse_dependencies(filename)[:3] cimports = set(cimports) externs = set(externs) for include in self.included_files(filename): included_cimports, included_externs = self.cimports_and_externs(include) cimports.update(included_cimports) externs.update(included_externs) return tuple(cimports), normalize_existing(filename, externs) def cimports(self, filename): return self.cimports_and_externs(filename)[0] def package(self, filename): return package(filename) def fully_qualified_name(self, filename): return fully_qualified_name(filename) @cached_method def find_pxd(self, module, filename=None): is_relative = module[0] == '.' if is_relative and not filename: raise NotImplementedError("New relative imports.") if filename is not None: module_path = module.split('.') if is_relative: module_path.pop(0) # just explicitly relative package_path = list(self.package(filename)) while module_path and not module_path[0]: try: package_path.pop() except IndexError: return None # FIXME: error? module_path.pop(0) relative = '.'.join(package_path + module_path) pxd = self.context.find_pxd_file(relative, None) if pxd: return pxd if is_relative: return None # FIXME: error? return self.context.find_pxd_file(module, None) @cached_method def cimported_files(self, filename): if filename[-4:] == '.pyx' and path_exists(filename[:-4] + '.pxd'): pxd_list = [filename[:-4] + '.pxd'] else: pxd_list = [] for module in self.cimports(filename): if module[:7] == 'cython.' or module == 'cython': continue pxd_file = self.find_pxd(module, filename) if pxd_file is not None: pxd_list.append(pxd_file) elif not self.quiet: print("missing cimport in module '%s': %s" % (module, filename)) return tuple(pxd_list) @cached_method def immediate_dependencies(self, filename): all = set([filename]) all.update(self.cimported_files(filename)) all.update(self.included_files(filename)) return all def all_dependencies(self, filename): return self.transitive_merge(filename, self.immediate_dependencies, set.union) @cached_method def timestamp(self, filename): return os.path.getmtime(filename) def extract_timestamp(self, filename): return self.timestamp(filename), filename def newest_dependency(self, filename): return max([self.extract_timestamp(f) for f in self.all_dependencies(filename)]) def transitive_fingerprint(self, filename, extra=None): try: m = hashlib.md5(__version__) m.update(file_hash(filename)) for x in sorted(self.all_dependencies(filename)): if os.path.splitext(x)[1] not in ('.c', '.cpp', '.h'): m.update(file_hash(x)) if extra is not None: m.update(str(extra)) return m.hexdigest() except IOError: return None def distutils_info0(self, filename): info = self.parse_dependencies(filename)[3] externs = self.cimports_and_externs(filename)[1] if externs: if 'depends' in info.values: info.values['depends'] = list(set(info.values['depends']).union(externs)) else: info.values['depends'] = list(externs) return info def distutils_info(self, filename, aliases=None, base=None): return (self.transitive_merge(filename, self.distutils_info0, DistutilsInfo.merge) .subs(aliases) .merge(base)) def transitive_merge(self, node, extract, merge): try: seen = self._transitive_cache[extract, merge] except KeyError: seen = self._transitive_cache[extract, merge] = {} return self.transitive_merge_helper( node, extract, merge, seen, {}, self.cimported_files)[0] def transitive_merge_helper(self, node, extract, merge, seen, stack, outgoing): if node in seen: return seen[node], None deps = extract(node) if node in stack: return deps, node try: stack[node] = len(stack) loop = None for next in outgoing(node): sub_deps, sub_loop = self.transitive_merge_helper(next, extract, merge, seen, stack, outgoing) if sub_loop is not None: if loop is not None and stack[loop] < stack[sub_loop]: pass else: loop = sub_loop deps = merge(deps, sub_deps) if loop == node: loop = None if loop is None: seen[node] = deps return deps, loop finally: del stack[node] _dep_tree = None def create_dependency_tree(ctx=None, quiet=False): global _dep_tree if _dep_tree is None: if ctx is None: ctx = Context(["."], CompilationOptions(default_options)) _dep_tree = DependencyTree(ctx, quiet=quiet) return _dep_tree # This may be useful for advanced users? def create_extension_list(patterns, exclude=[], ctx=None, aliases=None, quiet=False, exclude_failures=False): if not isinstance(patterns, (list, tuple)): patterns = [patterns] explicit_modules = set([m.name for m in patterns if isinstance(m, Extension)]) seen = set() deps = create_dependency_tree(ctx, quiet=quiet) to_exclude = set() if not isinstance(exclude, list): exclude = [exclude] for pattern in exclude: to_exclude.update(map(os.path.abspath, extended_iglob(pattern))) module_list = [] for pattern in patterns: if isinstance(pattern, str): filepattern = pattern template = None name = '*' base = None exn_type = Extension elif isinstance(pattern, Extension): filepattern = pattern.sources[0] if os.path.splitext(filepattern)[1] not in ('.py', '.pyx'): # ignore non-cython modules module_list.append(pattern) continue template = pattern name = template.name base = DistutilsInfo(exn=template) exn_type = template.__class__ else: raise TypeError(pattern) for file in extended_iglob(filepattern): if os.path.abspath(file) in to_exclude: continue pkg = deps.package(file) if '*' in name: module_name = deps.fully_qualified_name(file) if module_name in explicit_modules: continue else: module_name = name if module_name not in seen: try: kwds = deps.distutils_info(file, aliases, base).values except Exception: if exclude_failures: continue raise if base is not None: for key, value in base.values.items(): if key not in kwds: kwds[key] = value sources = [file] if template is not None: sources += template.sources[1:] if 'sources' in kwds: # allow users to add .c files etc. for source in kwds['sources']: source = encode_filename_in_py2(source) if source not in sources: sources.append(source) del kwds['sources'] if 'depends' in kwds: depends = resolve_depends(kwds['depends'], (kwds.get('include_dirs') or []) + [find_root_package_dir(file)]) if template is not None: # Always include everything from the template. depends = list(set(template.depends).union(set(depends))) kwds['depends'] = depends module_list.append(exn_type( name=module_name, sources=sources, **kwds)) m = module_list[-1] seen.add(name) return module_list # This is the user-exposed entry point. def cythonize(module_list, exclude=[], nthreads=0, aliases=None, quiet=False, force=False, exclude_failures=False, **options): """ Compile a set of source modules into C/C++ files and return a list of distutils Extension objects for them. As module list, pass either a glob pattern, a list of glob patterns or a list of Extension objects. The latter allows you to configure the extensions separately through the normal distutils options. When using glob patterns, you can exclude certain module names explicitly by passing them into the 'exclude' option. For parallel compilation, set the 'nthreads' option to the number of concurrent builds. For a broad 'try to compile' mode that ignores compilation failures and simply excludes the failed extensions, pass 'exclude_failures=True'. Note that this only really makes sense for compiling .py files which can also be used without compilation. Additional compilation options can be passed as keyword arguments. """ if 'include_path' not in options: options['include_path'] = ['.'] if 'common_utility_include_dir' in options: if options.get('cache'): raise NotImplementedError("common_utility_include_dir does not yet work with caching") if not os.path.exists(options['common_utility_include_dir']): os.makedirs(options['common_utility_include_dir']) c_options = CompilationOptions(**options) cpp_options = CompilationOptions(**options); cpp_options.cplus = True ctx = c_options.create_context() options = c_options module_list = create_extension_list( module_list, exclude=exclude, ctx=ctx, quiet=quiet, exclude_failures=exclude_failures, aliases=aliases) deps = create_dependency_tree(ctx, quiet=quiet) build_dir = getattr(options, 'build_dir', None) modules_by_cfile = {} to_compile = [] for m in module_list: if build_dir: root = os.path.realpath(os.path.abspath(find_root_package_dir(m.sources[0]))) def copy_to_build_dir(filepath, root=root): filepath_abs = os.path.realpath(os.path.abspath(filepath)) if os.path.isabs(filepath): filepath = filepath_abs if filepath_abs.startswith(root): mod_dir = os.path.join(build_dir, os.path.dirname(_relpath(filepath, root))) if not os.path.isdir(mod_dir): os.makedirs(mod_dir) shutil.copy(filepath, mod_dir) for dep in m.depends: copy_to_build_dir(dep) new_sources = [] for source in m.sources: base, ext = os.path.splitext(source) if ext in ('.pyx', '.py'): if m.language == 'c++': c_file = base + '.cpp' options = cpp_options else: c_file = base + '.c' options = c_options # setup for out of place build directory if enabled if build_dir: c_file = os.path.join(build_dir, c_file) dir = os.path.dirname(c_file) if not os.path.isdir(dir): os.makedirs(dir) if os.path.exists(c_file): c_timestamp = os.path.getmtime(c_file) else: c_timestamp = -1 # Priority goes first to modified files, second to direct # dependents, and finally to indirect dependents. if c_timestamp < deps.timestamp(source): dep_timestamp, dep = deps.timestamp(source), source priority = 0 else: dep_timestamp, dep = deps.newest_dependency(source) priority = 2 - (dep in deps.immediate_dependencies(source)) if force or c_timestamp < dep_timestamp: if not quiet: if source == dep: print("Compiling %s because it changed." % source) else: print("Compiling %s because it depends on %s." % (source, dep)) if not force and hasattr(options, 'cache'): extra = m.language fingerprint = deps.transitive_fingerprint(source, extra) else: fingerprint = None to_compile.append((priority, source, c_file, fingerprint, quiet, options, not exclude_failures)) new_sources.append(c_file) if c_file not in modules_by_cfile: modules_by_cfile[c_file] = [m] else: modules_by_cfile[c_file].append(m) else: new_sources.append(source) if build_dir: copy_to_build_dir(source) m.sources = new_sources if hasattr(options, 'cache'): if not os.path.exists(options.cache): os.makedirs(options.cache) to_compile.sort() if nthreads: # Requires multiprocessing (or Python >= 2.6) try: import multiprocessing pool = multiprocessing.Pool(nthreads) except (ImportError, OSError): print("multiprocessing required for parallel cythonization") nthreads = 0 else: pool.map(cythonize_one_helper, to_compile) if not nthreads: for args in to_compile: cythonize_one(*args[1:]) if exclude_failures: failed_modules = set() for c_file, modules in modules_by_cfile.iteritems(): if not os.path.exists(c_file): failed_modules.update(modules) elif os.path.getsize(c_file) < 200: f = io_open(c_file, 'r', encoding='iso8859-1') try: if f.read(len('#error ')) == '#error ': # dead compilation result failed_modules.update(modules) finally: f.close() if failed_modules: for module in failed_modules: module_list.remove(module) print("Failed compilations: %s" % ', '.join(sorted([ module.name for module in failed_modules]))) if hasattr(options, 'cache'): cleanup_cache(options.cache, getattr(options, 'cache_size', 1024 * 1024 * 100)) # cythonize() is often followed by the (non-Python-buffered) # compiler output, flush now to avoid interleaving output. sys.stdout.flush() return module_list if os.environ.get('XML_RESULTS'): compile_result_dir = os.environ['XML_RESULTS'] def record_results(func): def with_record(*args): t = time.time() success = True try: try: func(*args) except: success = False finally: t = time.time() - t module = fully_qualified_name(args[0]) name = "cythonize." + module failures = 1 - success if success: failure_item = "" else: failure_item = "failure" output = open(os.path.join(compile_result_dir, name + ".xml"), "w") output.write(""" %(failure_item)s """.strip() % locals()) output.close() return with_record else: record_results = lambda x: x # TODO: Share context? Issue: pyx processing leaks into pxd module @record_results def cythonize_one(pyx_file, c_file, fingerprint, quiet, options=None, raise_on_failure=True): from Cython.Compiler.Main import compile, default_options from Cython.Compiler.Errors import CompileError, PyrexError if fingerprint: if not os.path.exists(options.cache): try: os.mkdir(options.cache) except: if not os.path.exists(options.cache): raise # Cython-generated c files are highly compressible. # (E.g. a compression ratio of about 10 for Sage). fingerprint_file = join_path( options.cache, "%s-%s%s" % (os.path.basename(c_file), fingerprint, gzip_ext)) if os.path.exists(fingerprint_file): if not quiet: print("Found compiled %s in cache" % pyx_file) os.utime(fingerprint_file, None) g = gzip_open(fingerprint_file, 'rb') try: f = open(c_file, 'wb') try: shutil.copyfileobj(g, f) finally: f.close() finally: g.close() return if not quiet: print("Cythonizing %s" % pyx_file) if options is None: options = CompilationOptions(default_options) options.output_file = c_file any_failures = 0 try: result = compile([pyx_file], options) if result.num_errors > 0: any_failures = 1 except (EnvironmentError, PyrexError), e: sys.stderr.write('%s\n' % e) any_failures = 1 # XXX import traceback traceback.print_exc() except Exception: if raise_on_failure: raise import traceback traceback.print_exc() any_failures = 1 if any_failures: if raise_on_failure: raise CompileError(None, pyx_file) elif os.path.exists(c_file): os.remove(c_file) elif fingerprint: f = open(c_file, 'rb') try: g = gzip_open(fingerprint_file, 'wb') try: shutil.copyfileobj(f, g) finally: g.close() finally: f.close() def cythonize_one_helper(m): import traceback try: return cythonize_one(*m[1:]) except Exception: traceback.print_exc() raise def cleanup_cache(cache, target_size, ratio=.85): try: p = subprocess.Popen(['du', '-s', '-k', os.path.abspath(cache)], stdout=subprocess.PIPE) res = p.wait() if res == 0: total_size = 1024 * int(p.stdout.read().strip().split()[0]) if total_size < target_size: return except (OSError, ValueError): pass total_size = 0 all = [] for file in os.listdir(cache): path = join_path(cache, file) s = os.stat(path) total_size += s.st_size all.append((s.st_atime, s.st_size, path)) if total_size > target_size: for time, size, file in reversed(sorted(all)): os.unlink(file) total_size -= size if total_size < target_size * ratio: break cython-0.20.1+git90-g0e6e38e/Cython/Build/Inline.py000066400000000000000000000251761231323242300213530ustar00rootroot00000000000000import sys, os, re, inspect import imp try: import hashlib except ImportError: import md5 as hashlib from distutils.core import Distribution, Extension from distutils.command.build_ext import build_ext import Cython from Cython.Compiler.Main import Context, CompilationOptions, default_options from Cython.Compiler.ParseTreeTransforms import CythonTransform, SkipDeclarations, AnalyseDeclarationsTransform from Cython.Compiler.TreeFragment import parse_from_strings from Cython.Build.Dependencies import strip_string_literals, cythonize, cached_function from Cython.Compiler import Pipeline from Cython.Utils import get_cython_cache_dir import cython as cython_module # A utility function to convert user-supplied ASCII strings to unicode. if sys.version_info[0] < 3: def to_unicode(s): if not isinstance(s, unicode): return s.decode('ascii') else: return s else: to_unicode = lambda x: x class AllSymbols(CythonTransform, SkipDeclarations): def __init__(self): CythonTransform.__init__(self, None) self.names = set() def visit_NameNode(self, node): self.names.add(node.name) @cached_function def unbound_symbols(code, context=None): code = to_unicode(code) if context is None: context = Context([], default_options) from Cython.Compiler.ParseTreeTransforms import AnalyseDeclarationsTransform tree = parse_from_strings('(tree fragment)', code) for phase in Pipeline.create_pipeline(context, 'pyx'): if phase is None: continue tree = phase(tree) if isinstance(phase, AnalyseDeclarationsTransform): break symbol_collector = AllSymbols() symbol_collector(tree) unbound = [] try: import builtins except ImportError: import __builtin__ as builtins for name in symbol_collector.names: if not tree.scope.lookup(name) and not hasattr(builtins, name): unbound.append(name) return unbound def unsafe_type(arg, context=None): py_type = type(arg) if py_type is int: return 'long' else: return safe_type(arg, context) def safe_type(arg, context=None): py_type = type(arg) if py_type in [list, tuple, dict, str]: return py_type.__name__ elif py_type is complex: return 'double complex' elif py_type is float: return 'double' elif py_type is bool: return 'bint' elif 'numpy' in sys.modules and isinstance(arg, sys.modules['numpy'].ndarray): return 'numpy.ndarray[numpy.%s_t, ndim=%s]' % (arg.dtype.name, arg.ndim) else: for base_type in py_type.mro(): if base_type.__module__ in ('__builtin__', 'builtins'): return 'object' module = context.find_module(base_type.__module__, need_pxd=False) if module: entry = module.lookup(base_type.__name__) if entry.is_type: return '%s.%s' % (base_type.__module__, base_type.__name__) return 'object' def _get_build_extension(): dist = Distribution() # Ensure the build respects distutils configuration by parsing # the configuration files config_files = dist.find_config_files() dist.parse_config_files(config_files) build_extension = build_ext(dist) build_extension.finalize_options() return build_extension @cached_function def _create_context(cython_include_dirs): return Context(list(cython_include_dirs), default_options) def cython_inline(code, get_type=unsafe_type, lib_dir=os.path.join(get_cython_cache_dir(), 'inline'), cython_include_dirs=['.'], force=False, quiet=False, locals=None, globals=None, **kwds): if get_type is None: get_type = lambda x: 'object' code = to_unicode(code) orig_code = code code, literals = strip_string_literals(code) code = strip_common_indent(code) ctx = _create_context(tuple(cython_include_dirs)) if locals is None: locals = inspect.currentframe().f_back.f_back.f_locals if globals is None: globals = inspect.currentframe().f_back.f_back.f_globals try: for symbol in unbound_symbols(code): if symbol in kwds: continue elif symbol in locals: kwds[symbol] = locals[symbol] elif symbol in globals: kwds[symbol] = globals[symbol] else: print("Couldn't find ", symbol) except AssertionError: if not quiet: # Parsing from strings not fully supported (e.g. cimports). print("Could not parse code as a string (to extract unbound symbols).") cimports = [] for name, arg in kwds.items(): if arg is cython_module: cimports.append('\ncimport cython as %s' % name) del kwds[name] arg_names = kwds.keys() arg_names.sort() arg_sigs = tuple([(get_type(kwds[arg], ctx), arg) for arg in arg_names]) key = orig_code, arg_sigs, sys.version_info, sys.executable, Cython.__version__ module_name = "_cython_inline_" + hashlib.md5(str(key).encode('utf-8')).hexdigest() if module_name in sys.modules: module = sys.modules[module_name] else: build_extension = None if cython_inline.so_ext is None: # Figure out and cache current extension suffix build_extension = _get_build_extension() cython_inline.so_ext = build_extension.get_ext_filename('') module_path = os.path.join(lib_dir, module_name + cython_inline.so_ext) if not os.path.exists(lib_dir): os.makedirs(lib_dir) if force or not os.path.isfile(module_path): cflags = [] c_include_dirs = [] qualified = re.compile(r'([.\w]+)[.]') for type, _ in arg_sigs: m = qualified.match(type) if m: cimports.append('\ncimport %s' % m.groups()[0]) # one special case if m.groups()[0] == 'numpy': import numpy c_include_dirs.append(numpy.get_include()) # cflags.append('-Wno-unused') module_body, func_body = extract_func_code(code) params = ', '.join(['%s %s' % a for a in arg_sigs]) module_code = """ %(module_body)s %(cimports)s def __invoke(%(params)s): %(func_body)s """ % {'cimports': '\n'.join(cimports), 'module_body': module_body, 'params': params, 'func_body': func_body } for key, value in literals.items(): module_code = module_code.replace(key, value) pyx_file = os.path.join(lib_dir, module_name + '.pyx') fh = open(pyx_file, 'w') try: fh.write(module_code) finally: fh.close() extension = Extension( name = module_name, sources = [pyx_file], include_dirs = c_include_dirs, extra_compile_args = cflags) if build_extension is None: build_extension = _get_build_extension() build_extension.extensions = cythonize([extension], include_path=cython_include_dirs, quiet=quiet) build_extension.build_temp = os.path.dirname(pyx_file) build_extension.build_lib = lib_dir build_extension.run() module = imp.load_dynamic(module_name, module_path) arg_list = [kwds[arg] for arg in arg_names] return module.__invoke(*arg_list) # Cached suffix used by cython_inline above. None should get # overridden with actual value upon the first cython_inline invocation cython_inline.so_ext = None non_space = re.compile('[^ ]') def strip_common_indent(code): min_indent = None lines = code.split('\n') for line in lines: match = non_space.search(line) if not match: continue # blank indent = match.start() if line[indent] == '#': continue # comment elif min_indent is None or min_indent > indent: min_indent = indent for ix, line in enumerate(lines): match = non_space.search(line) if not match or line[indent] == '#': continue else: lines[ix] = line[min_indent:] return '\n'.join(lines) module_statement = re.compile(r'^((cdef +(extern|class))|cimport|(from .+ cimport)|(from .+ import +[*]))') def extract_func_code(code): module = [] function = [] current = function code = code.replace('\t', ' ') lines = code.split('\n') for line in lines: if not line.startswith(' '): if module_statement.match(line): current = module else: current = function current.append(line) return '\n'.join(module), ' ' + '\n '.join(function) try: from inspect import getcallargs except ImportError: def getcallargs(func, *arg_values, **kwd_values): all = {} args, varargs, kwds, defaults = inspect.getargspec(func) if varargs is not None: all[varargs] = arg_values[len(args):] for name, value in zip(args, arg_values): all[name] = value for name, value in kwd_values.items(): if name in args: if name in all: raise TypeError("Duplicate argument %s" % name) all[name] = kwd_values.pop(name) if kwds is not None: all[kwds] = kwd_values elif kwd_values: raise TypeError("Unexpected keyword arguments: %s" % kwd_values.keys()) if defaults is None: defaults = () first_default = len(args) - len(defaults) for ix, name in enumerate(args): if name not in all: if ix >= first_default: all[name] = defaults[ix - first_default] else: raise TypeError("Missing argument: %s" % name) return all def get_body(source): ix = source.index(':') if source[:5] == 'lambda': return "return %s" % source[ix+1:] else: return source[ix+1:] # Lots to be done here... It would be especially cool if compiled functions # could invoke each other quickly. class RuntimeCompiledFunction(object): def __init__(self, f): self._f = f self._body = get_body(inspect.getsource(f)) def __call__(self, *args, **kwds): all = getcallargs(self._f, *args, **kwds) return cython_inline(self._body, locals=self._f.func_globals, globals=self._f.func_globals, **all) cython-0.20.1+git90-g0e6e38e/Cython/Build/Tests/000077500000000000000000000000001231323242300206525ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Cython/Build/Tests/TestInline.py000066400000000000000000000032671231323242300233120ustar00rootroot00000000000000import os, tempfile from Cython.Shadow import inline from Cython.Build.Inline import safe_type from Cython.TestUtils import CythonTest try: import numpy has_numpy = True except: has_numpy = False test_kwds = dict(force=True, quiet=True) global_value = 100 class TestInline(CythonTest): def setUp(self): CythonTest.setUp(self) self.test_kwds = dict(test_kwds) if os.path.isdir('BUILD'): lib_dir = os.path.join('BUILD','inline') else: lib_dir = tempfile.mkdtemp(prefix='cython_inline_') self.test_kwds['lib_dir'] = lib_dir def test_simple(self): self.assertEquals(inline("return 1+2", **self.test_kwds), 3) def test_types(self): self.assertEquals(inline(""" cimport cython return cython.typeof(a), cython.typeof(b) """, a=1.0, b=[], **self.test_kwds), ('double', 'list object')) def test_locals(self): a = 1 b = 2 self.assertEquals(inline("return a+b", **self.test_kwds), 3) def test_globals(self): self.assertEquals(inline("return global_value + 1", **self.test_kwds), global_value + 1) def test_pure(self): import cython as cy b = inline(""" b = cy.declare(float, a) c = cy.declare(cy.pointer(cy.float), &b) return b """, a=3) self.assertEquals(type(b), float) if has_numpy: def test_numpy(self): import numpy a = numpy.ndarray((10, 20)) a[0,0] = 10 self.assertEquals(safe_type(a), 'numpy.ndarray[numpy.float64_t, ndim=2]') self.assertEquals(inline("return a[0,0]", a=a, **self.test_kwds), 10.0) cython-0.20.1+git90-g0e6e38e/Cython/Build/Tests/TestStripLiterals.py000066400000000000000000000030201231323242300246600ustar00rootroot00000000000000from Cython.Build.Dependencies import strip_string_literals from Cython.TestUtils import CythonTest class TestStripLiterals(CythonTest): def t(self, before, expected): actual, literals = strip_string_literals(before, prefix="_L") self.assertEquals(expected, actual) for key, value in literals.items(): actual = actual.replace(key, value) self.assertEquals(before, actual) def test_empty(self): self.t("", "") def test_single_quote(self): self.t("'x'", "'_L1_'") def test_double_quote(self): self.t('"x"', '"_L1_"') def test_nested_quotes(self): self.t(""" '"' "'" """, """ '_L1_' "_L2_" """) def test_triple_quote(self): self.t(" '''a\n''' ", " '''_L1_''' ") def test_backslash(self): self.t(r"'a\'b'", "'_L1_'") self.t(r"'a\\'", "'_L1_'") self.t(r"'a\\\'b'", "'_L1_'") def test_unicode(self): self.t("u'abc'", "u'_L1_'") def test_raw(self): self.t(r"r'abc\\'", "r'_L1_'") def test_raw_unicode(self): self.t(r"ru'abc\\'", "ru'_L1_'") def test_comment(self): self.t("abc # foo", "abc #_L1_") def test_comment_and_quote(self): self.t("abc # 'x'", "abc #_L1_") self.t("'abc#'", "'_L1_'") def test_include(self): self.t("include 'a.pxi' # something here", "include '_L1_' #_L2_") def test_extern(self): self.t("cdef extern from 'a.h': # comment", "cdef extern from '_L1_': #_L2_") cython-0.20.1+git90-g0e6e38e/Cython/Build/Tests/__init__.py000066400000000000000000000000151231323242300227570ustar00rootroot00000000000000# empty file cython-0.20.1+git90-g0e6e38e/Cython/Build/__init__.py000066400000000000000000000000431231323242300216560ustar00rootroot00000000000000from Dependencies import cythonize cython-0.20.1+git90-g0e6e38e/Cython/CodeWriter.py000066400000000000000000000350641231323242300211420ustar00rootroot00000000000000""" Serializes a Cython code tree to Cython code. This is primarily useful for debugging and testing purposes. The output is in a strict format, no whitespace or comments from the input is preserved (and it could not be as it is not present in the code tree). """ from Cython.Compiler.Visitor import TreeVisitor from Cython.Compiler.ExprNodes import * class LinesResult(object): def __init__(self): self.lines = [] self.s = u"" def put(self, s): self.s += s def newline(self): self.lines.append(self.s) self.s = u"" def putline(self, s): self.put(s) self.newline() class DeclarationWriter(TreeVisitor): indent_string = u" " def __init__(self, result = None): super(DeclarationWriter, self).__init__() if result is None: result = LinesResult() self.result = result self.numindents = 0 self.tempnames = {} self.tempblockindex = 0 def write(self, tree): self.visit(tree) return self.result def indent(self): self.numindents += 1 def dedent(self): self.numindents -= 1 def startline(self, s = u""): self.result.put(self.indent_string * self.numindents + s) def put(self, s): self.result.put(s) def putline(self, s): self.result.putline(self.indent_string * self.numindents + s) def endline(self, s = u""): self.result.putline(s) def line(self, s): self.startline(s) self.endline() def comma_separated_list(self, items, output_rhs=False): if len(items) > 0: for item in items[:-1]: self.visit(item) if output_rhs and item.default is not None: self.put(u" = ") self.visit(item.default) self.put(u", ") self.visit(items[-1]) def visit_Node(self, node): raise AssertionError("Node not handled by serializer: %r" % node) def visit_ModuleNode(self, node): self.visitchildren(node) def visit_StatListNode(self, node): self.visitchildren(node) def visit_CDefExternNode(self, node): if node.include_file is None: file = u'*' else: file = u'"%s"' % node.include_file self.putline(u"cdef extern from %s:" % file) self.indent() self.visit(node.body) self.dedent() def visit_CPtrDeclaratorNode(self, node): self.put('*') self.visit(node.base) def visit_CReferenceDeclaratorNode(self, node): self.put('&') self.visit(node.base) def visit_CArrayDeclaratorNode(self, node): self.visit(node.base) self.put(u'[') if node.dimension is not None: self.visit(node.dimension) self.put(u']') def visit_CArrayDeclaratorNode(self, node): self.visit(node.base) self.put(u'[') if node.dimension is not None: self.visit(node.dimension) self.put(u']') def visit_CFuncDeclaratorNode(self, node): # TODO: except, gil, etc. self.visit(node.base) self.put(u'(') self.comma_separated_list(node.args) self.endline(u')') def visit_CNameDeclaratorNode(self, node): self.put(node.name) def visit_CSimpleBaseTypeNode(self, node): # See Parsing.p_sign_and_longness if node.is_basic_c_type: self.put(("unsigned ", "", "signed ")[node.signed]) if node.longness < 0: self.put("short " * -node.longness) elif node.longness > 0: self.put("long " * node.longness) self.put(node.name) def visit_CComplexBaseTypeNode(self, node): self.put(u'(') self.visit(node.base_type) self.visit(node.declarator) self.put(u')') def visit_CNestedBaseTypeNode(self, node): self.visit(node.base_type) self.put(u'.') self.put(node.name) def visit_TemplatedTypeNode(self, node): self.visit(node.base_type_node) self.put(u'[') self.comma_separated_list(node.positional_args + node.keyword_args.key_value_pairs) self.put(u']') def visit_CVarDefNode(self, node): self.startline(u"cdef ") self.visit(node.base_type) self.put(u" ") self.comma_separated_list(node.declarators, output_rhs=True) self.endline() def visit_container_node(self, node, decl, extras, attributes): # TODO: visibility self.startline(decl) if node.name: self.put(u' ') self.put(node.name) if node.cname is not None: self.put(u' "%s"' % node.cname) if extras: self.put(extras) self.endline(':') self.indent() if not attributes: self.putline('pass') else: for attribute in attributes: self.visit(attribute) self.dedent() def visit_CStructOrUnionDefNode(self, node): if node.typedef_flag: decl = u'ctypedef ' else: decl = u'cdef ' if node.visibility == 'public': decl += u'public ' if node.packed: decl += u'packed ' decl += node.kind self.visit_container_node(node, decl, None, node.attributes) def visit_CppClassNode(self, node): extras = "" if node.templates: extras = u"[%s]" % ", ".join(node.templates) if node.base_classes: extras += "(%s)" % ", ".join(node.base_classes) self.visit_container_node(node, u"cdef cppclass", extras, node.attributes) def visit_CEnumDefNode(self, node): self.visit_container_node(node, u"cdef enum", None, node.items) def visit_CEnumDefItemNode(self, node): self.startline(node.name) if node.cname: self.put(u' "%s"' % node.cname) if node.value: self.put(u" = ") self.visit(node.value) self.endline() def visit_CClassDefNode(self, node): assert not node.module_name if node.decorators: for decorator in node.decorators: self.visit(decorator) self.startline(u"cdef class ") self.put(node.class_name) if node.base_class_name: self.put(u"(") if node.base_class_module: self.put(node.base_class_module) self.put(u".") self.put(node.base_class_name) self.put(u")") self.endline(u":") self.indent() self.visit(node.body) self.dedent() def visit_CTypeDefNode(self, node): self.startline(u"ctypedef ") self.visit(node.base_type) self.put(u" ") self.visit(node.declarator) self.endline() def visit_FuncDefNode(self, node): self.startline(u"def %s(" % node.name) self.comma_separated_list(node.args) self.endline(u"):") self.indent() self.visit(node.body) self.dedent() def visit_CArgDeclNode(self, node): if node.base_type.name is not None: self.visit(node.base_type) self.put(u" ") self.visit(node.declarator) if node.default is not None: self.put(u" = ") self.visit(node.default) def visit_CImportStatNode(self, node): self.startline(u"cimport ") self.put(node.module_name) if node.as_name: self.put(u" as ") self.put(node.as_name) self.endline() def visit_FromCImportStatNode(self, node): self.startline(u"from ") self.put(node.module_name) self.put(u" cimport ") first = True for pos, name, as_name, kind in node.imported_names: assert kind is None if first: first = False else: self.put(u", ") self.put(name) if as_name: self.put(u" as ") self.put(as_name) self.endline() def visit_NameNode(self, node): self.put(node.name) def visit_IntNode(self, node): self.put(node.value) def visit_NoneNode(self, node): self.put(u"None") def visit_NotNode(self, node): self.put(u"(not ") self.visit(node.operand) self.put(u")") def visit_DecoratorNode(self, node): self.startline("@") self.visit(node.decorator) self.endline() def visit_BinopNode(self, node): self.visit(node.operand1) self.put(u" %s " % node.operator) self.visit(node.operand2) def visit_AttributeNode(self, node): self.visit(node.obj) self.put(u".%s" % node.attribute) def visit_BoolNode(self, node): self.put(str(node.value)) # FIXME: represent string nodes correctly def visit_StringNode(self, node): value = node.value if value.encoding is not None: value = value.encode(value.encoding) self.put(repr(value)) def visit_PassStatNode(self, node): self.startline(u"pass") self.endline() class CodeWriter(DeclarationWriter): def visit_SingleAssignmentNode(self, node): self.startline() self.visit(node.lhs) self.put(u" = ") self.visit(node.rhs) self.endline() def visit_CascadedAssignmentNode(self, node): self.startline() for lhs in node.lhs_list: self.visit(lhs) self.put(u" = ") self.visit(node.rhs) self.endline() def visit_PrintStatNode(self, node): self.startline(u"print ") self.comma_separated_list(node.arg_tuple.args) if not node.append_newline: self.put(u",") self.endline() def visit_ForInStatNode(self, node): self.startline(u"for ") self.visit(node.target) self.put(u" in ") self.visit(node.iterator.sequence) self.endline(u":") self.indent() self.visit(node.body) self.dedent() if node.else_clause is not None: self.line(u"else:") self.indent() self.visit(node.else_clause) self.dedent() def visit_IfStatNode(self, node): # The IfClauseNode is handled directly without a seperate match # for clariy. self.startline(u"if ") self.visit(node.if_clauses[0].condition) self.endline(":") self.indent() self.visit(node.if_clauses[0].body) self.dedent() for clause in node.if_clauses[1:]: self.startline("elif ") self.visit(clause.condition) self.endline(":") self.indent() self.visit(clause.body) self.dedent() if node.else_clause is not None: self.line("else:") self.indent() self.visit(node.else_clause) self.dedent() def visit_SequenceNode(self, node): self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm... def visit_SimpleCallNode(self, node): self.visit(node.function) self.put(u"(") self.comma_separated_list(node.args) self.put(")") def visit_GeneralCallNode(self, node): self.visit(node.function) self.put(u"(") posarg = node.positional_args if isinstance(posarg, AsTupleNode): self.visit(posarg.arg) else: self.comma_separated_list(posarg) if node.keyword_args is not None or node.starstar_arg is not None: raise Exception("Not implemented yet") self.put(u")") def visit_ExprStatNode(self, node): self.startline() self.visit(node.expr) self.endline() def visit_InPlaceAssignmentNode(self, node): self.startline() self.visit(node.lhs) self.put(u" %s= " % node.operator) self.visit(node.rhs) self.endline() def visit_WithStatNode(self, node): self.startline() self.put(u"with ") self.visit(node.manager) if node.target is not None: self.put(u" as ") self.visit(node.target) self.endline(u":") self.indent() self.visit(node.body) self.dedent() def visit_TryFinallyStatNode(self, node): self.line(u"try:") self.indent() self.visit(node.body) self.dedent() self.line(u"finally:") self.indent() self.visit(node.finally_clause) self.dedent() def visit_TryExceptStatNode(self, node): self.line(u"try:") self.indent() self.visit(node.body) self.dedent() for x in node.except_clauses: self.visit(x) if node.else_clause is not None: self.visit(node.else_clause) def visit_ExceptClauseNode(self, node): self.startline(u"except") if node.pattern is not None: self.put(u" ") self.visit(node.pattern) if node.target is not None: self.put(u", ") self.visit(node.target) self.endline(":") self.indent() self.visit(node.body) self.dedent() def visit_ReturnStatNode(self, node): self.startline("return ") self.visit(node.value) self.endline() def visit_ReraiseStatNode(self, node): self.line("raise") def visit_ImportNode(self, node): self.put(u"(import %s)" % node.module_name.value) def visit_TempsBlockNode(self, node): """ Temporaries are output like $1_1', where the first number is an index of the TempsBlockNode and the second number is an index of the temporary which that block allocates. """ idx = 0 for handle in node.temps: self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx) idx += 1 self.tempblockindex += 1 self.visit(node.body) def visit_TempRefNode(self, node): self.put(self.tempnames[node.handle]) class PxdWriter(DeclarationWriter): def __call__(self, node): print u'\n'.join(self.write(node).lines) return node def visit_CFuncDefNode(self, node): if 'inline' in node.modifiers: return if node.overridable: self.startline(u'cpdef ') else: self.startline(u'cdef ') if node.visibility != 'private': self.put(node.visibility) self.put(u' ') if node.api: self.put(u'api ') self.visit(node.declarator) def visit_StatNode(self, node): pass cython-0.20.1+git90-g0e6e38e/Cython/Compiler/000077500000000000000000000000001231323242300202635ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Cython/Compiler/AnalysedTreeTransforms.py000066400000000000000000000072761231323242300253100ustar00rootroot00000000000000from Visitor import ScopeTrackingTransform from Nodes import StatListNode, SingleAssignmentNode, CFuncDefNode, DefNode from ExprNodes import DictNode, DictItemNode, NameNode, UnicodeNode from PyrexTypes import py_object_type from StringEncoding import EncodedString import Symtab class AutoTestDictTransform(ScopeTrackingTransform): # Handles autotestdict directive blacklist = ['__cinit__', '__dealloc__', '__richcmp__', '__nonzero__', '__bool__', '__len__', '__contains__'] def visit_ModuleNode(self, node): if node.is_pxd: return node self.scope_type = 'module' self.scope_node = node if not self.current_directives['autotestdict']: return node self.all_docstrings = self.current_directives['autotestdict.all'] self.cdef_docstrings = self.all_docstrings or self.current_directives['autotestdict.cdef'] assert isinstance(node.body, StatListNode) # First see if __test__ is already created if u'__test__' in node.scope.entries: # Do nothing return node pos = node.pos self.tests = [] self.testspos = node.pos test_dict_entry = node.scope.declare_var(EncodedString(u'__test__'), py_object_type, pos, visibility='public') create_test_dict_assignment = SingleAssignmentNode(pos, lhs=NameNode(pos, name=EncodedString(u'__test__'), entry=test_dict_entry), rhs=DictNode(pos, key_value_pairs=self.tests)) self.visitchildren(node) node.body.stats.append(create_test_dict_assignment) return node def add_test(self, testpos, path, doctest): pos = self.testspos keystr = u'%s (line %d)' % (path, testpos[1]) key = UnicodeNode(pos, value=EncodedString(keystr)) value = UnicodeNode(pos, value=doctest) self.tests.append(DictItemNode(pos, key=key, value=value)) def visit_ExprNode(self, node): # expressions cannot contain functions and lambda expressions # do not have a docstring return node def visit_FuncDefNode(self, node): if not node.doc or (isinstance(node, DefNode) and node.fused_py_func): return node if not self.cdef_docstrings: if isinstance(node, CFuncDefNode) and not node.py_func: return node if not self.all_docstrings and '>>>' not in node.doc: return node pos = self.testspos if self.scope_type == 'module': path = node.entry.name elif self.scope_type in ('pyclass', 'cclass'): if isinstance(node, CFuncDefNode): if node.py_func is not None: name = node.py_func.name else: name = node.entry.name else: name = node.name if self.scope_type == 'cclass' and name in self.blacklist: return node if self.scope_type == 'pyclass': class_name = self.scope_node.name else: class_name = self.scope_node.class_name if isinstance(node.entry.scope, Symtab.PropertyScope): property_method_name = node.entry.scope.name path = "%s.%s.%s" % (class_name, node.entry.scope.name, node.entry.name) else: path = "%s.%s" % (class_name, node.entry.name) else: assert False self.add_test(node.pos, path, node.doc) return node cython-0.20.1+git90-g0e6e38e/Cython/Compiler/Annotate.py000066400000000000000000000155121231323242300224120ustar00rootroot00000000000000# Note: Work in progress import os import re import codecs from xml.sax.saxutils import escape as html_escape from StringIO import StringIO import Version from Code import CCodeWriter from Cython import Utils # need one-characters subsitutions (for now) so offsets aren't off special_chars = [ (u'&', u'\xF2', u'&'), (u'<', u'\xF0', u'<'), (u'>', u'\xF1', u'>'), ] class AnnotationCCodeWriter(CCodeWriter): def __init__(self, create_from=None, buffer=None, copy_formatting=True): CCodeWriter.__init__(self, create_from, buffer, copy_formatting=True) if create_from is None: self.annotation_buffer = StringIO() self.annotations = [] self.last_pos = None self.code = {} else: # When creating an insertion point, keep references to the same database self.annotation_buffer = create_from.annotation_buffer self.annotations = create_from.annotations self.code = create_from.code self.last_pos = create_from.last_pos def create_new(self, create_from, buffer, copy_formatting): return AnnotationCCodeWriter(create_from, buffer, copy_formatting) def write(self, s): CCodeWriter.write(self, s) self.annotation_buffer.write(s) def mark_pos(self, pos): if pos is not None: CCodeWriter.mark_pos(self, pos) if self.last_pos: pos_code = self.code.setdefault(self.last_pos[0].filename,{}) code = pos_code.get(self.last_pos[1], "") pos_code[self.last_pos[1]] = code + self.annotation_buffer.getvalue() self.annotation_buffer = StringIO() self.last_pos = pos def annotate(self, pos, item): self.annotations.append((pos, item)) def save_annotation(self, source_filename, target_filename): self.mark_pos(None) f = Utils.open_source_file(source_filename) lines = f.readlines() for k, line in enumerate(lines): for c, cc, html in special_chars: line = line.replace(c, cc) lines[k] = line f.close() all = [] if False: for pos, item in self.annotations: if pos[0].filename == source_filename: start = item.start() size, end = item.end() if size: all.append((pos, start)) all.append(((source_filename, pos[1], pos[2]+size), end)) else: all.append((pos, start+end)) all.sort(reverse=True) for pos, item in all: _, line_no, col = pos line_no -= 1 col += 1 line = lines[line_no] lines[line_no] = line[:col] + item + line[col:] html_filename = os.path.splitext(target_filename)[0] + ".html" f = codecs.open(html_filename, "w", encoding="UTF-8") f.write(u'\n') f.write(u'\n' % Version.watermark) f.write(u'\n') f.write(u""" """) f.write(u'\n') f.write(u'

Generated by Cython %s\n' % Version.watermark) c_file = Utils.decode_filename(os.path.basename(target_filename)) f.write(u'

Raw output: %s\n' % (c_file, c_file)) zero_calls = dict((name, 0) for name in 'refnanny py_macro_api py_c_api pyx_macro_api pyx_c_api error_goto'.split()) def annotate(match): group_name = match.lastgroup calls[group_name] += 1 return ur"%s" % ( group_name, match.group(group_name)) pos_comment_marker = u'/* \N{HORIZONTAL ELLIPSIS} */\n' k = 0 code_source_file = self.code.get(source_filename, {}) for line in lines: k += 1 try: code = code_source_file[k] except KeyError: code = '' else: code = _replace_pos_comment(pos_comment_marker, code) if code.startswith(pos_comment_marker): code = code[len(pos_comment_marker):] code = html_escape(code) calls = zero_calls.copy() code = _parse_code(annotate, code) score = (5 * calls['py_c_api'] + 2 * calls['pyx_c_api'] + calls['py_macro_api'] + calls['pyx_macro_api']) color = u"FFFF%02x" % int(255/(1+score/10.0)) f.write(u"

" % (color, k))

            f.write(u" %d: " % k)
            for c, cc, html in special_chars:
                line = line.replace(cc, html)
            f.write(line.rstrip())

            f.write(u'
\n') f.write(u"
%s
" % (k, color, code)) f.write(u'\n') f.close() _parse_code = re.compile( ur'(?P__Pyx_X?(?:GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)|' ur'(?:' ur'(?P__Pyx_[A-Z][A-Z_]+)|' ur'(?P__Pyx_[A-Z][a-z_][A-Za-z_]+)|' ur'(?PPy[A-Z][a-z]+_[A-Z][A-Z_]+)|' ur'(?PPy[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]+)' ur')(?=\()|' # look-ahead to exclude subsequent '(' from replacement ur'(?P(?:(?<=;) *if .* +)?\{__pyx_filename = .*goto __pyx_L\w+;\})' ).sub _replace_pos_comment = re.compile( # this matches what Cython generates as code line marker comment ur'^\s*/\*(?:(?:[^*]|\*[^/])*\n)+\s*\*/\s*\n', re.M ).sub class AnnotationItem(object): def __init__(self, style, text, tag="", size=0): self.style = style self.text = text self.tag = tag self.size = size def start(self): return u"%s" % (self.style, self.text, self.tag) def end(self): return self.size, u"" cython-0.20.1+git90-g0e6e38e/Cython/Compiler/AutoDocTransforms.py000066400000000000000000000205301231323242300242520ustar00rootroot00000000000000from Cython.Compiler.Visitor import CythonTransform from Cython.Compiler.StringEncoding import EncodedString from Cython.Compiler import Options from Cython.Compiler import PyrexTypes, ExprNodes class EmbedSignature(CythonTransform): def __init__(self, context): super(EmbedSignature, self).__init__(context) self.denv = None # XXX self.class_name = None self.class_node = None unop_precedence = 11 binop_precedence = { 'or': 1, 'and': 2, 'not': 3, 'in': 4, 'not in': 4, 'is': 4, 'is not': 4, '<': 4, '<=': 4, '>': 4, '>=': 4, '!=': 4, '==': 4, '|': 5, '^': 6, '&': 7, '<<': 8, '>>': 8, '+': 9, '-': 9, '*': 10, '/': 10, '//': 10, '%': 10, # unary: '+': 11, '-': 11, '~': 11 '**': 12} def _fmt_expr_node(self, node, precedence=0): if isinstance(node, ExprNodes.BinopNode) and not node.inplace: new_prec = self.binop_precedence.get(node.operator, 0) result = '%s %s %s' % (self._fmt_expr_node(node.operand1, new_prec), node.operator, self._fmt_expr_node(node.operand2, new_prec)) if precedence > new_prec: result = '(%s)' % result elif isinstance(node, ExprNodes.UnopNode): result = '%s%s' % (node.operator, self._fmt_expr_node(node.operand, self.unop_precedence)) if precedence > self.unop_precedence: result = '(%s)' % result elif isinstance(node, ExprNodes.AttributeNode): result = '%s.%s' % (self._fmt_expr_node(node.obj), node.attribute) else: result = node.name return result def _fmt_arg_defv(self, arg): default_val = arg.default if not default_val: return None try: denv = self.denv # XXX ctval = default_val.compile_time_value(self.denv) repr_val = repr(ctval) if isinstance(default_val, ExprNodes.UnicodeNode): if repr_val[:1] != 'u': return u'u%s' % repr_val elif isinstance(default_val, ExprNodes.BytesNode): if repr_val[:1] != 'b': return u'b%s' % repr_val elif isinstance(default_val, ExprNodes.StringNode): if repr_val[:1] in 'ub': return repr_val[1:] return repr_val except Exception: try: return self._fmt_expr_node(default_val) except AttributeError, e: return '' def _fmt_arg(self, arg): if arg.type is PyrexTypes.py_object_type or arg.is_self_arg: doc = arg.name else: doc = arg.type.declaration_code(arg.name, for_display=1) if arg.default: arg_defv = self._fmt_arg_defv(arg) if arg_defv: doc = doc + ('=%s' % arg_defv) return doc def _fmt_arglist(self, args, npargs=0, pargs=None, nkargs=0, kargs=None, hide_self=False): arglist = [] for arg in args: if not hide_self or not arg.entry.is_self_arg: arg_doc = self._fmt_arg(arg) arglist.append(arg_doc) if pargs: arglist.insert(npargs, '*%s' % pargs.name) elif nkargs: arglist.insert(npargs, '*') if kargs: arglist.append('**%s' % kargs.name) return arglist def _fmt_ret_type(self, ret): if ret is PyrexTypes.py_object_type: return None else: return ret.declaration_code("", for_display=1) def _fmt_signature(self, cls_name, func_name, args, npargs=0, pargs=None, nkargs=0, kargs=None, return_type=None, hide_self=False): arglist = self._fmt_arglist(args, npargs, pargs, nkargs, kargs, hide_self=hide_self) arglist_doc = ', '.join(arglist) func_doc = '%s(%s)' % (func_name, arglist_doc) if cls_name: func_doc = '%s.%s' % (cls_name, func_doc) if return_type: ret_doc = self._fmt_ret_type(return_type) if ret_doc: func_doc = '%s -> %s' % (func_doc, ret_doc) return func_doc def _embed_signature(self, signature, node_doc): if node_doc: return "%s\n%s" % (signature, node_doc) else: return signature def __call__(self, node): if not Options.docstrings: return node else: return super(EmbedSignature, self).__call__(node) def visit_ClassDefNode(self, node): oldname = self.class_name oldclass = self.class_node self.class_node = node try: # PyClassDefNode self.class_name = node.name except AttributeError: # CClassDefNode self.class_name = node.class_name self.visitchildren(node) self.class_name = oldname self.class_node = oldclass return node def visit_DefNode(self, node): if not self.current_directives['embedsignature']: return node is_constructor = False hide_self = False if node.entry.is_special: is_constructor = self.class_node and node.name == '__init__' if not is_constructor: return node class_name, func_name = None, self.class_name hide_self = True else: class_name, func_name = self.class_name, node.name nkargs = getattr(node, 'num_kwonly_args', 0) npargs = len(node.args) - nkargs signature = self._fmt_signature( class_name, func_name, node.args, npargs, node.star_arg, nkargs, node.starstar_arg, return_type=None, hide_self=hide_self) if signature: if is_constructor: doc_holder = self.class_node.entry.type.scope else: doc_holder = node.entry if doc_holder.doc is not None: old_doc = doc_holder.doc elif not is_constructor and getattr(node, 'py_func', None) is not None: old_doc = node.py_func.entry.doc else: old_doc = None new_doc = self._embed_signature(signature, old_doc) doc_holder.doc = EncodedString(new_doc) if not is_constructor and getattr(node, 'py_func', None) is not None: node.py_func.entry.doc = EncodedString(new_doc) return node def visit_CFuncDefNode(self, node): if not self.current_directives['embedsignature']: return node if not node.overridable: # not cpdef FOO(...): return node signature = self._fmt_signature( self.class_name, node.declarator.base.name, node.declarator.args, return_type=node.return_type) if signature: if node.entry.doc is not None: old_doc = node.entry.doc elif getattr(node, 'py_func', None) is not None: old_doc = node.py_func.entry.doc else: old_doc = None new_doc = self._embed_signature(signature, old_doc) node.entry.doc = EncodedString(new_doc) if hasattr(node, 'py_func') and node.py_func is not None: node.py_func.entry.doc = EncodedString(new_doc) return node def visit_PropertyNode(self, node): if not self.current_directives['embedsignature']: return node entry = node.entry if entry.visibility == 'public': # property synthesised from a cdef public attribute type_name = entry.type.declaration_code("", for_display=1) if not entry.type.is_pyobject: type_name = "'%s'" % type_name elif entry.type.is_extension_type: type_name = entry.type.module_name + '.' + type_name signature = '%s: %s' % (entry.name, type_name) new_doc = self._embed_signature(signature, entry.doc) entry.doc = EncodedString(new_doc) return node cython-0.20.1+git90-g0e6e38e/Cython/Compiler/Buffer.py000066400000000000000000000721501231323242300220530ustar00rootroot00000000000000from Cython.Compiler.Visitor import CythonTransform from Cython.Compiler.ModuleNode import ModuleNode from Cython.Compiler.Errors import CompileError from Cython.Compiler.UtilityCode import CythonUtilityCode from Cython.Compiler.Code import UtilityCode, TempitaUtilityCode from Cython.Compiler import Options from Cython.Compiler import Interpreter from Cython.Compiler import PyrexTypes from Cython.Compiler import Naming from Cython.Compiler import Symtab def dedent(text, reindent=0): from textwrap import dedent text = dedent(text) if reindent > 0: indent = " " * reindent text = '\n'.join([indent + x for x in text.split('\n')]) return text class IntroduceBufferAuxiliaryVars(CythonTransform): # # Entry point # buffers_exists = False using_memoryview = False def __call__(self, node): assert isinstance(node, ModuleNode) self.max_ndim = 0 result = super(IntroduceBufferAuxiliaryVars, self).__call__(node) if self.buffers_exists: use_bufstruct_declare_code(node.scope) use_py2_buffer_functions(node.scope) node.scope.use_utility_code(empty_bufstruct_utility) return result # # Basic operations for transforms # def handle_scope(self, node, scope): # For all buffers, insert extra variables in the scope. # The variables are also accessible from the buffer_info # on the buffer entry bufvars = [entry for name, entry in scope.entries.iteritems() if entry.type.is_buffer] if len(bufvars) > 0: bufvars.sort(key=lambda entry: entry.name) self.buffers_exists = True memviewslicevars = [entry for name, entry in scope.entries.iteritems() if entry.type.is_memoryviewslice] if len(memviewslicevars) > 0: self.buffers_exists = True for (name, entry) in scope.entries.iteritems(): if name == 'memoryview' and isinstance(entry.utility_code_definition, CythonUtilityCode): self.using_memoryview = True break if isinstance(node, ModuleNode) and len(bufvars) > 0: # for now...note that pos is wrong raise CompileError(node.pos, "Buffer vars not allowed in module scope") for entry in bufvars: if entry.type.dtype.is_ptr: raise CompileError(node.pos, "Buffers with pointer types not yet supported.") name = entry.name buftype = entry.type if buftype.ndim > Options.buffer_max_dims: raise CompileError(node.pos, "Buffer ndims exceeds Options.buffer_max_dims = %d" % Options.buffer_max_dims) if buftype.ndim > self.max_ndim: self.max_ndim = buftype.ndim # Declare auxiliary vars def decvar(type, prefix): cname = scope.mangle(prefix, name) aux_var = scope.declare_var(name=None, cname=cname, type=type, pos=node.pos) if entry.is_arg: aux_var.used = True # otherwise, NameNode will mark whether it is used return aux_var auxvars = ((PyrexTypes.c_pyx_buffer_nd_type, Naming.pybuffernd_prefix), (PyrexTypes.c_pyx_buffer_type, Naming.pybufferstruct_prefix)) pybuffernd, rcbuffer = [decvar(type, prefix) for (type, prefix) in auxvars] entry.buffer_aux = Symtab.BufferAux(pybuffernd, rcbuffer) scope.buffer_entries = bufvars self.scope = scope def visit_ModuleNode(self, node): self.handle_scope(node, node.scope) self.visitchildren(node) return node def visit_FuncDefNode(self, node): self.handle_scope(node, node.local_scope) self.visitchildren(node) return node # # Analysis # buffer_options = ("dtype", "ndim", "mode", "negative_indices", "cast") # ordered! buffer_defaults = {"ndim": 1, "mode": "full", "negative_indices": True, "cast": False} buffer_positional_options_count = 1 # anything beyond this needs keyword argument ERR_BUF_OPTION_UNKNOWN = '"%s" is not a buffer option' ERR_BUF_TOO_MANY = 'Too many buffer options' ERR_BUF_DUP = '"%s" buffer option already supplied' ERR_BUF_MISSING = '"%s" missing' ERR_BUF_MODE = 'Only allowed buffer modes are: "c", "fortran", "full", "strided" (as a compile-time string)' ERR_BUF_NDIM = 'ndim must be a non-negative integer' ERR_BUF_DTYPE = 'dtype must be "object", numeric type or a struct' ERR_BUF_BOOL = '"%s" must be a boolean' def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, need_complete=True): """ Must be called during type analysis, as analyse is called on the dtype argument. posargs and dictargs should consist of a list and a dict of tuples (value, pos). Defaults should be a dict of values. Returns a dict containing all the options a buffer can have and its value (with the positions stripped). """ if defaults is None: defaults = buffer_defaults posargs, dictargs = Interpreter.interpret_compiletime_options(posargs, dictargs, type_env=env, type_args = (0,'dtype')) if len(posargs) > buffer_positional_options_count: raise CompileError(posargs[-1][1], ERR_BUF_TOO_MANY) options = {} for name, (value, pos) in dictargs.iteritems(): if not name in buffer_options: raise CompileError(pos, ERR_BUF_OPTION_UNKNOWN % name) options[name] = value for name, (value, pos) in zip(buffer_options, posargs): if not name in buffer_options: raise CompileError(pos, ERR_BUF_OPTION_UNKNOWN % name) if name in options: raise CompileError(pos, ERR_BUF_DUP % name) options[name] = value # Check that they are all there and copy defaults for name in buffer_options: if not name in options: try: options[name] = defaults[name] except KeyError: if need_complete: raise CompileError(globalpos, ERR_BUF_MISSING % name) dtype = options.get("dtype") if dtype and dtype.is_extension_type: raise CompileError(globalpos, ERR_BUF_DTYPE) ndim = options.get("ndim") if ndim and (not isinstance(ndim, int) or ndim < 0): raise CompileError(globalpos, ERR_BUF_NDIM) mode = options.get("mode") if mode and not (mode in ('full', 'strided', 'c', 'fortran')): raise CompileError(globalpos, ERR_BUF_MODE) def assert_bool(name): x = options.get(name) if not isinstance(x, bool): raise CompileError(globalpos, ERR_BUF_BOOL % name) assert_bool('negative_indices') assert_bool('cast') return options # # Code generation # class BufferEntry(object): def __init__(self, entry): self.entry = entry self.type = entry.type self.cname = entry.buffer_aux.buflocal_nd_var.cname self.buf_ptr = "%s.rcbuffer->pybuffer.buf" % self.cname self.buf_ptr_type = self.entry.type.buffer_ptr_type def get_buf_suboffsetvars(self): return self._for_all_ndim("%s.diminfo[%d].suboffsets") def get_buf_stridevars(self): return self._for_all_ndim("%s.diminfo[%d].strides") def get_buf_shapevars(self): return self._for_all_ndim("%s.diminfo[%d].shape") def _for_all_ndim(self, s): return [s % (self.cname, i) for i in range(self.type.ndim)] def generate_buffer_lookup_code(self, code, index_cnames): # Create buffer lookup and return it # This is done via utility macros/inline functions, which vary # according to the access mode used. params = [] nd = self.type.ndim mode = self.type.mode if mode == 'full': for i, s, o in zip(index_cnames, self.get_buf_stridevars(), self.get_buf_suboffsetvars()): params.append(i) params.append(s) params.append(o) funcname = "__Pyx_BufPtrFull%dd" % nd funcgen = buf_lookup_full_code else: if mode == 'strided': funcname = "__Pyx_BufPtrStrided%dd" % nd funcgen = buf_lookup_strided_code elif mode == 'c': funcname = "__Pyx_BufPtrCContig%dd" % nd funcgen = buf_lookup_c_code elif mode == 'fortran': funcname = "__Pyx_BufPtrFortranContig%dd" % nd funcgen = buf_lookup_fortran_code else: assert False for i, s in zip(index_cnames, self.get_buf_stridevars()): params.append(i) params.append(s) # Make sure the utility code is available if funcname not in code.globalstate.utility_codes: code.globalstate.utility_codes.add(funcname) protocode = code.globalstate['utility_code_proto'] defcode = code.globalstate['utility_code_def'] funcgen(protocode, defcode, name=funcname, nd=nd) buf_ptr_type_code = self.buf_ptr_type.declaration_code("") ptrcode = "%s(%s, %s, %s)" % (funcname, buf_ptr_type_code, self.buf_ptr, ", ".join(params)) return ptrcode def get_flags(buffer_aux, buffer_type): flags = 'PyBUF_FORMAT' mode = buffer_type.mode if mode == 'full': flags += '| PyBUF_INDIRECT' elif mode == 'strided': flags += '| PyBUF_STRIDES' elif mode == 'c': flags += '| PyBUF_C_CONTIGUOUS' elif mode == 'fortran': flags += '| PyBUF_F_CONTIGUOUS' else: assert False if buffer_aux.writable_needed: flags += "| PyBUF_WRITABLE" return flags def used_buffer_aux_vars(entry): buffer_aux = entry.buffer_aux buffer_aux.buflocal_nd_var.used = True buffer_aux.rcbuf_var.used = True def put_unpack_buffer_aux_into_scope(buf_entry, code): # Generate code to copy the needed struct info into local # variables. buffer_aux, mode = buf_entry.buffer_aux, buf_entry.type.mode pybuffernd_struct = buffer_aux.buflocal_nd_var.cname fldnames = ['strides', 'shape'] if mode == 'full': fldnames.append('suboffsets') ln = [] for i in range(buf_entry.type.ndim): for fldname in fldnames: ln.append("%s.diminfo[%d].%s = %s.rcbuffer->pybuffer.%s[%d];" % \ (pybuffernd_struct, i, fldname, pybuffernd_struct, fldname, i)) code.putln(' '.join(ln)) def put_init_vars(entry, code): bufaux = entry.buffer_aux pybuffernd_struct = bufaux.buflocal_nd_var.cname pybuffer_struct = bufaux.rcbuf_var.cname # init pybuffer_struct code.putln("%s.pybuffer.buf = NULL;" % pybuffer_struct) code.putln("%s.refcount = 0;" % pybuffer_struct) # init the buffer object # code.put_init_var_to_py_none(entry) # init the pybuffernd_struct code.putln("%s.data = NULL;" % pybuffernd_struct) code.putln("%s.rcbuffer = &%s;" % (pybuffernd_struct, pybuffer_struct)) def put_acquire_arg_buffer(entry, code, pos): code.globalstate.use_utility_code(acquire_utility_code) buffer_aux = entry.buffer_aux getbuffer = get_getbuffer_call(code, entry.cname, buffer_aux, entry.type) # Acquire any new buffer code.putln("{") code.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % entry.type.dtype.struct_nesting_depth()) code.putln(code.error_goto_if("%s == -1" % getbuffer, pos)) code.putln("}") # An exception raised in arg parsing cannot be catched, so no # need to care about the buffer then. put_unpack_buffer_aux_into_scope(entry, code) def put_release_buffer_code(code, entry): code.globalstate.use_utility_code(acquire_utility_code) code.putln("__Pyx_SafeReleaseBuffer(&%s.rcbuffer->pybuffer);" % entry.buffer_aux.buflocal_nd_var.cname) def get_getbuffer_call(code, obj_cname, buffer_aux, buffer_type): ndim = buffer_type.ndim cast = int(buffer_type.cast) flags = get_flags(buffer_aux, buffer_type) pybuffernd_struct = buffer_aux.buflocal_nd_var.cname dtype_typeinfo = get_type_information_cname(code, buffer_type.dtype) return ("__Pyx_GetBufferAndValidate(&%(pybuffernd_struct)s.rcbuffer->pybuffer, " "(PyObject*)%(obj_cname)s, &%(dtype_typeinfo)s, %(flags)s, %(ndim)d, " "%(cast)d, __pyx_stack)" % locals()) def put_assign_to_buffer(lhs_cname, rhs_cname, buf_entry, is_initialized, pos, code): """ Generate code for reassigning a buffer variables. This only deals with getting the buffer auxiliary structure and variables set up correctly, the assignment itself and refcounting is the responsibility of the caller. However, the assignment operation may throw an exception so that the reassignment never happens. Depending on the circumstances there are two possible outcomes: - Old buffer released, new acquired, rhs assigned to lhs - Old buffer released, new acquired which fails, reaqcuire old lhs buffer (which may or may not succeed). """ buffer_aux, buffer_type = buf_entry.buffer_aux, buf_entry.type code.globalstate.use_utility_code(acquire_utility_code) pybuffernd_struct = buffer_aux.buflocal_nd_var.cname flags = get_flags(buffer_aux, buffer_type) code.putln("{") # Set up necesarry stack for getbuffer code.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % buffer_type.dtype.struct_nesting_depth()) getbuffer = get_getbuffer_call(code, "%s", buffer_aux, buffer_type) # fill in object below if is_initialized: # Release any existing buffer code.putln('__Pyx_SafeReleaseBuffer(&%s.rcbuffer->pybuffer);' % pybuffernd_struct) # Acquire retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname)) code.putln('if (%s) {' % (code.unlikely("%s < 0" % retcode_cname))) # If acquisition failed, attempt to reacquire the old buffer # before raising the exception. A failure of reacquisition # will cause the reacquisition exception to be reported, one # can consider working around this later. type, value, tb = [code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=False) for i in range(3)] code.putln('PyErr_Fetch(&%s, &%s, &%s);' % (type, value, tb)) code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % lhs_cname))) code.putln('Py_XDECREF(%s); Py_XDECREF(%s); Py_XDECREF(%s);' % (type, value, tb)) # Do not refnanny these! code.globalstate.use_utility_code(raise_buffer_fallback_code) code.putln('__Pyx_RaiseBufferFallbackError();') code.putln('} else {') code.putln('PyErr_Restore(%s, %s, %s);' % (type, value, tb)) for t in (type, value, tb): code.funcstate.release_temp(t) code.putln('}') code.putln('}') # Unpack indices put_unpack_buffer_aux_into_scope(buf_entry, code) code.putln(code.error_goto_if_neg(retcode_cname, pos)) code.funcstate.release_temp(retcode_cname) else: # Our entry had no previous value, so set to None when acquisition fails. # In this case, auxiliary vars should be set up right in initialization to a zero-buffer, # so it suffices to set the buf field to NULL. code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % rhs_cname))) code.putln('%s = %s; __Pyx_INCREF(Py_None); %s.rcbuffer->pybuffer.buf = NULL;' % (lhs_cname, PyrexTypes.typecast(buffer_type, PyrexTypes.py_object_type, "Py_None"), pybuffernd_struct)) code.putln(code.error_goto(pos)) code.put('} else {') # Unpack indices put_unpack_buffer_aux_into_scope(buf_entry, code) code.putln('}') code.putln("}") # Release stack def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos, code, negative_indices, in_nogil_context): """ Generates code to process indices and calculate an offset into a buffer. Returns a C string which gives a pointer which can be read from or written to at will (it is an expression so caller should store it in a temporary if it is used more than once). As the bounds checking can have any number of combinations of unsigned arguments, smart optimizations etc. we insert it directly in the function body. The lookup however is delegated to a inline function that is instantiated once per ndim (lookup with suboffsets tend to get quite complicated). entry is a BufferEntry """ negative_indices = directives['wraparound'] and negative_indices if directives['boundscheck']: # Check bounds and fix negative indices. # We allocate a temporary which is initialized to -1, meaning OK (!). # If an error occurs, the temp is set to the dimension index the # error is occuring at. tmp_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) code.putln("%s = -1;" % tmp_cname) for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames, entry.get_buf_shapevars())): if signed != 0: # not unsigned, deal with negative index code.putln("if (%s < 0) {" % cname) if negative_indices: code.putln("%s += %s;" % (cname, shape)) code.putln("if (%s) %s = %d;" % ( code.unlikely("%s < 0" % cname), tmp_cname, dim)) else: code.putln("%s = %d;" % (tmp_cname, dim)) code.put("} else ") # check bounds in positive direction if signed != 0: cast = "" else: cast = "(size_t)" code.putln("if (%s) %s = %d;" % ( code.unlikely("%s >= %s%s" % (cname, cast, shape)), tmp_cname, dim)) if in_nogil_context: code.globalstate.use_utility_code(raise_indexerror_nogil) func = '__Pyx_RaiseBufferIndexErrorNogil' else: code.globalstate.use_utility_code(raise_indexerror_code) func = '__Pyx_RaiseBufferIndexError' code.putln("if (%s) {" % code.unlikely("%s != -1" % tmp_cname)) code.putln('%s(%s);' % (func, tmp_cname)) code.putln(code.error_goto(pos)) code.putln('}') code.funcstate.release_temp(tmp_cname) elif negative_indices: # Only fix negative indices. for signed, cname, shape in zip(index_signeds, index_cnames, entry.get_buf_shapevars()): if signed != 0: code.putln("if (%s < 0) %s += %s;" % (cname, cname, shape)) return entry.generate_buffer_lookup_code(code, index_cnames) def use_bufstruct_declare_code(env): env.use_utility_code(buffer_struct_declare_code) def get_empty_bufstruct_code(max_ndim): code = dedent(""" static Py_ssize_t __Pyx_zeros[] = {%s}; static Py_ssize_t __Pyx_minusones[] = {%s}; """) % (", ".join(["0"] * max_ndim), ", ".join(["-1"] * max_ndim)) return UtilityCode(proto=code) empty_bufstruct_utility = get_empty_bufstruct_code(Options.buffer_max_dims) def buf_lookup_full_code(proto, defin, name, nd): """ Generates a buffer lookup function for the right number of dimensions. The function gives back a void* at the right location. """ # _i_ndex, _s_tride, sub_o_ffset macroargs = ", ".join(["i%d, s%d, o%d" % (i, i, i) for i in range(nd)]) proto.putln("#define %s(type, buf, %s) (type)(%s_imp(buf, %s))" % (name, macroargs, name, macroargs)) funcargs = ", ".join(["Py_ssize_t i%d, Py_ssize_t s%d, Py_ssize_t o%d" % (i, i, i) for i in range(nd)]) proto.putln("static CYTHON_INLINE void* %s_imp(void* buf, %s);" % (name, funcargs)) defin.putln(dedent(""" static CYTHON_INLINE void* %s_imp(void* buf, %s) { char* ptr = (char*)buf; """) % (name, funcargs) + "".join([dedent("""\ ptr += s%d * i%d; if (o%d >= 0) ptr = *((char**)ptr) + o%d; """) % (i, i, i, i) for i in range(nd)] ) + "\nreturn ptr;\n}") def buf_lookup_strided_code(proto, defin, name, nd): """ Generates a buffer lookup function for the right number of dimensions. The function gives back a void* at the right location. """ # _i_ndex, _s_tride args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)]) offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd)]) proto.putln("#define %s(type, buf, %s) (type)((char*)buf + %s)" % (name, args, offset)) def buf_lookup_c_code(proto, defin, name, nd): """ Similar to strided lookup, but can assume that the last dimension doesn't need a multiplication as long as. Still we keep the same signature for now. """ if nd == 1: proto.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name) else: args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)]) offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd - 1)]) proto.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name, args, offset, nd - 1)) def buf_lookup_fortran_code(proto, defin, name, nd): """ Like C lookup, but the first index is optimized instead. """ if nd == 1: proto.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name) else: args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)]) offset = " + ".join(["i%d * s%d" % (i, i) for i in range(1, nd)]) proto.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name, args, offset, 0)) def use_py2_buffer_functions(env): env.use_utility_code(GetAndReleaseBufferUtilityCode()) class GetAndReleaseBufferUtilityCode(object): # Emulation of PyObject_GetBuffer and PyBuffer_Release for Python 2. # For >= 2.6 we do double mode -- use the new buffer interface on objects # which has the right tp_flags set, but emulation otherwise. requires = None is_cython_utility = False def __init__(self): pass def __eq__(self, other): return isinstance(other, GetAndReleaseBufferUtilityCode) def __hash__(self): return 24342342 def get_tree(self): pass def put_code(self, output): code = output['utility_code_def'] proto_code = output['utility_code_proto'] env = output.module_node.scope cython_scope = env.context.cython_scope # Search all types for __getbuffer__ overloads types = [] visited_scopes = set() def find_buffer_types(scope): if scope in visited_scopes: return visited_scopes.add(scope) for m in scope.cimported_modules: find_buffer_types(m) for e in scope.type_entries: if isinstance(e.utility_code_definition, CythonUtilityCode): continue t = e.type if t.is_extension_type: if scope is cython_scope and not e.used: continue release = get = None for x in t.scope.pyfunc_entries: if x.name == u"__getbuffer__": get = x.func_cname elif x.name == u"__releasebuffer__": release = x.func_cname if get: types.append((t.typeptr_cname, get, release)) find_buffer_types(env) util_code = TempitaUtilityCode.load( "GetAndReleaseBuffer", from_file="Buffer.c", context=dict(types=types)) proto = util_code.format_code(util_code.proto) impl = util_code.format_code( util_code.inject_string_constants(util_code.impl, output)[1]) proto_code.putln(proto) code.putln(impl) def mangle_dtype_name(dtype): # Use prefixes to seperate user defined types from builtins # (consider "typedef float unsigned_int") if dtype.is_pyobject: return "object" elif dtype.is_ptr: return "ptr" else: if dtype.is_typedef or dtype.is_struct_or_union: prefix = "nn_" else: prefix = "" type_decl = dtype.declaration_code("") type_decl = type_decl.replace(" ", "_") return prefix + type_decl.replace("[", "_").replace("]", "_") def get_type_information_cname(code, dtype, maxdepth=None): """ Output the run-time type information (__Pyx_TypeInfo) for given dtype, and return the name of the type info struct. Structs with two floats of the same size are encoded as complex numbers. One can seperate between complex numbers declared as struct or with native encoding by inspecting to see if the fields field of the type is filled in. """ namesuffix = mangle_dtype_name(dtype) name = "__Pyx_TypeInfo_%s" % namesuffix structinfo_name = "__Pyx_StructFields_%s" % namesuffix if dtype.is_error: return "" # It's critical that walking the type info doesn't use more stack # depth than dtype.struct_nesting_depth() returns, so use an assertion for this if maxdepth is None: maxdepth = dtype.struct_nesting_depth() if maxdepth <= 0: assert False if name not in code.globalstate.utility_codes: code.globalstate.utility_codes.add(name) typecode = code.globalstate['typeinfo'] arraysizes = [] if dtype.is_array: while dtype.is_array: arraysizes.append(dtype.size) dtype = dtype.base_type complex_possible = dtype.is_struct_or_union and dtype.can_be_complex() declcode = dtype.declaration_code("") if dtype.is_simple_buffer_dtype(): structinfo_name = "NULL" elif dtype.is_struct: fields = dtype.scope.var_entries # Must pre-call all used types in order not to recurse utility code # writing. assert len(fields) > 0 types = [get_type_information_cname(code, f.type, maxdepth - 1) for f in fields] typecode.putln("static __Pyx_StructField %s[] = {" % structinfo_name, safe=True) for f, typeinfo in zip(fields, types): typecode.putln(' {&%s, "%s", offsetof(%s, %s)},' % (typeinfo, f.name, dtype.declaration_code(""), f.cname), safe=True) typecode.putln(' {NULL, NULL, 0}', safe=True) typecode.putln("};", safe=True) else: assert False rep = str(dtype) flags = "0" is_unsigned = "0" if dtype is PyrexTypes.c_char_type: is_unsigned = "IS_UNSIGNED(%s)" % declcode typegroup = "'H'" elif dtype.is_int: is_unsigned = "IS_UNSIGNED(%s)" % declcode typegroup = "%s ? 'U' : 'I'" % is_unsigned elif complex_possible or dtype.is_complex: typegroup = "'C'" elif dtype.is_float: typegroup = "'R'" elif dtype.is_struct: typegroup = "'S'" if dtype.packed: flags = "__PYX_BUF_FLAGS_PACKED_STRUCT" elif dtype.is_pyobject: typegroup = "'O'" else: assert False, dtype typeinfo = ('static __Pyx_TypeInfo %s = ' '{ "%s", %s, sizeof(%s), { %s }, %s, %s, %s, %s };') tup = (name, rep, structinfo_name, declcode, ', '.join([str(x) for x in arraysizes]) or '0', len(arraysizes), typegroup, is_unsigned, flags) typecode.putln(typeinfo % tup, safe=True) return name def load_buffer_utility(util_code_name, context=None, **kwargs): if context is None: return UtilityCode.load(util_code_name, "Buffer.c", **kwargs) else: return TempitaUtilityCode.load(util_code_name, "Buffer.c", context=context, **kwargs) context = dict(max_dims=str(Options.buffer_max_dims)) buffer_struct_declare_code = load_buffer_utility("BufferStructDeclare", context=context) # Utility function to set the right exception # The caller should immediately goto_error raise_indexerror_code = load_buffer_utility("BufferIndexError") raise_indexerror_nogil = load_buffer_utility("BufferIndexErrorNogil") raise_buffer_fallback_code = load_buffer_utility("BufferFallbackError") buffer_structs_code = load_buffer_utility( "BufferFormatStructs", proto_block='utility_code_proto_before_types') acquire_utility_code = load_buffer_utility("BufferFormatCheck", context=context, requires=[buffer_structs_code]) # See utility code BufferFormatFromTypeInfo _typeinfo_to_format_code = load_buffer_utility("TypeInfoToFormat", context={}, requires=[buffer_structs_code]) typeinfo_compare_code = load_buffer_utility("TypeInfoCompare", context={}, requires=[buffer_structs_code]) cython-0.20.1+git90-g0e6e38e/Cython/Compiler/Builtin.py000066400000000000000000000476061231323242300222600ustar00rootroot00000000000000# # Builtin Definitions # from Symtab import BuiltinScope, StructOrUnionScope from Code import UtilityCode from TypeSlots import Signature import PyrexTypes import Options # C-level implementations of builtin types, functions and methods iter_next_utility_code = UtilityCode.load("IterNext", "ObjectHandling.c") getattr_utility_code = UtilityCode.load("GetAttr", "ObjectHandling.c") getattr3_utility_code = UtilityCode.load("GetAttr3", "Builtins.c") pyexec_utility_code = UtilityCode.load("PyExec", "Builtins.c") pyexec_globals_utility_code = UtilityCode.load("PyExecGlobals", "Builtins.c") globals_utility_code = UtilityCode.load("Globals", "Builtins.c") py_set_utility_code = UtilityCode.load("pyset_compat", "Builtins.c") builtin_utility_code = { 'set' : py_set_utility_code, 'frozenset' : py_set_utility_code, } # mapping from builtins to their C-level equivalents class _BuiltinOverride(object): def __init__(self, py_name, args, ret_type, cname, py_equiv="*", utility_code=None, sig=None, func_type=None, is_strict_signature=False, builtin_return_type=None): self.py_name, self.cname, self.py_equiv = py_name, cname, py_equiv self.args, self.ret_type = args, ret_type self.func_type, self.sig = func_type, sig self.builtin_return_type = builtin_return_type self.is_strict_signature = is_strict_signature self.utility_code = utility_code def build_func_type(self, sig=None, self_arg=None): if sig is None: sig = Signature(self.args, self.ret_type) sig.exception_check = False # not needed for the current builtins func_type = sig.function_type(self_arg) if self.is_strict_signature: func_type.is_strict_signature = True if self.builtin_return_type: func_type.return_type = builtin_types[self.builtin_return_type] return func_type class BuiltinAttribute(object): def __init__(self, py_name, cname=None, field_type=None, field_type_name=None): self.py_name = py_name self.cname = cname or py_name self.field_type_name = field_type_name # can't do the lookup before the type is declared! self.field_type = field_type def declare_in_type(self, self_type): if self.field_type_name is not None: # lazy type lookup field_type = builtin_scope.lookup(self.field_type_name).type else: field_type = self.field_type or PyrexTypes.py_object_type entry = self_type.scope.declare(self.py_name, self.cname, field_type, None, 'private') entry.is_variable = True class BuiltinFunction(_BuiltinOverride): def declare_in_scope(self, scope): func_type, sig = self.func_type, self.sig if func_type is None: func_type = self.build_func_type(sig) scope.declare_builtin_cfunction(self.py_name, func_type, self.cname, self.py_equiv, self.utility_code) class BuiltinMethod(_BuiltinOverride): def declare_in_type(self, self_type): method_type, sig = self.func_type, self.sig if method_type is None: # override 'self' type (first argument) self_arg = PyrexTypes.CFuncTypeArg("", self_type, None) self_arg.not_none = True self_arg.accept_builtin_subtypes = True method_type = self.build_func_type(sig, self_arg) self_type.scope.declare_builtin_cfunction( self.py_name, method_type, self.cname, utility_code=self.utility_code) builtin_function_table = [ # name, args, return, C API func, py equiv = "*" BuiltinFunction('abs', "d", "d", "fabs", is_strict_signature = True), BuiltinFunction('abs', "f", "f", "fabsf", is_strict_signature = True), BuiltinFunction('abs', None, None, "__Pyx_abs_int", utility_code = UtilityCode.load("abs_int", "Builtins.c"), func_type = PyrexTypes.CFuncType( PyrexTypes.c_uint_type, [ PyrexTypes.CFuncTypeArg("arg", PyrexTypes.c_int_type, None) ], is_strict_signature = True)), BuiltinFunction('abs', None, None, "__Pyx_abs_long", utility_code = UtilityCode.load("abs_long", "Builtins.c"), func_type = PyrexTypes.CFuncType( PyrexTypes.c_ulong_type, [ PyrexTypes.CFuncTypeArg("arg", PyrexTypes.c_long_type, None) ], is_strict_signature = True)), BuiltinFunction('abs', None, None, "__Pyx_abs_longlong", utility_code = UtilityCode.load("abs_longlong", "Builtins.c"), func_type = PyrexTypes.CFuncType( PyrexTypes.c_ulonglong_type, [ PyrexTypes.CFuncTypeArg("arg", PyrexTypes.c_longlong_type, None) ], is_strict_signature = True)), BuiltinFunction('abs', "O", "O", "PyNumber_Absolute"), BuiltinFunction('callable', "O", "b", "__Pyx_PyCallable_Check", utility_code = UtilityCode.load("CallableCheck", "ObjectHandling.c")), #('chr', "", "", ""), #('cmp', "", "", "", ""), # int PyObject_Cmp(PyObject *o1, PyObject *o2, int *result) #('compile', "", "", ""), # PyObject* Py_CompileString( char *str, char *filename, int start) BuiltinFunction('delattr', "OO", "r", "PyObject_DelAttr"), BuiltinFunction('dir', "O", "O", "PyObject_Dir"), BuiltinFunction('divmod', "OO", "O", "PyNumber_Divmod"), BuiltinFunction('exec', "O", "O", "__Pyx_PyExecGlobals", utility_code = pyexec_globals_utility_code), BuiltinFunction('exec', "OO", "O", "__Pyx_PyExec2", utility_code = pyexec_utility_code), BuiltinFunction('exec', "OOO", "O", "__Pyx_PyExec3", utility_code = pyexec_utility_code), #('eval', "", "", ""), #('execfile', "", "", ""), #('filter', "", "", ""), BuiltinFunction('getattr3', "OOO", "O", "__Pyx_GetAttr3", "getattr", utility_code=getattr3_utility_code), # Pyrex legacy BuiltinFunction('getattr', "OOO", "O", "__Pyx_GetAttr3", utility_code=getattr3_utility_code), BuiltinFunction('getattr', "OO", "O", "__Pyx_GetAttr", utility_code=getattr_utility_code), BuiltinFunction('hasattr', "OO", "b", "PyObject_HasAttr"), BuiltinFunction('hash', "O", "h", "PyObject_Hash"), #('hex', "", "", ""), #('id', "", "", ""), #('input', "", "", ""), BuiltinFunction('intern', "O", "O", "__Pyx_Intern", utility_code = UtilityCode.load("Intern", "Builtins.c")), BuiltinFunction('isinstance', "OO", "b", "PyObject_IsInstance"), BuiltinFunction('issubclass', "OO", "b", "PyObject_IsSubclass"), BuiltinFunction('iter', "OO", "O", "PyCallIter_New"), BuiltinFunction('iter', "O", "O", "PyObject_GetIter"), BuiltinFunction('len', "O", "z", "PyObject_Length"), BuiltinFunction('locals', "", "O", "__pyx_locals"), #('map', "", "", ""), #('max', "", "", ""), #('min', "", "", ""), BuiltinFunction('next', "O", "O", "__Pyx_PyIter_Next", utility_code = iter_next_utility_code), # not available in Py2 => implemented here BuiltinFunction('next', "OO", "O", "__Pyx_PyIter_Next2", utility_code = iter_next_utility_code), # not available in Py2 => implemented here #('oct', "", "", ""), #('open', "ss", "O", "PyFile_FromString"), # not in Py3 #('ord', "", "", ""), BuiltinFunction('pow', "OOO", "O", "PyNumber_Power"), BuiltinFunction('pow', "OO", "O", "__Pyx_PyNumber_Power2", utility_code = UtilityCode.load("pow2", "Builtins.c")), #('range', "", "", ""), #('raw_input', "", "", ""), #('reduce', "", "", ""), BuiltinFunction('reload', "O", "O", "PyImport_ReloadModule"), BuiltinFunction('repr', "O", "O", "PyObject_Repr", builtin_return_type='str'), #('round', "", "", ""), BuiltinFunction('setattr', "OOO", "r", "PyObject_SetAttr"), #('sum', "", "", ""), #('type', "O", "O", "PyObject_Type"), #('unichr', "", "", ""), #('unicode', "", "", ""), #('vars', "", "", ""), #('zip', "", "", ""), # Can't do these easily until we have builtin type entries. #('typecheck', "OO", "i", "PyObject_TypeCheck", False), #('issubtype', "OO", "i", "PyType_IsSubtype", False), # Put in namespace append optimization. BuiltinFunction('__Pyx_PyObject_Append', "OO", "O", "__Pyx_PyObject_Append"), ] if not Options.old_style_globals: builtin_function_table.append( BuiltinFunction('globals', "", "O", "__Pyx_Globals", utility_code=globals_utility_code)) # Builtin types # bool # buffer # classmethod # dict # enumerate # file # float # int # list # long # object # property # slice # staticmethod # super # str # tuple # type # xrange builtin_types_table = [ ("type", "PyType_Type", []), # This conflicts with the C++ bool type, and unfortunately # C++ is too liberal about PyObject* <-> bool conversions, # resulting in unintuitive runtime behavior and segfaults. # ("bool", "PyBool_Type", []), ("int", "PyInt_Type", []), ("long", "PyLong_Type", []), ("float", "PyFloat_Type", []), ("complex", "PyComplex_Type", [BuiltinAttribute('cval', field_type_name = 'Py_complex'), BuiltinAttribute('real', 'cval.real', field_type = PyrexTypes.c_double_type), BuiltinAttribute('imag', 'cval.imag', field_type = PyrexTypes.c_double_type), ]), ("basestring", "PyBaseString_Type", [ BuiltinMethod("join", "TO", "T", "__Pyx_PyBaseString_Join", utility_code=UtilityCode.load("StringJoin", "StringTools.c")), ]), ("bytearray", "PyByteArray_Type", [ ]), ("bytes", "PyBytes_Type", [BuiltinMethod("__contains__", "TO", "b", "PySequence_Contains"), BuiltinMethod("join", "TO", "O", "__Pyx_PyBytes_Join", utility_code=UtilityCode.load("StringJoin", "StringTools.c")), ]), ("str", "PyString_Type", [BuiltinMethod("__contains__", "TO", "b", "PySequence_Contains"), BuiltinMethod("join", "TO", "O", "__Pyx_PyString_Join", builtin_return_type='basestring', utility_code=UtilityCode.load("StringJoin", "StringTools.c")), ]), ("unicode", "PyUnicode_Type", [BuiltinMethod("__contains__", "TO", "b", "PyUnicode_Contains"), BuiltinMethod("join", "TO", "T", "PyUnicode_Join"), ]), ("tuple", "PyTuple_Type", [BuiltinMethod("__contains__", "TO", "b", "PySequence_Contains"), ]), ("list", "PyList_Type", [BuiltinMethod("__contains__", "TO", "b", "PySequence_Contains"), BuiltinMethod("insert", "TzO", "r", "PyList_Insert"), BuiltinMethod("reverse", "T", "r", "PyList_Reverse"), BuiltinMethod("append", "TO", "r", "__Pyx_PyList_Append", utility_code=UtilityCode.load("ListAppend", "Optimize.c")), BuiltinMethod("extend", "TO", "r", "__Pyx_PyList_Extend", utility_code=UtilityCode.load("ListExtend", "Optimize.c")), ]), ("dict", "PyDict_Type", [BuiltinMethod("__contains__", "TO", "b", "PyDict_Contains"), BuiltinMethod("has_key", "TO", "b", "PyDict_Contains"), BuiltinMethod("items", "T", "O", "__Pyx_PyDict_Items", utility_code=UtilityCode.load("py_dict_items", "Builtins.c")), BuiltinMethod("keys", "T", "O", "__Pyx_PyDict_Keys", utility_code=UtilityCode.load("py_dict_keys", "Builtins.c")), BuiltinMethod("values", "T", "O", "__Pyx_PyDict_Values", utility_code=UtilityCode.load("py_dict_values", "Builtins.c")), BuiltinMethod("iteritems", "T", "O", "__Pyx_PyDict_IterItems", utility_code=UtilityCode.load("py_dict_iteritems", "Builtins.c")), BuiltinMethod("iterkeys", "T", "O", "__Pyx_PyDict_IterKeys", utility_code=UtilityCode.load("py_dict_iterkeys", "Builtins.c")), BuiltinMethod("itervalues", "T", "O", "__Pyx_PyDict_IterValues", utility_code=UtilityCode.load("py_dict_itervalues", "Builtins.c")), BuiltinMethod("viewitems", "T", "O", "__Pyx_PyDict_ViewItems", utility_code=UtilityCode.load("py_dict_viewitems", "Builtins.c")), BuiltinMethod("viewkeys", "T", "O", "__Pyx_PyDict_ViewKeys", utility_code=UtilityCode.load("py_dict_viewkeys", "Builtins.c")), BuiltinMethod("viewvalues", "T", "O", "__Pyx_PyDict_ViewValues", utility_code=UtilityCode.load("py_dict_viewvalues", "Builtins.c")), BuiltinMethod("clear", "T", "r", "__Pyx_PyDict_Clear", utility_code=UtilityCode.load("py_dict_clear", "Optimize.c")), BuiltinMethod("copy", "T", "T", "PyDict_Copy")]), ("slice", "PySlice_Type", [BuiltinAttribute('start'), BuiltinAttribute('stop'), BuiltinAttribute('step'), ]), # ("file", "PyFile_Type", []), # not in Py3 ("set", "PySet_Type", [BuiltinMethod("__contains__", "TO", "b", "PySequence_Contains"), BuiltinMethod("clear", "T", "r", "PySet_Clear", utility_code = py_set_utility_code), # discard() and remove() have a special treatment for unhashable values # BuiltinMethod("discard", "TO", "r", "PySet_Discard", # utility_code = py_set_utility_code), BuiltinMethod("add", "TO", "r", "PySet_Add", utility_code = py_set_utility_code), BuiltinMethod("pop", "T", "O", "PySet_Pop", utility_code = py_set_utility_code)]), ("frozenset", "PyFrozenSet_Type", []), ] types_that_construct_their_instance = set([ # some builtin types do not always return an instance of # themselves - these do: 'type', 'bool', 'long', 'float', 'complex', 'bytes', 'unicode', 'bytearray', 'tuple', 'list', 'dict', 'set', 'frozenset' # 'str', # only in Py3.x # 'file', # only in Py2.x ]) builtin_structs_table = [ ('Py_buffer', 'Py_buffer', [("buf", PyrexTypes.c_void_ptr_type), ("obj", PyrexTypes.py_object_type), ("len", PyrexTypes.c_py_ssize_t_type), ("itemsize", PyrexTypes.c_py_ssize_t_type), ("readonly", PyrexTypes.c_bint_type), ("ndim", PyrexTypes.c_int_type), ("format", PyrexTypes.c_char_ptr_type), ("shape", PyrexTypes.c_py_ssize_t_ptr_type), ("strides", PyrexTypes.c_py_ssize_t_ptr_type), ("suboffsets", PyrexTypes.c_py_ssize_t_ptr_type), ("smalltable", PyrexTypes.CArrayType(PyrexTypes.c_py_ssize_t_type, 2)), ("internal", PyrexTypes.c_void_ptr_type), ]), ('Py_complex', 'Py_complex', [('real', PyrexTypes.c_double_type), ('imag', PyrexTypes.c_double_type), ]) ] # set up builtin scope builtin_scope = BuiltinScope() def init_builtin_funcs(): for bf in builtin_function_table: bf.declare_in_scope(builtin_scope) builtin_types = {} def init_builtin_types(): global builtin_types for name, cname, methods in builtin_types_table: utility = builtin_utility_code.get(name) if name == 'frozenset': objstruct_cname = 'PySetObject' elif name == 'bool': objstruct_cname = None else: objstruct_cname = 'Py%sObject' % name.capitalize() the_type = builtin_scope.declare_builtin_type(name, cname, utility, objstruct_cname) builtin_types[name] = the_type for method in methods: method.declare_in_type(the_type) def init_builtin_structs(): for name, cname, attribute_types in builtin_structs_table: scope = StructOrUnionScope(name) for attribute_name, attribute_type in attribute_types: scope.declare_var(attribute_name, attribute_type, None, attribute_name, allow_pyobject=True) builtin_scope.declare_struct_or_union( name, "struct", scope, 1, None, cname = cname) def init_builtins(): init_builtin_structs() init_builtin_types() init_builtin_funcs() builtin_scope.declare_var( '__debug__', PyrexTypes.c_const_type(PyrexTypes.c_bint_type), pos=None, cname='(!Py_OptimizeFlag)', is_cdef=True) global list_type, tuple_type, dict_type, set_type, frozenset_type global bytes_type, str_type, unicode_type, basestring_type, slice_type global float_type, bool_type, type_type, complex_type, bytearray_type type_type = builtin_scope.lookup('type').type list_type = builtin_scope.lookup('list').type tuple_type = builtin_scope.lookup('tuple').type dict_type = builtin_scope.lookup('dict').type set_type = builtin_scope.lookup('set').type frozenset_type = builtin_scope.lookup('frozenset').type slice_type = builtin_scope.lookup('slice').type bytes_type = builtin_scope.lookup('bytes').type str_type = builtin_scope.lookup('str').type unicode_type = builtin_scope.lookup('unicode').type basestring_type = builtin_scope.lookup('basestring').type bytearray_type = builtin_scope.lookup('bytearray').type float_type = builtin_scope.lookup('float').type bool_type = builtin_scope.lookup('bool').type complex_type = builtin_scope.lookup('complex').type init_builtins() cython-0.20.1+git90-g0e6e38e/Cython/Compiler/CmdLine.py000066400000000000000000000177771231323242300221730ustar00rootroot00000000000000# # Cython - Command Line Parsing # import os import sys import Options usage = """\ Cython (http://cython.org) is a compiler for code written in the Cython language. Cython is based on Pyrex by Greg Ewing. Usage: cython [options] sourcefile.{pyx,py} ... Options: -V, --version Display version number of cython compiler -l, --create-listing Write error messages to a listing file -I, --include-dir Search for include files in named directory (multiple include directories are allowed). -o, --output-file Specify name of generated C file -t, --timestamps Only compile newer source files -f, --force Compile all source files (overrides implied -t) -v, --verbose Be verbose, print file names on multiple compilation -p, --embed-positions If specified, the positions in Cython files of each function definition is embedded in its docstring. --cleanup Release interned objects on python exit, for memory debugging. Level indicates aggressiveness, default 0 releases nothing. -w, --working Sets the working directory for Cython (the directory modules are searched from) --gdb Output debug information for cygdb --gdb-outdir Specify gdb debug information output directory. Implies --gdb. -D, --no-docstrings Strip docstrings from the compiled module. -a, --annotate Produce a colorized HTML version of the source. --line-directives Produce #line directives pointing to the .pyx source --cplus Output a C++ rather than C file. --embed[=] Generate a main() function that embeds the Python interpreter. -2 Compile based on Python-2 syntax and code semantics. -3 Compile based on Python-3 syntax and code semantics. --lenient Change some compile time errors to runtime errors to improve Python compatibility --capi-reexport-cincludes Add cincluded headers to any auto-generated header files. --fast-fail Abort the compilation on the first error --warning-errors, -Werror Make all warnings into errors --warning-extra, -Wextra Enable extra warnings -X, --directive =[, 1: sys.stderr.write( "cython: Only one source file allowed when using -o\n") sys.exit(1) if len(sources) == 0 and not options.show_version: bad_usage() if Options.embed and len(sources) > 1: sys.stderr.write( "cython: Only one source file allowed when using -embed\n") sys.exit(1) return options, sources cython-0.20.1+git90-g0e6e38e/Cython/Compiler/Code.pxd000066400000000000000000000047031231323242300216560ustar00rootroot00000000000000 cimport cython #cdef class UtilityCodeBase(object): # cdef public object name # cdef public object proto # cdef public object impl # cdef public object init # cdef public object cleanup # cdef public object requires # cdef public dict _cache # cdef public list specialize_list # cdef public object proto_block # cdef public object file # # cpdef format_code(self, code_string, replace_empty_lines=*) cdef class FunctionState: cdef public set names_taken cdef public object owner cdef public object error_label cdef public size_t label_counter cdef public set labels_used cdef public object return_label cdef public object continue_label cdef public object break_label cdef public list yield_labels cdef public object return_from_error_cleanup_label # not used in __init__ ? cdef public bint in_try_finally cdef public object exc_vars cdef public bint can_trace cdef public list temps_allocated cdef public dict temps_free cdef public dict temps_used_type cdef public size_t temp_counter cdef public list collect_temps_stack cdef public object closure_temps cdef public bint should_declare_error_indicator cdef public bint uses_error_indicator @cython.locals(n=size_t) cpdef new_label(self, name=*) cpdef tuple get_loop_labels(self) cpdef set_loop_labels(self, labels) cpdef tuple get_all_labels(self) cpdef set_all_labels(self, labels) cpdef start_collecting_temps(self) cpdef stop_collecting_temps(self) cpdef list temps_in_use(self) cdef class IntConst: cdef public object cname cdef public object value cdef public bint is_long cdef class PyObjectConst: cdef public object cname cdef public object type cdef class StringConst: cdef public object cname cdef public object text cdef public object escaped_value cdef public dict py_strings cdef public list py_versions @cython.locals(intern=bint, is_str=bint, is_unicode=bint) cpdef get_py_string_const(self, encoding, identifier=*, is_str=*, py3str_cstring=*) ## cdef class PyStringConst: ## cdef public object cname ## cdef public object encoding ## cdef public bint is_str ## cdef public bint is_unicode ## cdef public bint intern #class GlobalState(object): #def funccontext_property(name): #class CCodeWriter(object): cdef class PyrexCodeWriter: cdef public object f cdef public Py_ssize_t level cython-0.20.1+git90-g0e6e38e/Cython/Compiler/Code.py000066400000000000000000002376331231323242300215250ustar00rootroot00000000000000# cython: language_level = 2 # # Code output module # import cython cython.declare(os=object, re=object, operator=object, Naming=object, Options=object, StringEncoding=object, Utils=object, SourceDescriptor=object, StringIOTree=object, DebugFlags=object, basestring=object) import os import re import sys from string import Template import operator import textwrap try: import hashlib except ImportError: import md5 as hashlib import Naming import Options import StringEncoding from Cython import Utils from Scanning import SourceDescriptor from Cython.StringIOTree import StringIOTree import DebugFlags try: from __builtin__ import basestring except ImportError: from builtins import str as basestring KEYWORDS_MUST_BE_BYTES = sys.version_info < (2,7) non_portable_builtins_map = { # builtins that have different names in different Python versions 'bytes' : ('PY_MAJOR_VERSION < 3', 'str'), 'unicode' : ('PY_MAJOR_VERSION >= 3', 'str'), 'basestring' : ('PY_MAJOR_VERSION >= 3', 'str'), 'xrange' : ('PY_MAJOR_VERSION >= 3', 'range'), 'raw_input' : ('PY_MAJOR_VERSION >= 3', 'input'), 'BaseException' : ('PY_VERSION_HEX < 0x02050000', 'Exception'), } basicsize_builtins_map = { # builtins whose type has a different tp_basicsize than sizeof(...) 'PyTypeObject' : 'PyHeapTypeObject', } uncachable_builtins = [ # builtin names that cannot be cached because they may or may not # be available at import time 'WindowsError', ] modifier_output_mapper = { 'inline': 'CYTHON_INLINE' }.get is_self_assignment = re.compile(r" *(\w+) = (\1);\s*$").match def get_utility_dir(): # make this a function and not global variables: # http://trac.cython.org/cython_trac/ticket/475 Cython_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) return os.path.join(Cython_dir, "Utility") class UtilityCodeBase(object): """ Support for loading utility code from a file. Code sections in the file can be specified as follows: ##### MyUtility.proto ##### [proto declarations] ##### MyUtility.init ##### [code run at module initialization] ##### MyUtility ##### #@requires: MyOtherUtility #@substitute: naming [definitions] for prototypes and implementation respectively. For non-python or -cython files backslashes should be used instead. 5 to 30 comment characters may be used on either side. If the @cname decorator is not used and this is a CythonUtilityCode, one should pass in the 'name' keyword argument to be used for name mangling of such entries. """ is_cython_utility = False requires = None _utility_cache = {} @classmethod def _add_utility(cls, utility, type, lines, begin_lineno, tags=None): if utility is None: return code = '\n'.join(lines) if tags and 'substitute' in tags and tags['substitute'] == set(['naming']): del tags['substitute'] try: code = Template(code).substitute(vars(Naming)) except (KeyError, ValueError), e: raise RuntimeError("Error parsing templated utility code of type '%s' at line %d: %s" % ( type, begin_lineno, e)) # remember correct line numbers at least until after templating code = '\n' * begin_lineno + code if type == 'proto': utility[0] = code elif type == 'impl': utility[1] = code else: all_tags = utility[2] if KEYWORDS_MUST_BE_BYTES: type = type.encode('ASCII') all_tags[type] = code if tags: all_tags = utility[2] for name, values in tags.items(): if KEYWORDS_MUST_BE_BYTES: name = name.encode('ASCII') all_tags.setdefault(name, set()).update(values) @classmethod def load_utilities_from_file(cls, path): utilities = cls._utility_cache.get(path) if utilities: return utilities filename = os.path.join(get_utility_dir(), path) _, ext = os.path.splitext(path) if ext in ('.pyx', '.py', '.pxd', '.pxi'): comment = '#' replace_comments = re.compile(r'^\s*#.*').sub else: comment = '/' replace_comments = re.compile(r'^\s*//.*|^\s*/\*[^*]*\*/').sub match_special = re.compile( (r'^%(C)s{5,30}\s*(?P(?:\w|\.)+)\s*%(C)s{5,30}|' r'^%(C)s+@(?P\w+)\s*:\s*(?P(?:\w|[.:])+)' ) % {'C':comment}).match match_type = re.compile('(.+)[.](proto|impl|init|cleanup)$').match f = Utils.open_source_file(filename, encoding='UTF-8') try: all_lines = f.readlines() finally: f.close() utilities = {} lines = [] tags = {} utility = type = None begin_lineno = 0 for lineno, line in enumerate(all_lines): m = match_special(line) if m: if m.group('name'): cls._add_utility(utility, type, lines, begin_lineno, tags) begin_lineno = lineno + 1 del lines[:] tags.clear() name = m.group('name') mtype = match_type(name) if mtype: name, type = mtype.groups() else: type = 'impl' utility = utilities.setdefault(name, [None, None, {}]) else: tags.setdefault(m.group('tag'), set()).add(m.group('value')) lines.append('') # keep line number correct else: lines.append(replace_comments('', line).rstrip()) if utility is None: raise ValueError("Empty utility code file") # Don't forget to add the last utility code cls._add_utility(utility, type, lines, begin_lineno, tags) cls._utility_cache[path] = utilities return utilities @classmethod def load(cls, util_code_name, from_file=None, **kwargs): """ Load utility code from a file specified by from_file (relative to Cython/Utility) and name util_code_name. If from_file is not given, load it from the file util_code_name.*. There should be only one file matched by this pattern. """ if '::' in util_code_name: from_file, util_code_name = util_code_name.rsplit('::', 1) if not from_file: utility_dir = get_utility_dir() prefix = util_code_name + '.' try: listing = os.listdir(utility_dir) except OSError: # XXX the code below assumes as 'zipimport.zipimporter' instance # XXX should be easy to generalize, but too lazy right now to write it import zipfile global __loader__ loader = __loader__ archive = loader.archive fileobj = zipfile.ZipFile(archive) listing = [ os.path.basename(name) for name in fileobj.namelist() if os.path.join(archive, name).startswith(utility_dir)] fileobj.close() files = [ os.path.join(utility_dir, filename) for filename in listing if filename.startswith(prefix) ] if not files: raise ValueError("No match found for utility code " + util_code_name) if len(files) > 1: raise ValueError("More than one filename match found for utility code " + util_code_name) from_file = files[0] utilities = cls.load_utilities_from_file(from_file) proto, impl, tags = utilities[util_code_name] if tags: orig_kwargs = kwargs.copy() for name, values in tags.items(): if name in kwargs: continue # only pass lists when we have to: most argument expect one value or None if name == 'requires': if orig_kwargs: values = [cls.load(dep, from_file, **orig_kwargs) for dep in sorted(values)] else: # dependencies are rarely unique, so use load_cached() when we can values = [cls.load_cached(dep, from_file) for dep in sorted(values)] elif not values: values = None elif len(values) == 1: values = values[0] kwargs[name] = values if proto is not None: kwargs['proto'] = proto if impl is not None: kwargs['impl'] = impl if 'name' not in kwargs: kwargs['name'] = util_code_name if 'file' not in kwargs and from_file: kwargs['file'] = from_file return cls(**kwargs) @classmethod def load_cached(cls, utility_code_name, from_file=None, __cache={}): """ Calls .load(), but using a per-type cache based on utility name and file name. """ key = (cls, from_file, utility_code_name) try: return __cache[key] except KeyError: pass code = __cache[key] = cls.load(utility_code_name, from_file) return code @classmethod def load_as_string(cls, util_code_name, from_file=None, **kwargs): """ Load a utility code as a string. Returns (proto, implementation) """ util = cls.load(util_code_name, from_file, **kwargs) proto, impl = util.proto, util.impl return util.format_code(proto), util.format_code(impl) def format_code(self, code_string, replace_empty_lines=re.compile(r'\n\n+').sub): """ Format a code section for output. """ if code_string: code_string = replace_empty_lines('\n', code_string.strip()) + '\n\n' return code_string def __str__(self): return "<%s(%s)" % (type(self).__name__, self.name) def get_tree(self): pass class UtilityCode(UtilityCodeBase): """ Stores utility code to add during code generation. See GlobalState.put_utility_code. hashes/equals by instance proto C prototypes impl implemenation code init code to call on module initialization requires utility code dependencies proto_block the place in the resulting file where the prototype should end up name name of the utility code (or None) file filename of the utility code file this utility was loaded from (or None) """ def __init__(self, proto=None, impl=None, init=None, cleanup=None, requires=None, proto_block='utility_code_proto', name=None, file=None): # proto_block: Which code block to dump prototype in. See GlobalState. self.proto = proto self.impl = impl self.init = init self.cleanup = cleanup self.requires = requires self._cache = {} self.specialize_list = [] self.proto_block = proto_block self.name = name self.file = file def __hash__(self): return hash((self.proto, self.impl)) def __eq__(self, other): if self is other: return True if not isinstance(other, type(self)): return False self_proto = getattr(self, 'proto', None) other_proto = getattr(other, 'proto', None) return (self_proto, self.impl) == (other_proto, other.impl) def none_or_sub(self, s, context): """ Format a string in this utility code with context. If None, do nothing. """ if s is None: return None return s % context def specialize(self, pyrex_type=None, **data): # Dicts aren't hashable... if pyrex_type is not None: data['type'] = pyrex_type.declaration_code('') data['type_name'] = pyrex_type.specialization_name() key = tuple(sorted(data.items())) try: return self._cache[key] except KeyError: if self.requires is None: requires = None else: requires = [r.specialize(data) for r in self.requires] s = self._cache[key] = UtilityCode( self.none_or_sub(self.proto, data), self.none_or_sub(self.impl, data), self.none_or_sub(self.init, data), self.none_or_sub(self.cleanup, data), requires, self.proto_block) self.specialize_list.append(s) return s def inject_string_constants(self, impl, output): """Replace 'PYIDENT("xyz")' by a constant Python identifier cname. """ replacements = {} def externalise(matchobj): name = matchobj.group(1) try: cname = replacements[name] except KeyError: cname = replacements[name] = output.get_interned_identifier( StringEncoding.EncodedString(name)).cname return cname impl = re.sub('PYIDENT\("([^"]+)"\)', externalise, impl) return bool(replacements), impl def put_code(self, output): if self.requires: for dependency in self.requires: output.use_utility_code(dependency) if self.proto: output[self.proto_block].put_or_include( self.format_code(self.proto), '%s_proto' % self.name) if self.impl: impl = self.format_code(self.impl) is_specialised, impl = self.inject_string_constants(impl, output) if not is_specialised: # no module specific adaptations => can be reused output['utility_code_def'].put_or_include( impl, '%s_impl' % self.name) else: output['utility_code_def'].put(impl) if self.init: writer = output['init_globals'] writer.putln("/* %s.init */" % self.name) if isinstance(self.init, basestring): writer.put(self.format_code(self.init)) else: self.init(writer, output.module_pos) writer.putln(writer.error_goto_if_PyErr(output.module_pos)) writer.putln() if self.cleanup and Options.generate_cleanup_code: writer = output['cleanup_globals'] if isinstance(self.cleanup, basestring): writer.put_or_include( self.format_code(self.cleanup), '%s_cleanup' % self.name) else: self.cleanup(writer, output.module_pos) def sub_tempita(s, context, file=None, name=None): "Run tempita on string s with given context." if not s: return None if file: context['__name'] = "%s:%s" % (file, name) elif name: context['__name'] = name from Cython.Tempita import sub return sub(s, **context) class TempitaUtilityCode(UtilityCode): def __init__(self, name=None, proto=None, impl=None, init=None, file=None, context=None, **kwargs): if context is None: context = {} proto = sub_tempita(proto, context, file, name) impl = sub_tempita(impl, context, file, name) init = sub_tempita(init, context, file, name) super(TempitaUtilityCode, self).__init__( proto, impl, init=init, name=name, file=file, **kwargs) def none_or_sub(self, s, context): """ Format a string in this utility code with context. If None, do nothing. """ if s is None: return None return sub_tempita(s, context, self.file, self.name) class LazyUtilityCode(UtilityCodeBase): """ Utility code that calls a callback with the root code writer when available. Useful when you only have 'env' but not 'code'. """ def __init__(self, callback): self.callback = callback def put_code(self, globalstate): utility = self.callback(globalstate.rootwriter) globalstate.use_utility_code(utility) class FunctionState(object): # return_label string function return point label # error_label string error catch point label # continue_label string loop continue point label # break_label string loop break point label # return_from_error_cleanup_label string # label_counter integer counter for naming labels # in_try_finally boolean inside try of try...finally # exc_vars (string * 3) exception variables for reraise, or None # can_trace boolean line tracing is supported in the current context # Not used for now, perhaps later def __init__(self, owner, names_taken=set()): self.names_taken = names_taken self.owner = owner self.error_label = None self.label_counter = 0 self.labels_used = set() self.return_label = self.new_label() self.new_error_label() self.continue_label = None self.break_label = None self.yield_labels = [] self.in_try_finally = 0 self.exc_vars = None self.can_trace = False self.temps_allocated = [] # of (name, type, manage_ref, static) self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status self.temps_used_type = {} # name -> (type, manage_ref) self.temp_counter = 0 self.closure_temps = None # This is used to collect temporaries, useful to find out which temps # need to be privatized in parallel sections self.collect_temps_stack = [] # This is used for the error indicator, which needs to be local to the # function. It used to be global, which relies on the GIL being held. # However, exceptions may need to be propagated through 'nogil' # sections, in which case we introduce a race condition. self.should_declare_error_indicator = False self.uses_error_indicator = False # labels def new_label(self, name=None): n = self.label_counter self.label_counter = n + 1 label = "%s%d" % (Naming.label_prefix, n) if name is not None: label += '_' + name return label def new_yield_label(self): label = self.new_label('resume_from_yield') num_and_label = (len(self.yield_labels) + 1, label) self.yield_labels.append(num_and_label) return num_and_label def new_error_label(self): old_err_lbl = self.error_label self.error_label = self.new_label('error') return old_err_lbl def get_loop_labels(self): return ( self.continue_label, self.break_label) def set_loop_labels(self, labels): (self.continue_label, self.break_label) = labels def new_loop_labels(self): old_labels = self.get_loop_labels() self.set_loop_labels( (self.new_label("continue"), self.new_label("break"))) return old_labels def get_all_labels(self): return ( self.continue_label, self.break_label, self.return_label, self.error_label) def set_all_labels(self, labels): (self.continue_label, self.break_label, self.return_label, self.error_label) = labels def all_new_labels(self): old_labels = self.get_all_labels() new_labels = [] for old_label, name in zip(old_labels, ['continue', 'break', 'return', 'error']): if old_label: new_labels.append(self.new_label(name)) else: new_labels.append(old_label) self.set_all_labels(new_labels) return old_labels def use_label(self, lbl): self.labels_used.add(lbl) def label_used(self, lbl): return lbl in self.labels_used # temp handling def allocate_temp(self, type, manage_ref, static=False): """ Allocates a temporary (which may create a new one or get a previously allocated and released one of the same type). Type is simply registered and handed back, but will usually be a PyrexType. If type.is_pyobject, manage_ref comes into play. If manage_ref is set to True, the temp will be decref-ed on return statements and in exception handling clauses. Otherwise the caller has to deal with any reference counting of the variable. If not type.is_pyobject, then manage_ref will be ignored, but it still has to be passed. It is recommended to pass False by convention if it is known that type will never be a Python object. static=True marks the temporary declaration with "static". This is only used when allocating backing store for a module-level C array literals. A C string referring to the variable is returned. """ if type.is_const: type = type.const_base_type if not type.is_pyobject and not type.is_memoryviewslice: # Make manage_ref canonical, so that manage_ref will always mean # a decref is needed. manage_ref = False freelist = self.temps_free.get((type, manage_ref)) if freelist is not None and len(freelist) > 0: result = freelist.pop() else: while True: self.temp_counter += 1 result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter) if not result in self.names_taken: break self.temps_allocated.append((result, type, manage_ref, static)) self.temps_used_type[result] = (type, manage_ref) if DebugFlags.debug_temp_code_comments: self.owner.putln("/* %s allocated */" % result) if self.collect_temps_stack: self.collect_temps_stack[-1].add((result, type)) return result def release_temp(self, name): """ Releases a temporary so that it can be reused by other code needing a temp of the same type. """ type, manage_ref = self.temps_used_type[name] freelist = self.temps_free.get((type, manage_ref)) if freelist is None: freelist = [] self.temps_free[(type, manage_ref)] = freelist if name in freelist: raise RuntimeError("Temp %s freed twice!" % name) freelist.append(name) if DebugFlags.debug_temp_code_comments: self.owner.putln("/* %s released */" % name) def temps_in_use(self): """Return a list of (cname,type,manage_ref) tuples of temp names and their type that are currently in use. """ used = [] for name, type, manage_ref, static in self.temps_allocated: freelist = self.temps_free.get((type, manage_ref)) if freelist is None or name not in freelist: used.append((name, type, manage_ref and type.is_pyobject)) return used def temps_holding_reference(self): """Return a list of (cname,type) tuples of temp names and their type that are currently in use. This includes only temps of a Python object type which owns its reference. """ return [(name, type) for name, type, manage_ref in self.temps_in_use() if manage_ref and type.is_pyobject] def all_managed_temps(self): """Return a list of (cname, type) tuples of refcount-managed Python objects. """ return [(cname, type) for cname, type, manage_ref, static in self.temps_allocated if manage_ref] def all_free_managed_temps(self): """Return a list of (cname, type) tuples of refcount-managed Python objects that are not currently in use. This is used by try-except and try-finally blocks to clean up temps in the error case. """ return [(cname, type) for (type, manage_ref), freelist in self.temps_free.items() if manage_ref for cname in freelist] def start_collecting_temps(self): """ Useful to find out which temps were used in a code block """ self.collect_temps_stack.append(set()) def stop_collecting_temps(self): return self.collect_temps_stack.pop() def init_closure_temps(self, scope): self.closure_temps = ClosureTempAllocator(scope) class NumConst(object): """Global info about a Python number constant held by GlobalState. cname string value string py_type string int, long, float value_code string evaluation code if different from value """ def __init__(self, cname, value, py_type, value_code=None): self.cname = cname self.value = value self.py_type = py_type self.value_code = value_code or value class PyObjectConst(object): """Global info about a generic constant held by GlobalState. """ # cname string # type PyrexType def __init__(self, cname, type): self.cname = cname self.type = type cython.declare(possible_unicode_identifier=object, possible_bytes_identifier=object, replace_identifier=object, find_alphanums=object) possible_unicode_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match replace_identifier = re.compile(r'[^a-zA-Z0-9_]+').sub find_alphanums = re.compile('([a-zA-Z0-9]+)').findall class StringConst(object): """Global info about a C string constant held by GlobalState. """ # cname string # text EncodedString or BytesLiteral # py_strings {(identifier, encoding) : PyStringConst} def __init__(self, cname, text, byte_string): self.cname = cname self.text = text self.escaped_value = StringEncoding.escape_byte_string(byte_string) self.py_strings = None self.py_versions = [] def add_py_version(self, version): if not version: self.py_versions = [2,3] elif version not in self.py_versions: self.py_versions.append(version) def get_py_string_const(self, encoding, identifier=None, is_str=False, py3str_cstring=None): py_strings = self.py_strings text = self.text is_str = bool(identifier or is_str) is_unicode = encoding is None and not is_str if encoding is None: # unicode string encoding_key = None else: # bytes or str encoding = encoding.lower() if encoding in ('utf8', 'utf-8', 'ascii', 'usascii', 'us-ascii'): encoding = None encoding_key = None else: encoding_key = ''.join(find_alphanums(encoding)) key = (is_str, is_unicode, encoding_key, py3str_cstring) if py_strings is not None: try: return py_strings[key] except KeyError: pass else: self.py_strings = {} if identifier: intern = True elif identifier is None: if isinstance(text, unicode): intern = bool(possible_unicode_identifier(text)) else: intern = bool(possible_bytes_identifier(text)) else: intern = False if intern: prefix = Naming.interned_prefixes['str'] else: prefix = Naming.py_const_prefix if encoding_key: encoding_prefix = '_%s' % encoding_key else: encoding_prefix = '' pystring_cname = "%s%s%s_%s" % ( prefix, (is_str and 's') or (is_unicode and 'u') or 'b', encoding_prefix, self.cname[len(Naming.const_prefix):]) py_string = PyStringConst( pystring_cname, encoding, is_unicode, is_str, py3str_cstring, intern) self.py_strings[key] = py_string return py_string class PyStringConst(object): """Global info about a Python string constant held by GlobalState. """ # cname string # py3str_cstring string # encoding string # intern boolean # is_unicode boolean # is_str boolean def __init__(self, cname, encoding, is_unicode, is_str=False, py3str_cstring=None, intern=False): self.cname = cname self.py3str_cstring = py3str_cstring self.encoding = encoding self.is_str = is_str self.is_unicode = is_unicode self.intern = intern def __lt__(self, other): return self.cname < other.cname class GlobalState(object): # filename_table {string : int} for finding filename table indexes # filename_list [string] filenames in filename table order # input_file_contents dict contents (=list of lines) of any file that was used as input # to create this output C code. This is # used to annotate the comments. # # utility_codes set IDs of used utility code (to avoid reinsertion) # # declared_cnames {string:Entry} used in a transition phase to merge pxd-declared # constants etc. into the pyx-declared ones (i.e, # check if constants are already added). # In time, hopefully the literals etc. will be # supplied directly instead. # # const_cnames_used dict global counter for unique constant identifiers # # parts {string:CCodeWriter} # interned_strings # consts # interned_nums # directives set Temporary variable used to track # the current set of directives in the code generation # process. directives = {} code_layout = [ 'h_code', 'filename_table', 'utility_code_proto_before_types', 'numeric_typedefs', # Let these detailed individual parts stay!, 'complex_type_declarations', # as the proper solution is to make a full DAG... 'type_declarations', # More coarse-grained blocks would simply hide 'utility_code_proto', # the ugliness, not fix it 'module_declarations', 'typeinfo', 'before_global_var', 'global_var', 'decls', 'all_the_rest', 'pystring_table', 'cached_builtins', 'cached_constants', 'init_globals', 'init_module', 'cleanup_globals', 'cleanup_module', 'main_method', 'utility_code_def', 'end' ] def __init__(self, writer, module_node, emit_linenums=False, common_utility_include_dir=None): self.filename_table = {} self.filename_list = [] self.input_file_contents = {} self.utility_codes = set() self.declared_cnames = {} self.in_utility_code_generation = False self.emit_linenums = emit_linenums self.common_utility_include_dir = common_utility_include_dir self.parts = {} self.module_node = module_node # because some utility code generation needs it # (generating backwards-compatible Get/ReleaseBuffer self.const_cnames_used = {} self.string_const_index = {} self.pyunicode_ptr_const_index = {} self.num_const_index = {} self.py_constants = [] assert writer.globalstate is None writer.globalstate = self self.rootwriter = writer def initialize_main_c_code(self): rootwriter = self.rootwriter for part in self.code_layout: self.parts[part] = rootwriter.insertion_point() if not Options.cache_builtins: del self.parts['cached_builtins'] else: w = self.parts['cached_builtins'] w.enter_cfunc_scope() w.putln("static int __Pyx_InitCachedBuiltins(void) {") w = self.parts['cached_constants'] w.enter_cfunc_scope() w.putln("") w.putln("static int __Pyx_InitCachedConstants(void) {") w.put_declare_refcount_context() w.put_setup_refcount_context("__Pyx_InitCachedConstants") w = self.parts['init_globals'] w.enter_cfunc_scope() w.putln("") w.putln("static int __Pyx_InitGlobals(void) {") if not Options.generate_cleanup_code: del self.parts['cleanup_globals'] else: w = self.parts['cleanup_globals'] w.enter_cfunc_scope() w.putln("") w.putln("static void __Pyx_CleanupGlobals(void) {") # # utility_code_def # code = self.parts['utility_code_def'] if self.emit_linenums: code.write('\n#line 1 "cython_utility"\n') code.putln("") code.putln("/* Runtime support code */") def finalize_main_c_code(self): self.close_global_decls() # # utility_code_def # code = self.parts['utility_code_def'] code.put(UtilityCode.load_as_string("TypeConversions", "TypeConversion.c")[1]) code.putln("") def __getitem__(self, key): return self.parts[key] # # Global constants, interned objects, etc. # def close_global_decls(self): # This is called when it is known that no more global declarations will # declared. self.generate_const_declarations() if Options.cache_builtins: w = self.parts['cached_builtins'] w.putln("return 0;") if w.label_used(w.error_label): w.put_label(w.error_label) w.putln("return -1;") w.putln("}") w.exit_cfunc_scope() w = self.parts['cached_constants'] w.put_finish_refcount_context() w.putln("return 0;") if w.label_used(w.error_label): w.put_label(w.error_label) w.put_finish_refcount_context() w.putln("return -1;") w.putln("}") w.exit_cfunc_scope() w = self.parts['init_globals'] w.putln("return 0;") if w.label_used(w.error_label): w.put_label(w.error_label) w.putln("return -1;") w.putln("}") w.exit_cfunc_scope() if Options.generate_cleanup_code: w = self.parts['cleanup_globals'] w.putln("}") w.exit_cfunc_scope() if Options.generate_cleanup_code: w = self.parts['cleanup_module'] w.putln("}") w.exit_cfunc_scope() def put_pyobject_decl(self, entry): self['global_var'].putln("static PyObject *%s;" % entry.cname) # constant handling at code generation time def get_cached_constants_writer(self): return self.parts['cached_constants'] def get_int_const(self, str_value, longness=False): py_type = longness and 'long' or 'int' try: c = self.num_const_index[(str_value, py_type)] except KeyError: c = self.new_num_const(str_value, py_type) return c def get_float_const(self, str_value, value_code): try: c = self.num_const_index[(str_value, 'float')] except KeyError: c = self.new_num_const(str_value, 'float', value_code) return c def get_py_const(self, type, prefix='', cleanup_level=None): # create a new Python object constant const = self.new_py_const(type, prefix) if cleanup_level is not None \ and cleanup_level <= Options.generate_cleanup_code: cleanup_writer = self.parts['cleanup_globals'] cleanup_writer.putln('Py_CLEAR(%s);' % const.cname) return const def get_string_const(self, text, py_version=None): # return a C string constant, creating a new one if necessary if text.is_unicode: byte_string = text.utf8encode() else: byte_string = text.byteencode() try: c = self.string_const_index[byte_string] except KeyError: c = self.new_string_const(text, byte_string) c.add_py_version(py_version) return c def get_pyunicode_ptr_const(self, text): # return a Py_UNICODE[] constant, creating a new one if necessary assert text.is_unicode try: c = self.pyunicode_ptr_const_index[text] except KeyError: c = self.pyunicode_ptr_const_index[text] = self.new_const_cname() return c def get_py_string_const(self, text, identifier=None, is_str=False, unicode_value=None): # return a Python string constant, creating a new one if necessary py3str_cstring = None if is_str and unicode_value is not None \ and unicode_value.utf8encode() != text.byteencode(): py3str_cstring = self.get_string_const(unicode_value, py_version=3) c_string = self.get_string_const(text, py_version=2) else: c_string = self.get_string_const(text) py_string = c_string.get_py_string_const( text.encoding, identifier, is_str, py3str_cstring) return py_string def get_interned_identifier(self, text): return self.get_py_string_const(text, identifier=True) def new_string_const(self, text, byte_string): cname = self.new_string_const_cname(byte_string) c = StringConst(cname, text, byte_string) self.string_const_index[byte_string] = c return c def new_num_const(self, value, py_type, value_code=None): cname = self.new_num_const_cname(value, py_type) c = NumConst(cname, value, py_type, value_code) self.num_const_index[(value, py_type)] = c return c def new_py_const(self, type, prefix=''): cname = self.new_const_cname(prefix) c = PyObjectConst(cname, type) self.py_constants.append(c) return c def new_string_const_cname(self, bytes_value): # Create a new globally-unique nice name for a C string constant. value = bytes_value.decode('ASCII', 'ignore') return self.new_const_cname(value=value) def new_num_const_cname(self, value, py_type): if py_type == 'long': value += 'L' py_type = 'int' prefix = Naming.interned_prefixes[py_type] cname = "%s%s" % (prefix, value) cname = cname.replace('+', '_').replace('-', 'neg_').replace('.', '_') return cname def new_const_cname(self, prefix='', value=''): value = replace_identifier('_', value)[:32].strip('_') used = self.const_cnames_used name_suffix = value while name_suffix in used: counter = used[value] = used[value] + 1 name_suffix = '%s_%d' % (value, counter) used[name_suffix] = 1 if prefix: prefix = Naming.interned_prefixes[prefix] else: prefix = Naming.const_prefix return "%s%s" % (prefix, name_suffix) def add_cached_builtin_decl(self, entry): if entry.is_builtin and entry.is_const: if self.should_declare(entry.cname, entry): self.put_pyobject_decl(entry) w = self.parts['cached_builtins'] condition = None if entry.name in non_portable_builtins_map: condition, replacement = non_portable_builtins_map[entry.name] w.putln('#if %s' % condition) self.put_cached_builtin_init( entry.pos, StringEncoding.EncodedString(replacement), entry.cname) w.putln('#else') self.put_cached_builtin_init( entry.pos, StringEncoding.EncodedString(entry.name), entry.cname) if condition: w.putln('#endif') def put_cached_builtin_init(self, pos, name, cname): w = self.parts['cached_builtins'] interned_cname = self.get_interned_identifier(name).cname self.use_utility_code( UtilityCode.load_cached("GetBuiltinName", "ObjectHandling.c")) w.putln('%s = __Pyx_GetBuiltinName(%s); if (!%s) %s' % ( cname, interned_cname, cname, w.error_goto(pos))) def generate_const_declarations(self): self.generate_string_constants() self.generate_num_constants() self.generate_object_constant_decls() def generate_object_constant_decls(self): consts = [ (len(c.cname), c.cname, c) for c in self.py_constants ] consts.sort() decls_writer = self.parts['decls'] for _, cname, c in consts: decls_writer.putln( "static %s;" % c.type.declaration_code(cname)) def generate_string_constants(self): c_consts = [ (len(c.cname), c.cname, c) for c in self.string_const_index.values() ] c_consts.sort() py_strings = [] decls_writer = self.parts['decls'] for _, cname, c in c_consts: conditional = False if c.py_versions and (2 not in c.py_versions or 3 not in c.py_versions): conditional = True decls_writer.putln("#if PY_MAJOR_VERSION %s 3" % ( (2 in c.py_versions) and '<' or '>=')) decls_writer.putln('static char %s[] = "%s";' % ( cname, StringEncoding.split_string_literal(c.escaped_value))) if conditional: decls_writer.putln("#endif") if c.py_strings is not None: for py_string in c.py_strings.values(): py_strings.append((c.cname, len(py_string.cname), py_string)) for c, cname in self.pyunicode_ptr_const_index.items(): utf16_array, utf32_array = StringEncoding.encode_pyunicode_string(c) if utf16_array: # Narrow and wide representations differ decls_writer.putln("#ifdef Py_UNICODE_WIDE") decls_writer.putln("static Py_UNICODE %s[] = { %s };" % (cname, utf32_array)) if utf16_array: decls_writer.putln("#else") decls_writer.putln("static Py_UNICODE %s[] = { %s };" % (cname, utf16_array)) decls_writer.putln("#endif") if py_strings: self.use_utility_code(UtilityCode.load_cached("InitStrings", "StringTools.c")) py_strings.sort() w = self.parts['pystring_table'] w.putln("") w.putln("static __Pyx_StringTabEntry %s[] = {" % Naming.stringtab_cname) for c_cname, _, py_string in py_strings: if not py_string.is_str or not py_string.encoding or \ py_string.encoding in ('ASCII', 'USASCII', 'US-ASCII', 'UTF8', 'UTF-8'): encoding = '0' else: encoding = '"%s"' % py_string.encoding.lower() decls_writer.putln( "static PyObject *%s;" % py_string.cname) if py_string.py3str_cstring: w.putln("#if PY_MAJOR_VERSION >= 3") w.putln( "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % ( py_string.cname, py_string.py3str_cstring.cname, py_string.py3str_cstring.cname, '0', 1, 0, py_string.intern )) w.putln("#else") w.putln( "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % ( py_string.cname, c_cname, c_cname, encoding, py_string.is_unicode, py_string.is_str, py_string.intern )) if py_string.py3str_cstring: w.putln("#endif") w.putln("{0, 0, 0, 0, 0, 0, 0}") w.putln("};") init_globals = self.parts['init_globals'] init_globals.putln( "if (__Pyx_InitStrings(%s) < 0) %s;" % ( Naming.stringtab_cname, init_globals.error_goto(self.module_pos))) def generate_num_constants(self): consts = [(c.py_type, c.value[0] == '-', len(c.value), c.value, c.value_code, c) for c in self.num_const_index.values()] consts.sort() decls_writer = self.parts['decls'] init_globals = self.parts['init_globals'] for py_type, _, _, value, value_code, c in consts: cname = c.cname decls_writer.putln("static PyObject *%s;" % cname) if py_type == 'float': function = 'PyFloat_FromDouble(%s)' elif py_type == 'long': function = 'PyLong_FromString((char *)"%s", 0, 0)' elif Utils.long_literal(value): function = 'PyInt_FromString((char *)"%s", 0, 0)' elif len(value.lstrip('-')) > 4: function = "PyInt_FromLong(%sL)" else: function = "PyInt_FromLong(%s)" init_globals.putln('%s = %s; %s' % ( cname, function % value_code, init_globals.error_goto_if_null(cname, self.module_pos))) # The functions below are there in a transition phase only # and will be deprecated. They are called from Nodes.BlockNode. # The copy&paste duplication is intentional in order to be able # to see quickly how BlockNode worked, until this is replaced. def should_declare(self, cname, entry): if cname in self.declared_cnames: other = self.declared_cnames[cname] assert str(entry.type) == str(other.type) assert entry.init == other.init return False else: self.declared_cnames[cname] = entry return True # # File name state # def lookup_filename(self, filename): try: index = self.filename_table[filename] except KeyError: index = len(self.filename_list) self.filename_list.append(filename) self.filename_table[filename] = index return index def commented_file_contents(self, source_desc): try: return self.input_file_contents[source_desc] except KeyError: pass source_file = source_desc.get_lines(encoding='ASCII', error_handling='ignore') try: F = [u' * ' + line.rstrip().replace( u'*/', u'*[inserted by cython to avoid comment closer]/' ).replace( u'/*', u'/[inserted by cython to avoid comment start]*' ) for line in source_file] finally: if hasattr(source_file, 'close'): source_file.close() if not F: F.append(u'') self.input_file_contents[source_desc] = F return F # # Utility code state # def use_utility_code(self, utility_code): """ Adds code to the C file. utility_code should a) implement __eq__/__hash__ for the purpose of knowing whether the same code has already been included b) implement put_code, which takes a globalstate instance See UtilityCode. """ if utility_code not in self.utility_codes: self.utility_codes.add(utility_code) utility_code.put_code(self) def funccontext_property(name): attribute_of = operator.attrgetter(name) def get(self): return attribute_of(self.funcstate) def set(self, value): setattr(self.funcstate, name, value) return property(get, set) class CCodeWriter(object): """ Utility class to output C code. When creating an insertion point one must care about the state that is kept: - formatting state (level, bol) is cloned and used in insertion points as well - labels, temps, exc_vars: One must construct a scope in which these can exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for sanity checking and forward compatabilty). Created insertion points looses this scope and cannot access it. - marker: Not copied to insertion point - filename_table, filename_list, input_file_contents: All codewriters coming from the same root share the same instances simultaneously. """ # f file output file # buffer StringIOTree # level int indentation level # bol bool beginning of line? # marker string comment to emit before next line # funcstate FunctionState contains state local to a C function used for code # generation (labels and temps state etc.) # globalstate GlobalState contains state global for a C file (input file info, # utility code, declared constants etc.) # emit_linenums boolean whether or not to write #line pragmas # # c_line_in_traceback boolean append the c file and line number to the traceback for exceptions # # pyclass_stack list used during recursive code generation to pass information # about the current class one is in globalstate = None def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None, c_line_in_traceback=True): if buffer is None: buffer = StringIOTree() self.buffer = buffer self.marker = None self.last_marker_line = 0 self.source_desc = "" self.pyclass_stack = [] self.funcstate = None self.level = 0 self.call_level = 0 self.bol = 1 if create_from is not None: # Use same global state self.globalstate = create_from.globalstate self.funcstate = create_from.funcstate # Clone formatting state if copy_formatting: self.level = create_from.level self.bol = create_from.bol self.call_level = create_from.call_level if emit_linenums is None and self.globalstate: self.emit_linenums = self.globalstate.emit_linenums else: self.emit_linenums = emit_linenums self.c_line_in_traceback = c_line_in_traceback def create_new(self, create_from, buffer, copy_formatting): # polymorphic constructor -- very slightly more versatile # than using __class__ result = CCodeWriter(create_from, buffer, copy_formatting, c_line_in_traceback=self.c_line_in_traceback) return result def copyto(self, f): self.buffer.copyto(f) def getvalue(self): return self.buffer.getvalue() def write(self, s): # also put invalid markers (lineno 0), to indicate that those lines # have no Cython source code correspondence if self.marker is None: cython_lineno = self.last_marker_line else: cython_lineno = self.marker[0] self.buffer.markers.extend([cython_lineno] * s.count('\n')) self.buffer.write(s) def insertion_point(self): other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True) return other def new_writer(self): """ Creates a new CCodeWriter connected to the same global state, which can later be inserted using insert. """ return CCodeWriter(create_from=self, c_line_in_traceback=self.c_line_in_traceback) def insert(self, writer): """ Inserts the contents of another code writer (created with the same global state) in the current location. It is ok to write to the inserted writer also after insertion. """ assert writer.globalstate is self.globalstate self.buffer.insert(writer.buffer) # Properties delegated to function scope label_counter = funccontext_property("label_counter") return_label = funccontext_property("return_label") error_label = funccontext_property("error_label") labels_used = funccontext_property("labels_used") continue_label = funccontext_property("continue_label") break_label = funccontext_property("break_label") return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label") yield_labels = funccontext_property("yield_labels") # Functions delegated to function scope def new_label(self, name=None): return self.funcstate.new_label(name) def new_error_label(self): return self.funcstate.new_error_label() def new_yield_label(self): return self.funcstate.new_yield_label() def get_loop_labels(self): return self.funcstate.get_loop_labels() def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels) def new_loop_labels(self): return self.funcstate.new_loop_labels() def get_all_labels(self): return self.funcstate.get_all_labels() def set_all_labels(self, labels): return self.funcstate.set_all_labels(labels) def all_new_labels(self): return self.funcstate.all_new_labels() def use_label(self, lbl): return self.funcstate.use_label(lbl) def label_used(self, lbl): return self.funcstate.label_used(lbl) def enter_cfunc_scope(self): self.funcstate = FunctionState(self) def exit_cfunc_scope(self): self.funcstate = None # constant handling def get_py_int(self, str_value, longness): return self.globalstate.get_int_const(str_value, longness).cname def get_py_float(self, str_value, value_code): return self.globalstate.get_float_const(str_value, value_code).cname def get_py_const(self, type, prefix='', cleanup_level=None): return self.globalstate.get_py_const(type, prefix, cleanup_level).cname def get_string_const(self, text): return self.globalstate.get_string_const(text).cname def get_pyunicode_ptr_const(self, text): return self.globalstate.get_pyunicode_ptr_const(text) def get_py_string_const(self, text, identifier=None, is_str=False, unicode_value=None): return self.globalstate.get_py_string_const( text, identifier, is_str, unicode_value).cname def get_argument_default_const(self, type): return self.globalstate.get_py_const(type).cname def intern(self, text): return self.get_py_string_const(text) def intern_identifier(self, text): return self.get_py_string_const(text, identifier=True) def get_cached_constants_writer(self): return self.globalstate.get_cached_constants_writer() # code generation def putln(self, code="", safe=False): if self.marker and self.bol: self.emit_marker() if self.emit_linenums and self.last_marker_line != 0: self.write('\n#line %s "%s"\n' % (self.last_marker_line, self.source_desc)) if code: if safe: self.put_safe(code) else: self.put(code) self.write("\n") self.bol = 1 def emit_marker(self): self.write("\n") self.indent() self.write("/* %s */\n" % self.marker[1]) if (self.funcstate and self.funcstate.can_trace and self.globalstate.directives['linetrace']): self.indent() self.write('__Pyx_TraceLine(%d)\n' % self.marker[0]) self.last_marker_line = self.marker[0] self.marker = None def put_safe(self, code): # put code, but ignore {} self.write(code) self.bol = 0 def put_or_include(self, code, name): include_dir = self.globalstate.common_utility_include_dir if include_dir and len(code) > 1024: include_file = "%s_%s.h" % ( name, hashlib.md5(code.encode('utf8')).hexdigest()) path = os.path.join(include_dir, include_file) if not os.path.exists(path): tmp_path = '%s.tmp%s' % (path, os.getpid()) f = Utils.open_new_file(tmp_path) try: f.write(code) finally: f.close() os.rename(tmp_path, path) code = '#include "%s"\n' % path self.put(code) def put(self, code): if is_self_assignment(code): return fix_indent = False if "{" in code: dl = code.count("{") else: dl = 0 if "}" in code: dl -= code.count("}") if dl < 0: self.level += dl elif dl == 0 and code[0] == "}": # special cases like "} else {" need a temporary dedent fix_indent = True self.level -= 1 if self.bol: self.indent() self.write(code) self.bol = 0 if dl > 0: self.level += dl elif fix_indent: self.level += 1 def putln_tempita(self, code, **context): from Cython.Tempita import sub self.putln(sub(code, **context)) def put_tempita(self, code, **context): from Cython.Tempita import sub self.put(sub(code, **context)) def increase_indent(self): self.level += 1 def decrease_indent(self): self.level -= 1 def begin_block(self): self.putln("{") self.increase_indent() def end_block(self): self.decrease_indent() self.putln("}") def indent(self): self.write(" " * self.level) def get_py_version_hex(self, pyversion): return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4] def mark_pos(self, pos): if pos is None: return source_desc, line, col = pos if self.last_marker_line == line: return assert isinstance(source_desc, SourceDescriptor) contents = self.globalstate.commented_file_contents(source_desc) lines = contents[max(0, line-3):line] # line numbers start at 1 lines[-1] += u' # <<<<<<<<<<<<<<' lines += contents[line:line+2] marker = u'"%s":%d\n%s\n' % ( source_desc.get_escaped_description(), line, u'\n'.join(lines)) self.marker = (line, marker) if self.emit_linenums: self.source_desc = source_desc.get_escaped_description() def put_label(self, lbl): if lbl in self.funcstate.labels_used: self.putln("%s:;" % lbl) def put_goto(self, lbl): self.funcstate.use_label(lbl) self.putln("goto %s;" % lbl) def put_var_declaration(self, entry, storage_class="", dll_linkage=None, definition=True): #print "Code.put_var_declaration:", entry.name, "definition =", definition ### if entry.visibility == 'private' and not (definition or entry.defined_in_pxd): #print "...private and not definition, skipping", entry.cname ### return if entry.visibility == "private" and not entry.used: #print "...private and not used, skipping", entry.cname ### return if storage_class: self.put("%s " % storage_class) if not entry.cf_used: self.put('CYTHON_UNUSED ') self.put(entry.type.declaration_code( entry.cname, dll_linkage=dll_linkage)) if entry.init is not None: self.put_safe(" = %s" % entry.type.literal_code(entry.init)) elif entry.type.is_pyobject: self.put(" = NULL") self.putln(";") def put_temp_declarations(self, func_context): for name, type, manage_ref, static in func_context.temps_allocated: decl = type.declaration_code(name) if type.is_pyobject: self.putln("%s = NULL;" % decl) elif type.is_memoryviewslice: import MemoryView self.putln("%s = %s;" % (decl, MemoryView.memslice_entry_init)) else: self.putln("%s%s;" % (static and "static " or "", decl)) if func_context.should_declare_error_indicator: if self.funcstate.uses_error_indicator: unused = '' else: unused = 'CYTHON_UNUSED ' # Initialize these variables to silence compiler warnings self.putln("%sint %s = 0;" % (unused, Naming.lineno_cname)) self.putln("%sconst char *%s = NULL;" % (unused, Naming.filename_cname)) self.putln("%sint %s = 0;" % (unused, Naming.clineno_cname)) def put_h_guard(self, guard): self.putln("#ifndef %s" % guard) self.putln("#define %s" % guard) def unlikely(self, cond): if Options.gcc_branch_hints: return 'unlikely(%s)' % cond else: return cond def build_function_modifiers(self, modifiers, mapper=modifier_output_mapper): if not modifiers: return '' return '%s ' % ' '.join([mapper(m,m) for m in modifiers]) # Python objects and reference counting def entry_as_pyobject(self, entry): type = entry.type if (not entry.is_self_arg and not entry.type.is_complete() or entry.type.is_extension_type): return "(PyObject *)" + entry.cname else: return entry.cname def as_pyobject(self, cname, type): from PyrexTypes import py_object_type, typecast return typecast(py_object_type, type, cname) def put_gotref(self, cname): self.putln("__Pyx_GOTREF(%s);" % cname) def put_giveref(self, cname): self.putln("__Pyx_GIVEREF(%s);" % cname) def put_xgiveref(self, cname): self.putln("__Pyx_XGIVEREF(%s);" % cname) def put_xgotref(self, cname): self.putln("__Pyx_XGOTREF(%s);" % cname) def put_incref(self, cname, type, nanny=True): if nanny: self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type)) else: self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type)) def put_decref(self, cname, type, nanny=True): self._put_decref(cname, type, nanny, null_check=False, clear=False) def put_var_gotref(self, entry): if entry.type.is_pyobject: self.putln("__Pyx_GOTREF(%s);" % self.entry_as_pyobject(entry)) def put_var_giveref(self, entry): if entry.type.is_pyobject: self.putln("__Pyx_GIVEREF(%s);" % self.entry_as_pyobject(entry)) def put_var_xgotref(self, entry): if entry.type.is_pyobject: self.putln("__Pyx_XGOTREF(%s);" % self.entry_as_pyobject(entry)) def put_var_xgiveref(self, entry): if entry.type.is_pyobject: self.putln("__Pyx_XGIVEREF(%s);" % self.entry_as_pyobject(entry)) def put_var_incref(self, entry): if entry.type.is_pyobject: self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry)) def put_decref_clear(self, cname, type, nanny=True, clear_before_decref=False): self._put_decref(cname, type, nanny, null_check=False, clear=True, clear_before_decref=clear_before_decref) def put_xdecref(self, cname, type, nanny=True, have_gil=True): self._put_decref(cname, type, nanny, null_check=True, have_gil=have_gil, clear=False) def put_xdecref_clear(self, cname, type, nanny=True, clear_before_decref=False): self._put_decref(cname, type, nanny, null_check=True, clear=True, clear_before_decref=clear_before_decref) def _put_decref(self, cname, type, nanny=True, null_check=False, have_gil=True, clear=False, clear_before_decref=False): if type.is_memoryviewslice: self.put_xdecref_memoryviewslice(cname, have_gil=have_gil) return prefix = nanny and '__Pyx' or 'Py' X = null_check and 'X' or '' if clear: if clear_before_decref: if not nanny: X = '' # CPython doesn't have a Py_XCLEAR() self.putln("%s_%sCLEAR(%s);" % (prefix, X, cname)) else: self.putln("%s_%sDECREF(%s); %s = 0;" % ( prefix, X, self.as_pyobject(cname, type), cname)) else: self.putln("%s_%sDECREF(%s);" % ( prefix, X, self.as_pyobject(cname, type))) def put_decref_set(self, cname, rhs_cname): self.putln("__Pyx_DECREF_SET(%s, %s);" % (cname, rhs_cname)) def put_xdecref_set(self, cname, rhs_cname): self.putln("__Pyx_XDECREF_SET(%s, %s);" % (cname, rhs_cname)) def put_var_decref(self, entry): if entry.type.is_pyobject: self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry)) def put_var_xdecref(self, entry): if entry.type.is_pyobject: self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry)) def put_var_decref_clear(self, entry): self._put_var_decref_clear(entry, null_check=False) def put_var_xdecref_clear(self, entry): self._put_var_decref_clear(entry, null_check=True) def _put_var_decref_clear(self, entry, null_check): if entry.type.is_pyobject: if entry.in_closure: # reset before DECREF to make sure closure state is # consistent during call to DECREF() self.putln("__Pyx_%sCLEAR(%s);" % ( null_check and 'X' or '', entry.cname)) else: self.putln("__Pyx_%sDECREF(%s); %s = 0;" % ( null_check and 'X' or '', self.entry_as_pyobject(entry), entry.cname)) def put_var_decrefs(self, entries, used_only = 0): for entry in entries: if not used_only or entry.used: if entry.xdecref_cleanup: self.put_var_xdecref(entry) else: self.put_var_decref(entry) def put_var_xdecrefs(self, entries): for entry in entries: self.put_var_xdecref(entry) def put_var_xdecrefs_clear(self, entries): for entry in entries: self.put_var_xdecref_clear(entry) def put_incref_memoryviewslice(self, slice_cname, have_gil=False): import MemoryView self.globalstate.use_utility_code(MemoryView.memviewslice_init_code) self.putln("__PYX_INC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil))) def put_xdecref_memoryviewslice(self, slice_cname, have_gil=False): import MemoryView self.globalstate.use_utility_code(MemoryView.memviewslice_init_code) self.putln("__PYX_XDEC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil))) def put_xgiveref_memoryviewslice(self, slice_cname): self.put_xgiveref("%s.memview" % slice_cname) def put_init_to_py_none(self, cname, type, nanny=True): from PyrexTypes import py_object_type, typecast py_none = typecast(type, py_object_type, "Py_None") if nanny: self.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname, py_none)) else: self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none)) def put_init_var_to_py_none(self, entry, template = "%s", nanny=True): code = template % entry.cname #if entry.type.is_extension_type: # code = "((PyObject*)%s)" % code self.put_init_to_py_none(code, entry.type, nanny) if entry.in_closure: self.put_giveref('Py_None') def put_pymethoddef(self, entry, term, allow_skip=True): if entry.is_special or entry.name == '__getattribute__': if entry.name not in ['__cinit__', '__dealloc__', '__richcmp__', '__next__', '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', '__getcharbuffer__', '__getbuffer__', '__releasebuffer__']: if entry.name == '__getattr__' and not self.globalstate.directives['fast_getattr']: pass # Python's typeobject.c will automatically fill in our slot # in add_operators() (called by PyType_Ready) with a value # that's better than ours. elif allow_skip: return from TypeSlots import method_coexist if entry.doc: doc_code = entry.doc_cname else: doc_code = 0 method_flags = entry.signature.method_flags() if method_flags: if entry.is_special: method_flags += [method_coexist] self.putln( '{__Pyx_NAMESTR("%s"), (PyCFunction)%s, %s, __Pyx_DOCSTR(%s)}%s' % ( entry.name, entry.func_cname, "|".join(method_flags), doc_code, term)) # GIL methods def put_ensure_gil(self, declare_gilstate=True, variable=None): """ Acquire the GIL. The generated code is safe even when no PyThreadState has been allocated for this thread (for threads not initialized by using the Python API). Additionally, the code generated by this method may be called recursively. """ self.globalstate.use_utility_code( UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c")) self.putln("#ifdef WITH_THREAD") if not variable: variable = '__pyx_gilstate_save' if declare_gilstate: self.put("PyGILState_STATE ") self.putln("%s = PyGILState_Ensure();" % variable) self.putln("#endif") def put_release_ensured_gil(self, variable=None): """ Releases the GIL, corresponds to `put_ensure_gil`. """ if not variable: variable = '__pyx_gilstate_save' self.putln("#ifdef WITH_THREAD") self.putln("PyGILState_Release(%s);" % variable) self.putln("#endif") def put_acquire_gil(self, variable=None): """ Acquire the GIL. The thread's thread state must have been initialized by a previous `put_release_gil` """ self.putln("#ifdef WITH_THREAD") if variable: self.putln('_save = %s;' % variable) self.putln("Py_BLOCK_THREADS") self.putln("#endif") def put_release_gil(self, variable=None): "Release the GIL, corresponds to `put_acquire_gil`." self.putln("#ifdef WITH_THREAD") self.putln("PyThreadState *_save;") self.putln("Py_UNBLOCK_THREADS") if variable: self.putln('%s = _save;' % variable) self.putln("#endif") def declare_gilstate(self): self.putln("#ifdef WITH_THREAD") self.putln("PyGILState_STATE __pyx_gilstate_save;") self.putln("#endif") # error handling def put_error_if_neg(self, pos, value): # return self.putln("if (unlikely(%s < 0)) %s" % (value, self.error_goto(pos))) # TODO this path is almost _never_ taken, yet this macro makes is slower! return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos))) def put_error_if_unbound(self, pos, entry, in_nogil_context=False): import ExprNodes if entry.from_closure: func = '__Pyx_RaiseClosureNameError' self.globalstate.use_utility_code( ExprNodes.raise_closure_name_error_utility_code) elif entry.type.is_memoryviewslice and in_nogil_context: func = '__Pyx_RaiseUnboundMemoryviewSliceNogil' self.globalstate.use_utility_code( ExprNodes.raise_unbound_memoryview_utility_code_nogil) else: func = '__Pyx_RaiseUnboundLocalError' self.globalstate.use_utility_code( ExprNodes.raise_unbound_local_error_utility_code) self.putln('if (unlikely(!%s)) { %s("%s"); %s }' % ( entry.type.check_for_null_code(entry.cname), func, entry.name, self.error_goto(pos))) def set_error_info(self, pos, used=False): self.funcstate.should_declare_error_indicator = True if used: self.funcstate.uses_error_indicator = True if self.c_line_in_traceback: cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro) else: cinfo = "" return "%s = %s[%s]; %s = %s;%s" % ( Naming.filename_cname, Naming.filetable_cname, self.lookup_filename(pos[0]), Naming.lineno_cname, pos[1], cinfo) def error_goto(self, pos): lbl = self.funcstate.error_label self.funcstate.use_label(lbl) return "{%s goto %s;}" % ( self.set_error_info(pos), lbl) def error_goto_if(self, cond, pos): return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos)) def error_goto_if_null(self, cname, pos): return self.error_goto_if("!%s" % cname, pos) def error_goto_if_neg(self, cname, pos): return self.error_goto_if("%s < 0" % cname, pos) def error_goto_if_PyErr(self, pos): return self.error_goto_if("PyErr_Occurred()", pos) def lookup_filename(self, filename): return self.globalstate.lookup_filename(filename) def put_declare_refcount_context(self): self.putln('__Pyx_RefNannyDeclarations') def put_setup_refcount_context(self, name, acquire_gil=False): if acquire_gil: self.globalstate.use_utility_code( UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c")) self.putln('__Pyx_RefNannySetupContext("%s", %d);' % (name, acquire_gil and 1 or 0)) def put_finish_refcount_context(self): self.putln("__Pyx_RefNannyFinishContext();") def put_add_traceback(self, qualified_name): """ Build a Python traceback for propagating exceptions. qualified_name should be the qualified name of the function. """ format_tuple = ( qualified_name, Naming.clineno_cname, Naming.lineno_cname, Naming.filename_cname, ) self.funcstate.uses_error_indicator = True self.putln('__Pyx_AddTraceback("%s", %s, %s, %s);' % format_tuple) def put_unraisable(self, qualified_name): """ Generate code to print a Python warning for an unraisable exception. qualified_name should be the qualified name of the function. """ format_tuple = ( qualified_name, Naming.clineno_cname, Naming.lineno_cname, Naming.filename_cname, int(self.globalstate.directives['unraisable_tracebacks']) ) self.funcstate.uses_error_indicator = True self.putln('__Pyx_WriteUnraisable("%s", %s, %s, %s, %s);' % format_tuple) self.globalstate.use_utility_code( UtilityCode.load_cached("WriteUnraisableException", "Exceptions.c")) def put_trace_declarations(self): self.putln('__Pyx_TraceDeclarations') def put_trace_call(self, name, pos): self.putln('__Pyx_TraceCall("%s", %s[%s], %s);' % (name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1])) def put_trace_exception(self): self.putln("__Pyx_TraceException();") def put_trace_return(self, retvalue_cname): self.putln("__Pyx_TraceReturn(%s);" % retvalue_cname) def putln_openmp(self, string): self.putln("#ifdef _OPENMP") self.putln(string) self.putln("#endif /* _OPENMP */") def undef_builtin_expect(self, cond): """ Redefine the macros likely() and unlikely to no-ops, depending on condition 'cond' """ self.putln("#if %s" % cond) self.putln(" #undef likely") self.putln(" #undef unlikely") self.putln(" #define likely(x) (x)") self.putln(" #define unlikely(x) (x)") self.putln("#endif") def redef_builtin_expect(self, cond): self.putln("#if %s" % cond) self.putln(" #undef likely") self.putln(" #undef unlikely") self.putln(" #define likely(x) __builtin_expect(!!(x), 1)") self.putln(" #define unlikely(x) __builtin_expect(!!(x), 0)") self.putln("#endif") class PyrexCodeWriter(object): # f file output file # level int indentation level def __init__(self, outfile_name): self.f = Utils.open_new_file(outfile_name) self.level = 0 def putln(self, code): self.f.write("%s%s\n" % (" " * self.level, code)) def indent(self): self.level += 1 def dedent(self): self.level -= 1 class PyxCodeWriter(object): """ Can be used for writing out some Cython code. To use the indenter functionality, the Cython.Compiler.Importer module will have to be used to load the code to support python 2.4 """ def __init__(self, buffer=None, indent_level=0, context=None, encoding='ascii'): self.buffer = buffer or StringIOTree() self.level = indent_level self.context = context self.encoding = encoding def indent(self, levels=1): self.level += levels return True def dedent(self, levels=1): self.level -= levels def indenter(self, line): """ Instead of with pyx_code.indenter("for i in range(10):"): pyx_code.putln("print i") write if pyx_code.indenter("for i in range(10);"): pyx_code.putln("print i") pyx_code.dedent() """ self.putln(line) self.indent() return True def getvalue(self): result = self.buffer.getvalue() if not isinstance(result, unicode): result = result.decode(self.encoding) return result def putln(self, line, context=None): context = context or self.context if context: line = sub_tempita(line, context) self._putln(line) def _putln(self, line): self.buffer.write("%s%s\n" % (self.level * " ", line)) def put_chunk(self, chunk, context=None): context = context or self.context if context: chunk = sub_tempita(chunk, context) chunk = textwrap.dedent(chunk) for line in chunk.splitlines(): self._putln(line) def insertion_point(self): return PyxCodeWriter(self.buffer.insertion_point(), self.level, self.context) def named_insertion_point(self, name): setattr(self, name, self.insertion_point()) class ClosureTempAllocator(object): def __init__(self, klass): self.klass = klass self.temps_allocated = {} self.temps_free = {} self.temps_count = 0 def reset(self): for type, cnames in self.temps_allocated.items(): self.temps_free[type] = list(cnames) def allocate_temp(self, type): if not type in self.temps_allocated: self.temps_allocated[type] = [] self.temps_free[type] = [] elif self.temps_free[type]: return self.temps_free[type].pop(0) cname = '%s%d' % (Naming.codewriter_temp_prefix, self.temps_count) self.klass.declare_var(pos=None, name=cname, cname=cname, type=type, is_cdef=True) self.temps_allocated[type].append(cname) self.temps_count += 1 return cname cython-0.20.1+git90-g0e6e38e/Cython/Compiler/CodeGeneration.py000066400000000000000000000021111231323242300235160ustar00rootroot00000000000000from Cython.Compiler.Visitor import VisitorTransform from Cython.Compiler.Nodes import StatListNode class ExtractPxdCode(VisitorTransform): """ Finds nodes in a pxd file that should generate code, and returns them in a StatListNode. The result is a tuple (StatListNode, ModuleScope), i.e. everything that is needed from the pxd after it is processed. A purer approach would be to seperately compile the pxd code, but the result would have to be slightly more sophisticated than pure strings (functions + wanted interned strings + wanted utility code + wanted cached objects) so for now this approach is taken. """ def __call__(self, root): self.funcs = [] self.visitchildren(root) return (StatListNode(root.pos, stats=self.funcs), root.scope) def visit_FuncDefNode(self, node): self.funcs.append(node) # Do not visit children, nested funcdefnodes will # also be moved by this action... return node def visit_Node(self, node): self.visitchildren(node) return node cython-0.20.1+git90-g0e6e38e/Cython/Compiler/CythonScope.py000066400000000000000000000132711231323242300230770ustar00rootroot00000000000000from Symtab import ModuleScope from PyrexTypes import * from UtilityCode import CythonUtilityCode from Errors import error from Scanning import StringSourceDescriptor import MemoryView class CythonScope(ModuleScope): is_cython_builtin = 1 _cythonscope_initialized = False def __init__(self, context): ModuleScope.__init__(self, u'cython', None, None) self.pxd_file_loaded = True self.populate_cython_scope() # The Main.Context object self.context = context for fused_type in (cy_integral_type, cy_floating_type, cy_numeric_type): entry = self.declare_typedef(fused_type.name, fused_type, None, cname='') entry.in_cinclude = True def lookup_type(self, name): # This function should go away when types are all first-level objects. type = parse_basic_type(name) if type: return type return super(CythonScope, self).lookup_type(name) def lookup(self, name): entry = super(CythonScope, self).lookup(name) if entry is None and not self._cythonscope_initialized: self.load_cythonscope() entry = super(CythonScope, self).lookup(name) return entry def find_module(self, module_name, pos): error("cython.%s is not available" % module_name, pos) def find_submodule(self, module_name): entry = self.entries.get(module_name, None) if not entry: self.load_cythonscope() entry = self.entries.get(module_name, None) if entry and entry.as_module: return entry.as_module else: # TODO: fix find_submodule control flow so that we're not # expected to create a submodule here (to protect CythonScope's # possible immutability). Hack ourselves out of the situation # for now. raise error((StringSourceDescriptor(u"cython", u""), 0, 0), "cython.%s is not available" % module_name) def lookup_qualified_name(self, qname): # ExprNode.as_cython_attribute generates qnames and we untangle it here... name_path = qname.split(u'.') scope = self while len(name_path) > 1: scope = scope.lookup_here(name_path[0]).as_module del name_path[0] if scope is None: return None else: return scope.lookup_here(name_path[0]) def populate_cython_scope(self): # These are used to optimize isinstance in FinalOptimizePhase type_object = self.declare_typedef( 'PyTypeObject', base_type = c_void_type, pos = None, cname = 'PyTypeObject') type_object.is_void = True type_object_type = type_object.type self.declare_cfunction( 'PyObject_TypeCheck', CFuncType(c_bint_type, [CFuncTypeArg("o", py_object_type, None), CFuncTypeArg("t", c_ptr_type(type_object_type), None)]), pos = None, defining = 1, cname = 'PyObject_TypeCheck') def load_cythonscope(self): """ Creates some entries for testing purposes and entries for cython.array() and for cython.view.*. """ if self._cythonscope_initialized: return self._cythonscope_initialized = True cython_testscope_utility_code.declare_in_scope( self, cython_scope=self) cython_test_extclass_utility_code.declare_in_scope( self, cython_scope=self) # # The view sub-scope # self.viewscope = viewscope = ModuleScope(u'view', self, None) self.declare_module('view', viewscope, None).as_module = viewscope viewscope.is_cython_builtin = True viewscope.pxd_file_loaded = True cythonview_testscope_utility_code.declare_in_scope( viewscope, cython_scope=self) view_utility_scope = MemoryView.view_utility_code.declare_in_scope( self.viewscope, cython_scope=self, whitelist=MemoryView.view_utility_whitelist) # self.entries["array"] = view_utility_scope.entries.pop("array") def create_cython_scope(context): # One could in fact probably make it a singleton, # but not sure yet whether any code mutates it (which would kill reusing # it across different contexts) return CythonScope(context) # Load test utilities for the cython scope def load_testscope_utility(cy_util_name, **kwargs): return CythonUtilityCode.load(cy_util_name, "TestCythonScope.pyx", **kwargs) undecorated_methods_protos = UtilityCode(proto=u""" /* These methods are undecorated and have therefore no prototype */ static PyObject *__pyx_TestClass_cdef_method( struct __pyx_TestClass_obj *self, int value); static PyObject *__pyx_TestClass_cpdef_method( struct __pyx_TestClass_obj *self, int value, int skip_dispatch); static PyObject *__pyx_TestClass_def_method( PyObject *self, PyObject *value); """) cython_testscope_utility_code = load_testscope_utility("TestScope") test_cython_utility_dep = load_testscope_utility("TestDep") cython_test_extclass_utility_code = \ load_testscope_utility("TestClass", name="TestClass", requires=[undecorated_methods_protos, test_cython_utility_dep]) cythonview_testscope_utility_code = load_testscope_utility("View.TestScope") cython-0.20.1+git90-g0e6e38e/Cython/Compiler/DebugFlags.py000066400000000000000000000011571231323242300226440ustar00rootroot00000000000000# Can be enabled at the command line with --debug-xxx. debug_disposal_code = 0 debug_temp_alloc = 0 debug_coercion = 0 # Write comments into the C code that show where temporary variables # are allocated and released. debug_temp_code_comments = 0 # Write a call trace of the code generation phase into the C code. debug_trace_code_generation = 0 # Do not replace exceptions with user-friendly error messages. debug_no_exception_intercept = 0 # Print a message each time a new stage in the pipeline is entered. debug_verbose_pipeline = 0 # Raise an exception when an error is encountered. debug_exception_on_error = 0 cython-0.20.1+git90-g0e6e38e/Cython/Compiler/Errors.py000066400000000000000000000157321231323242300221210ustar00rootroot00000000000000# # Errors # import sys from Cython.Utils import open_new_file import DebugFlags import Options class PyrexError(Exception): pass class PyrexWarning(Exception): pass def context(position): source = position[0] assert not (isinstance(source, unicode) or isinstance(source, str)), ( "Please replace filename strings with Scanning.FileSourceDescriptor instances %r" % source) try: F = source.get_lines() except UnicodeDecodeError: # file has an encoding problem s = u"[unprintable code]\n" else: s = u''.join(F[max(0, position[1]-6):position[1]]) s = u'...\n%s%s^\n' % (s, u' '*(position[2]-1)) s = u'%s\n%s%s\n' % (u'-'*60, s, u'-'*60) return s def format_position(position): if position: return u"%s:%d:%d: " % (position[0].get_error_description(), position[1], position[2]) return u'' def format_error(message, position): if position: pos_str = format_position(position) cont = context(position) message = u'\nError compiling Cython file:\n%s\n%s%s' % (cont, pos_str, message or u'') return message class CompileError(PyrexError): def __init__(self, position = None, message = u""): self.position = position self.message_only = message self.formatted_message = format_error(message, position) self.reported = False # Deprecated and withdrawn in 2.6: # self.message = message Exception.__init__(self, self.formatted_message) # Python Exception subclass pickling is broken, # see http://bugs.python.org/issue1692335 self.args = (position, message) def __str__(self): return self.formatted_message class CompileWarning(PyrexWarning): def __init__(self, position = None, message = ""): self.position = position # Deprecated and withdrawn in 2.6: # self.message = message Exception.__init__(self, format_position(position) + message) class InternalError(Exception): # If this is ever raised, there is a bug in the compiler. def __init__(self, message): self.message_only = message Exception.__init__(self, u"Internal compiler error: %s" % message) class AbortError(Exception): # Throw this to stop the compilation immediately. def __init__(self, message): self.message_only = message Exception.__init__(self, u"Abort error: %s" % message) class CompilerCrash(CompileError): # raised when an unexpected exception occurs in a transform def __init__(self, pos, context, message, cause, stacktrace=None): if message: message = u'\n' + message else: message = u'\n' self.message_only = message if context: message = u"Compiler crash in %s%s" % (context, message) if stacktrace: import traceback message += ( u'\n\nCompiler crash traceback from this point on:\n' + u''.join(traceback.format_tb(stacktrace))) if cause: if not stacktrace: message += u'\n' message += u'%s: %s' % (cause.__class__.__name__, cause) CompileError.__init__(self, pos, message) # Python Exception subclass pickling is broken, # see http://bugs.python.org/issue1692335 self.args = (pos, context, message, cause, stacktrace) class NoElementTreeInstalledException(PyrexError): """raised when the user enabled options.gdb_debug but no ElementTree implementation was found """ listing_file = None num_errors = 0 echo_file = None def open_listing_file(path, echo_to_stderr = 1): # Begin a new error listing. If path is None, no file # is opened, the error counter is just reset. global listing_file, num_errors, echo_file if path is not None: listing_file = open_new_file(path) else: listing_file = None if echo_to_stderr: echo_file = sys.stderr else: echo_file = None num_errors = 0 def close_listing_file(): global listing_file if listing_file: listing_file.close() listing_file = None def report_error(err): if error_stack: error_stack[-1].append(err) else: global num_errors # See Main.py for why dual reporting occurs. Quick fix for now. if err.reported: return err.reported = True try: line = u"%s\n" % err except UnicodeEncodeError: # Python <= 2.5 does this for non-ASCII Unicode exceptions line = format_error(getattr(err, 'message_only', "[unprintable exception message]"), getattr(err, 'position', None)) + u'\n' if listing_file: try: listing_file.write(line) except UnicodeEncodeError: listing_file.write(line.encode('ASCII', 'replace')) if echo_file: try: echo_file.write(line) except UnicodeEncodeError: echo_file.write(line.encode('ASCII', 'replace')) num_errors = num_errors + 1 if Options.fast_fail: raise AbortError("fatal errors") def error(position, message): #print "Errors.error:", repr(position), repr(message) ### if position is None: raise InternalError(message) err = CompileError(position, message) if DebugFlags.debug_exception_on_error: raise Exception(err) # debug report_error(err) return err LEVEL=1 # warn about all errors level 1 or higher def message(position, message, level=1): if level < LEVEL: return warn = CompileWarning(position, message) line = "note: %s\n" % warn if listing_file: listing_file.write(line) if echo_file: echo_file.write(line) return warn def warning(position, message, level=0): if level < LEVEL: return if Options.warning_errors and position: return error(position, message) warn = CompileWarning(position, message) line = "warning: %s\n" % warn if listing_file: listing_file.write(line) if echo_file: echo_file.write(line) return warn _warn_once_seen = {} def warn_once(position, message, level=0): if level < LEVEL or message in _warn_once_seen: return warn = CompileWarning(position, message) line = "warning: %s\n" % warn if listing_file: listing_file.write(line) if echo_file: echo_file.write(line) _warn_once_seen[message] = True return warn # These functions can be used to momentarily suppress errors. error_stack = [] def hold_errors(): error_stack.append([]) def release_errors(ignore=False): held_errors = error_stack.pop() if not ignore: for err in held_errors: report_error(err) def held_errors(): return error_stack[-1] # this module needs a redesign to support parallel cythonisation, but # for now, the following works at least in sequential compiler runs def reset(): _warn_once_seen.clear() del error_stack[:] cython-0.20.1+git90-g0e6e38e/Cython/Compiler/ExprNodes.py000066400000000000000000015333711231323242300225610ustar00rootroot00000000000000# # Parse tree nodes for expressions # import cython cython.declare(error=object, warning=object, warn_once=object, InternalError=object, CompileError=object, UtilityCode=object, TempitaUtilityCode=object, StringEncoding=object, operator=object, Naming=object, Nodes=object, PyrexTypes=object, py_object_type=object, list_type=object, tuple_type=object, set_type=object, dict_type=object, unicode_type=object, str_type=object, bytes_type=object, type_type=object, Builtin=object, Symtab=object, Utils=object, find_coercion_error=object, debug_disposal_code=object, debug_temp_alloc=object, debug_coercion=object, bytearray_type=object, slice_type=object) import sys import copy import operator from Errors import error, warning, warn_once, InternalError, CompileError from Errors import hold_errors, release_errors, held_errors, report_error from Code import UtilityCode, TempitaUtilityCode import StringEncoding import Naming import Nodes from Nodes import Node import PyrexTypes from PyrexTypes import py_object_type, c_long_type, typecast, error_type, \ unspecified_type import TypeSlots from Builtin import list_type, tuple_type, set_type, dict_type, type_type, \ unicode_type, str_type, bytes_type, bytearray_type, basestring_type, slice_type import Builtin import Symtab from Cython import Utils from Annotate import AnnotationItem from Cython.Compiler import Future from Cython.Debugging import print_call_chain from DebugFlags import debug_disposal_code, debug_temp_alloc, \ debug_coercion try: from __builtin__ import basestring except ImportError: basestring = str # Python 3 try: from builtins import bytes except ImportError: bytes = str # Python 2 class NotConstant(object): _obj = None def __new__(cls): if NotConstant._obj is None: NotConstant._obj = super(NotConstant, cls).__new__(cls) return NotConstant._obj def __repr__(self): return "" not_a_constant = NotConstant() constant_value_not_set = object() # error messages when coercing from key[0] to key[1] coercion_error_dict = { # string related errors (Builtin.unicode_type, Builtin.bytes_type) : "Cannot convert Unicode string to 'bytes' implicitly, encoding required.", (Builtin.unicode_type, Builtin.str_type) : "Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.", (Builtin.unicode_type, PyrexTypes.c_char_ptr_type) : "Unicode objects only support coercion to Py_UNICODE*.", (Builtin.unicode_type, PyrexTypes.c_uchar_ptr_type) : "Unicode objects only support coercion to Py_UNICODE*.", (Builtin.bytes_type, Builtin.unicode_type) : "Cannot convert 'bytes' object to unicode implicitly, decoding required", (Builtin.bytes_type, Builtin.str_type) : "Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.", (Builtin.bytes_type, Builtin.basestring_type) : "Cannot convert 'bytes' object to basestring implicitly. This is not portable to Py3.", (Builtin.bytes_type, PyrexTypes.c_py_unicode_ptr_type) : "Cannot convert 'bytes' object to Py_UNICODE*, use 'unicode'.", (Builtin.basestring_type, Builtin.bytes_type) : "Cannot convert 'basestring' object to bytes implicitly. This is not portable.", (Builtin.str_type, Builtin.unicode_type) : "str objects do not support coercion to unicode, use a unicode string literal instead (u'')", (Builtin.str_type, Builtin.bytes_type) : "Cannot convert 'str' to 'bytes' implicitly. This is not portable.", (Builtin.str_type, PyrexTypes.c_char_ptr_type) : "'str' objects do not support coercion to C types (use 'bytes'?).", (Builtin.str_type, PyrexTypes.c_uchar_ptr_type) : "'str' objects do not support coercion to C types (use 'bytes'?).", (Builtin.str_type, PyrexTypes.c_py_unicode_ptr_type) : "'str' objects do not support coercion to C types (use 'unicode'?).", (PyrexTypes.c_char_ptr_type, Builtin.unicode_type) : "Cannot convert 'char*' to unicode implicitly, decoding required", (PyrexTypes.c_uchar_ptr_type, Builtin.unicode_type) : "Cannot convert 'char*' to unicode implicitly, decoding required", } def find_coercion_error(type_tuple, default, env): err = coercion_error_dict.get(type_tuple) if err is None: return default elif ((PyrexTypes.c_char_ptr_type in type_tuple or PyrexTypes.c_uchar_ptr_type in type_tuple) and env.directives['c_string_encoding']): if type_tuple[1].is_pyobject: return default elif env.directives['c_string_encoding'] in ('ascii', 'default'): return default else: return "'%s' objects do not support coercion to C types with non-ascii or non-default c_string_encoding" % type_tuple[0].name else: return err def default_str_type(env): return { 'bytes': bytes_type, 'bytearray': bytearray_type, 'str': str_type, 'unicode': unicode_type }.get(env.directives['c_string_type']) def check_negative_indices(*nodes): """ Raise a warning on nodes that are known to have negative numeric values. Used to find (potential) bugs inside of "wraparound=False" sections. """ for node in nodes: if (node is None or not isinstance(node.constant_result, (int, float, long))): continue if node.constant_result < 0: warning(node.pos, "the result of using negative indices inside of " "code sections marked as 'wraparound=False' is " "undefined", level=1) def infer_sequence_item_type(env, seq_node, index_node=None, seq_type=None): if not seq_node.is_sequence_constructor: if seq_type is None: seq_type = seq_node.infer_type(env) if seq_type is tuple_type: # tuples are immutable => we can safely follow assignments if seq_node.cf_state and len(seq_node.cf_state) == 1: try: seq_node = seq_node.cf_state[0].rhs except AttributeError: pass if seq_node is not None and seq_node.is_sequence_constructor: if index_node is not None and index_node.has_constant_result(): try: item = seq_node.args[index_node.constant_result] except (ValueError, TypeError, IndexError): pass else: return item.infer_type(env) # if we're lucky, all items have the same type item_types = set([item.infer_type(env) for item in seq_node.args]) if len(item_types) == 1: return item_types.pop() return None class ExprNode(Node): # subexprs [string] Class var holding names of subexpr node attrs # type PyrexType Type of the result # result_code string Code fragment # result_ctype string C type of result_code if different from type # is_temp boolean Result is in a temporary variable # is_sequence_constructor # boolean Is a list or tuple constructor expression # is_starred boolean Is a starred expression (e.g. '*a') # saved_subexpr_nodes # [ExprNode or [ExprNode or None] or None] # Cached result of subexpr_nodes() # use_managed_ref boolean use ref-counted temps/assignments/etc. # result_is_used boolean indicates that the result will be dropped and the # result_code/temp_result can safely be set to None result_ctype = None type = None temp_code = None old_temp = None # error checker for multiple frees etc. use_managed_ref = True # can be set by optimisation transforms result_is_used = True # The Analyse Expressions phase for expressions is split # into two sub-phases: # # Analyse Types # Determines the result type of the expression based # on the types of its sub-expressions, and inserts # coercion nodes into the expression tree where needed. # Marks nodes which will need to have temporary variables # allocated. # # Allocate Temps # Allocates temporary variables where needed, and fills # in the result_code field of each node. # # ExprNode provides some convenience routines which # perform both of the above phases. These should only # be called from statement nodes, and only when no # coercion nodes need to be added around the expression # being analysed. In that case, the above two phases # should be invoked separately. # # Framework code in ExprNode provides much of the common # processing for the various phases. It makes use of the # 'subexprs' class attribute of ExprNodes, which should # contain a list of the names of attributes which can # hold sub-nodes or sequences of sub-nodes. # # The framework makes use of a number of abstract methods. # Their responsibilities are as follows. # # Declaration Analysis phase # # analyse_target_declaration # Called during the Analyse Declarations phase to analyse # the LHS of an assignment or argument of a del statement. # Nodes which cannot be the LHS of an assignment need not # implement it. # # Expression Analysis phase # # analyse_types # - Call analyse_types on all sub-expressions. # - Check operand types, and wrap coercion nodes around # sub-expressions where needed. # - Set the type of this node. # - If a temporary variable will be required for the # result, set the is_temp flag of this node. # # analyse_target_types # Called during the Analyse Types phase to analyse # the LHS of an assignment or argument of a del # statement. Similar responsibilities to analyse_types. # # target_code # Called by the default implementation of allocate_target_temps. # Should return a C lvalue for assigning to the node. The default # implementation calls calculate_result_code. # # check_const # - Check that this node and its subnodes form a # legal constant expression. If so, do nothing, # otherwise call not_const. # # The default implementation of check_const # assumes that the expression is not constant. # # check_const_addr # - Same as check_const, except check that the # expression is a C lvalue whose address is # constant. Otherwise, call addr_not_const. # # The default implementation of calc_const_addr # assumes that the expression is not a constant # lvalue. # # Code Generation phase # # generate_evaluation_code # - Call generate_evaluation_code for sub-expressions. # - Perform the functions of generate_result_code # (see below). # - If result is temporary, call generate_disposal_code # on all sub-expressions. # # A default implementation of generate_evaluation_code # is provided which uses the following abstract methods: # # generate_result_code # - Generate any C statements necessary to calculate # the result of this node from the results of its # sub-expressions. # # calculate_result_code # - Should return a C code fragment evaluating to the # result. This is only called when the result is not # a temporary. # # generate_assignment_code # Called on the LHS of an assignment. # - Call generate_evaluation_code for sub-expressions. # - Generate code to perform the assignment. # - If the assignment absorbed a reference, call # generate_post_assignment_code on the RHS, # otherwise call generate_disposal_code on it. # # generate_deletion_code # Called on an argument of a del statement. # - Call generate_evaluation_code for sub-expressions. # - Generate code to perform the deletion. # - Call generate_disposal_code on all sub-expressions. # # is_sequence_constructor = 0 is_string_literal = 0 is_attribute = 0 is_subscript = 0 saved_subexpr_nodes = None is_temp = 0 is_target = 0 is_starred = 0 constant_result = constant_value_not_set # whether this node with a memoryview type should be broadcast memslice_broadcast = False child_attrs = property(fget=operator.attrgetter('subexprs')) def not_implemented(self, method_name): print_call_chain(method_name, "not implemented") ### raise InternalError( "%s.%s not implemented" % (self.__class__.__name__, method_name)) def is_lvalue(self): return 0 def is_addressable(self): return self.is_lvalue() and not self.type.is_memoryviewslice def is_ephemeral(self): # An ephemeral node is one whose result is in # a Python temporary and we suspect there are no # other references to it. Certain operations are # disallowed on such values, since they are # likely to result in a dangling pointer. return self.type.is_pyobject and self.is_temp def subexpr_nodes(self): # Extract a list of subexpression nodes based # on the contents of the subexprs class attribute. nodes = [] for name in self.subexprs: item = getattr(self, name) if item is not None: if type(item) is list: nodes.extend(item) else: nodes.append(item) return nodes def result(self): if self.is_temp: return self.temp_code else: return self.calculate_result_code() def result_as(self, type = None): # Return the result code cast to the specified C type. if (self.is_temp and self.type.is_pyobject and type != py_object_type): # Allocated temporaries are always PyObject *, which may not # reflect the actual type (e.g. an extension type) return typecast(type, py_object_type, self.result()) return typecast(type, self.ctype(), self.result()) def py_result(self): # Return the result code cast to PyObject *. return self.result_as(py_object_type) def ctype(self): # Return the native C type of the result (i.e. the # C type of the result_code expression). return self.result_ctype or self.type def get_constant_c_result_code(self): # Return the constant value of this node as a result code # string, or None if the node is not constant. This method # can be called when the constant result code is required # before the code generation phase. # # The return value is a string that can represent a simple C # value, a constant C name or a constant C expression. If the # node type depends on Python code, this must return None. return None def calculate_constant_result(self): # Calculate the constant compile time result value of this # expression and store it in ``self.constant_result``. Does # nothing by default, thus leaving ``self.constant_result`` # unknown. If valid, the result can be an arbitrary Python # value. # # This must only be called when it is assured that all # sub-expressions have a valid constant_result value. The # ConstantFolding transform will do this. pass def has_constant_result(self): return self.constant_result is not constant_value_not_set and \ self.constant_result is not not_a_constant def compile_time_value(self, denv): # Return value of compile-time expression, or report error. error(self.pos, "Invalid compile-time expression") def compile_time_value_error(self, e): error(self.pos, "Error in compile-time expression: %s: %s" % ( e.__class__.__name__, e)) # ------------- Declaration Analysis ---------------- def analyse_target_declaration(self, env): error(self.pos, "Cannot assign to or delete this") # ------------- Expression Analysis ---------------- def analyse_const_expression(self, env): # Called during the analyse_declarations phase of a # constant expression. Analyses the expression's type, # checks whether it is a legal const expression, # and determines its value. node = self.analyse_types(env) node.check_const() return node def analyse_expressions(self, env): # Convenience routine performing both the Type # Analysis and Temp Allocation phases for a whole # expression. return self.analyse_types(env) def analyse_target_expression(self, env, rhs): # Convenience routine performing both the Type # Analysis and Temp Allocation phases for the LHS of # an assignment. return self.analyse_target_types(env) def analyse_boolean_expression(self, env): # Analyse expression and coerce to a boolean. node = self.analyse_types(env) bool = node.coerce_to_boolean(env) return bool def analyse_temp_boolean_expression(self, env): # Analyse boolean expression and coerce result into # a temporary. This is used when a branch is to be # performed on the result and we won't have an # opportunity to ensure disposal code is executed # afterwards. By forcing the result into a temporary, # we ensure that all disposal has been done by the # time we get the result. node = self.analyse_types(env) return node.coerce_to_boolean(env).coerce_to_simple(env) # --------------- Type Inference ----------------- def type_dependencies(self, env): # Returns the list of entries whose types must be determined # before the type of self can be inferred. if hasattr(self, 'type') and self.type is not None: return () return sum([node.type_dependencies(env) for node in self.subexpr_nodes()], ()) def infer_type(self, env): # Attempt to deduce the type of self. # Differs from analyse_types as it avoids unnecessary # analysis of subexpressions, but can assume everything # in self.type_dependencies() has been resolved. if hasattr(self, 'type') and self.type is not None: return self.type elif hasattr(self, 'entry') and self.entry is not None: return self.entry.type else: self.not_implemented("infer_type") def nonlocally_immutable(self): # Returns whether this variable is a safe reference, i.e. # can't be modified as part of globals or closures. return self.is_literal or self.is_temp or self.type.is_array or self.type.is_cfunction # --------------- Type Analysis ------------------ def analyse_as_module(self, env): # If this node can be interpreted as a reference to a # cimported module, return its scope, else None. return None def analyse_as_type(self, env): # If this node can be interpreted as a reference to a # type, return that type, else None. return None def analyse_as_extension_type(self, env): # If this node can be interpreted as a reference to an # extension type or builtin type, return its type, else None. return None def analyse_types(self, env): self.not_implemented("analyse_types") def analyse_target_types(self, env): return self.analyse_types(env) def nogil_check(self, env): # By default, any expression based on Python objects is # prevented in nogil environments. Subtypes must override # this if they can work without the GIL. if self.type and self.type.is_pyobject: self.gil_error() def gil_assignment_check(self, env): if env.nogil and self.type.is_pyobject: error(self.pos, "Assignment of Python object not allowed without gil") def check_const(self): self.not_const() return False def not_const(self): error(self.pos, "Not allowed in a constant expression") def check_const_addr(self): self.addr_not_const() return False def addr_not_const(self): error(self.pos, "Address is not constant") # ----------------- Result Allocation ----------------- def result_in_temp(self): # Return true if result is in a temporary owned by # this node or one of its subexpressions. Overridden # by certain nodes which can share the result of # a subnode. return self.is_temp def target_code(self): # Return code fragment for use as LHS of a C assignment. return self.calculate_result_code() def calculate_result_code(self): self.not_implemented("calculate_result_code") # def release_target_temp(self, env): # # Release temporaries used by LHS of an assignment. # self.release_subexpr_temps(env) def allocate_temp_result(self, code): if self.temp_code: raise RuntimeError("Temp allocated multiple times in %r: %r" % (self.__class__.__name__, self.pos)) type = self.type if not type.is_void: if type.is_pyobject: type = PyrexTypes.py_object_type self.temp_code = code.funcstate.allocate_temp( type, manage_ref=self.use_managed_ref) else: self.temp_code = None def release_temp_result(self, code): if not self.temp_code: if not self.result_is_used: # not used anyway, so ignore if not set up return if self.old_temp: raise RuntimeError("temp %s released multiple times in %s" % ( self.old_temp, self.__class__.__name__)) else: raise RuntimeError("no temp, but release requested in %s" % ( self.__class__.__name__)) code.funcstate.release_temp(self.temp_code) self.old_temp = self.temp_code self.temp_code = None # ---------------- Code Generation ----------------- def make_owned_reference(self, code): """ If result is a pyobject, make sure we own a reference to it. If the result is in a temp, it is already a new reference. """ if self.type.is_pyobject and not self.result_in_temp(): code.put_incref(self.result(), self.ctype()) def make_owned_memoryviewslice(self, code): """ Make sure we own the reference to this memoryview slice. """ if not self.result_in_temp(): code.put_incref_memoryviewslice(self.result(), have_gil=self.in_nogil_context) def generate_evaluation_code(self, code): # Generate code to evaluate this node and # its sub-expressions, and dispose of any # temporary results of its sub-expressions. self.generate_subexpr_evaluation_code(code) code.mark_pos(self.pos) if self.is_temp: self.allocate_temp_result(code) self.generate_result_code(code) if self.is_temp: # If we are temp we do not need to wait until this node is disposed # before disposing children. self.generate_subexpr_disposal_code(code) self.free_subexpr_temps(code) def generate_subexpr_evaluation_code(self, code): for node in self.subexpr_nodes(): node.generate_evaluation_code(code) def generate_result_code(self, code): self.not_implemented("generate_result_code") def generate_disposal_code(self, code): if self.is_temp: if self.result(): if self.type.is_pyobject: code.put_decref_clear(self.result(), self.ctype()) elif self.type.is_memoryviewslice: code.put_xdecref_memoryviewslice( self.result(), have_gil=not self.in_nogil_context) else: # Already done if self.is_temp self.generate_subexpr_disposal_code(code) def generate_subexpr_disposal_code(self, code): # Generate code to dispose of temporary results # of all sub-expressions. for node in self.subexpr_nodes(): node.generate_disposal_code(code) def generate_post_assignment_code(self, code): if self.is_temp: if self.type.is_pyobject: code.putln("%s = 0;" % self.result()) elif self.type.is_memoryviewslice: code.putln("%s.memview = NULL;" % self.result()) code.putln("%s.data = NULL;" % self.result()) else: self.generate_subexpr_disposal_code(code) def generate_assignment_code(self, rhs, code): # Stub method for nodes which are not legal as # the LHS of an assignment. An error will have # been reported earlier. pass def generate_deletion_code(self, code, ignore_nonexisting=False): # Stub method for nodes that are not legal as # the argument of a del statement. An error # will have been reported earlier. pass def free_temps(self, code): if self.is_temp: if not self.type.is_void: self.release_temp_result(code) else: self.free_subexpr_temps(code) def free_subexpr_temps(self, code): for sub in self.subexpr_nodes(): sub.free_temps(code) def generate_function_definitions(self, env, code): pass # ---------------- Annotation --------------------- def annotate(self, code): for node in self.subexpr_nodes(): node.annotate(code) # ----------------- Coercion ---------------------- def coerce_to(self, dst_type, env): # Coerce the result so that it can be assigned to # something of type dst_type. If processing is necessary, # wraps this node in a coercion node and returns that. # Otherwise, returns this node unchanged. # # This method is called during the analyse_expressions # phase of the src_node's processing. # # Note that subclasses that override this (especially # ConstNodes) must not (re-)set their own .type attribute # here. Since expression nodes may turn up in different # places in the tree (e.g. inside of CloneNodes in cascaded # assignments), this method must return a new node instance # if it changes the type. # src = self src_type = self.type if self.check_for_coercion_error(dst_type, env): return self if dst_type.is_reference and not src_type.is_reference: dst_type = dst_type.ref_base_type if src_type.is_const: src_type = src_type.const_base_type if src_type.is_fused or dst_type.is_fused: # See if we are coercing a fused function to a pointer to a # specialized function if (src_type.is_cfunction and not dst_type.is_fused and dst_type.is_ptr and dst_type.base_type.is_cfunction): dst_type = dst_type.base_type for signature in src_type.get_all_specialized_function_types(): if signature.same_as(dst_type): src.type = signature src.entry = src.type.entry src.entry.used = True return self if src_type.is_fused: error(self.pos, "Type is not specialized") else: error(self.pos, "Cannot coerce to a type that is not specialized") self.type = error_type return self if self.coercion_type is not None: # This is purely for error checking purposes! node = NameNode(self.pos, name='', type=self.coercion_type) node.coerce_to(dst_type, env) if dst_type.is_memoryviewslice: import MemoryView if not src.type.is_memoryviewslice: if src.type.is_pyobject: src = CoerceToMemViewSliceNode(src, dst_type, env) elif src.type.is_array: src = CythonArrayNode.from_carray(src, env).coerce_to( dst_type, env) elif not src_type.is_error: error(self.pos, "Cannot convert '%s' to memoryviewslice" % (src_type,)) elif not MemoryView.src_conforms_to_dst( src.type, dst_type, broadcast=self.memslice_broadcast): if src.type.dtype.same_as(dst_type.dtype): msg = "Memoryview '%s' not conformable to memoryview '%s'." tup = src.type, dst_type else: msg = "Different base types for memoryviews (%s, %s)" tup = src.type.dtype, dst_type.dtype error(self.pos, msg % tup) elif dst_type.is_pyobject: if not src.type.is_pyobject: if dst_type is bytes_type and src.type.is_int: src = CoerceIntToBytesNode(src, env) else: src = CoerceToPyTypeNode(src, env, type=dst_type) if not src.type.subtype_of(dst_type): if src.constant_result is not None: src = PyTypeTestNode(src, dst_type, env) elif src.type.is_pyobject: src = CoerceFromPyTypeNode(dst_type, src, env) elif (dst_type.is_complex and src_type != dst_type and dst_type.assignable_from(src_type)): src = CoerceToComplexNode(src, dst_type, env) else: # neither src nor dst are py types # Added the string comparison, since for c types that # is enough, but Cython gets confused when the types are # in different pxi files. if not (str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)): self.fail_assignment(dst_type) return src def fail_assignment(self, dst_type): error(self.pos, "Cannot assign type '%s' to '%s'" % (self.type, dst_type)) def check_for_coercion_error(self, dst_type, env, fail=False, default=None): if fail and not default: default = "Cannot assign type '%(FROM)s' to '%(TO)s'" message = find_coercion_error((self.type, dst_type), default, env) if message is not None: error(self.pos, message % {'FROM': self.type, 'TO': dst_type}) return True if fail: self.fail_assignment(dst_type) return True return False def coerce_to_pyobject(self, env): return self.coerce_to(PyrexTypes.py_object_type, env) def coerce_to_boolean(self, env): # Coerce result to something acceptable as # a boolean value. # if it's constant, calculate the result now if self.has_constant_result(): bool_value = bool(self.constant_result) return BoolNode(self.pos, value=bool_value, constant_result=bool_value) type = self.type if type.is_enum or type.is_error: return self elif type.is_pyobject or type.is_int or type.is_ptr or type.is_float: return CoerceToBooleanNode(self, env) else: error(self.pos, "Type '%s' not acceptable as a boolean" % type) return self def coerce_to_integer(self, env): # If not already some C integer type, coerce to longint. if self.type.is_int: return self else: return self.coerce_to(PyrexTypes.c_long_type, env) def coerce_to_temp(self, env): # Ensure that the result is in a temporary. if self.result_in_temp(): return self else: return CoerceToTempNode(self, env) def coerce_to_simple(self, env): # Ensure that the result is simple (see is_simple). if self.is_simple(): return self else: return self.coerce_to_temp(env) def is_simple(self): # A node is simple if its result is something that can # be referred to without performing any operations, e.g. # a constant, local var, C global var, struct member # reference, or temporary. return self.result_in_temp() def may_be_none(self): if self.type and not (self.type.is_pyobject or self.type.is_memoryviewslice): return False if self.has_constant_result(): return self.constant_result is not None return True def as_cython_attribute(self): return None def as_none_safe_node(self, message, error="PyExc_TypeError", format_args=()): # Wraps the node in a NoneCheckNode if it is not known to be # not-None (e.g. because it is a Python literal). if self.may_be_none(): return NoneCheckNode(self, error, message, format_args) else: return self @classmethod def from_node(cls, node, **kwargs): """Instantiate this node class from another node, properly copying over all attributes that one would forget otherwise. """ attributes = "cf_state cf_maybe_null cf_is_null constant_result".split() for attr_name in attributes: if attr_name in kwargs: continue try: value = getattr(node, attr_name) except AttributeError: pass else: kwargs[attr_name] = value return cls(node.pos, **kwargs) class AtomicExprNode(ExprNode): # Abstract base class for expression nodes which have # no sub-expressions. subexprs = [] # Override to optimize -- we know we have no children def generate_subexpr_evaluation_code(self, code): pass def generate_subexpr_disposal_code(self, code): pass class PyConstNode(AtomicExprNode): # Abstract base class for constant Python values. is_literal = 1 type = py_object_type def is_simple(self): return 1 def may_be_none(self): return False def analyse_types(self, env): return self def calculate_result_code(self): return self.value def generate_result_code(self, code): pass class NoneNode(PyConstNode): # The constant value None is_none = 1 value = "Py_None" constant_result = None nogil_check = None def compile_time_value(self, denv): return None def may_be_none(self): return True class EllipsisNode(PyConstNode): # '...' in a subscript list. value = "Py_Ellipsis" constant_result = Ellipsis def compile_time_value(self, denv): return Ellipsis class ConstNode(AtomicExprNode): # Abstract base type for literal constant nodes. # # value string C code fragment is_literal = 1 nogil_check = None def is_simple(self): return 1 def nonlocally_immutable(self): return 1 def may_be_none(self): return False def analyse_types(self, env): return self # Types are held in class variables def check_const(self): return True def get_constant_c_result_code(self): return self.calculate_result_code() def calculate_result_code(self): return str(self.value) def generate_result_code(self, code): pass class BoolNode(ConstNode): type = PyrexTypes.c_bint_type # The constant value True or False def calculate_constant_result(self): self.constant_result = self.value def compile_time_value(self, denv): return self.value def calculate_result_code(self): if self.type.is_pyobject: return self.value and 'Py_True' or 'Py_False' else: return str(int(self.value)) def coerce_to(self, dst_type, env): if dst_type.is_pyobject and self.type.is_int: return BoolNode( self.pos, value=self.value, constant_result=self.constant_result, type=Builtin.bool_type) if dst_type.is_int and self.type.is_pyobject: return BoolNode( self.pos, value=self.value, constant_result=self.constant_result, type=PyrexTypes.c_bint_type) return ConstNode.coerce_to(self, dst_type, env) class NullNode(ConstNode): type = PyrexTypes.c_null_ptr_type value = "NULL" constant_result = 0 def get_constant_c_result_code(self): return self.value class CharNode(ConstNode): type = PyrexTypes.c_char_type def calculate_constant_result(self): self.constant_result = ord(self.value) def compile_time_value(self, denv): return ord(self.value) def calculate_result_code(self): return "'%s'" % StringEncoding.escape_char(self.value) class IntNode(ConstNode): # unsigned "" or "U" # longness "" or "L" or "LL" # is_c_literal True/False/None creator considers this a C integer literal unsigned = "" longness = "" is_c_literal = None # unknown def __init__(self, pos, **kwds): ExprNode.__init__(self, pos, **kwds) if 'type' not in kwds: self.type = self.find_suitable_type_for_value() def find_suitable_type_for_value(self): if self.constant_result is constant_value_not_set: try: self.calculate_constant_result() except ValueError: pass # we ignore 'is_c_literal = True' and instead map signed 32bit # integers as C long values if self.is_c_literal or \ self.constant_result in (constant_value_not_set, not_a_constant) or \ self.unsigned or self.longness == 'LL': # clearly a C literal rank = (self.longness == 'LL') and 2 or 1 suitable_type = PyrexTypes.modifiers_and_name_to_type[not self.unsigned, rank, "int"] if self.type: suitable_type = PyrexTypes.widest_numeric_type(suitable_type, self.type) else: # C literal or Python literal - split at 32bit boundary if -2**31 <= self.constant_result < 2**31: if self.type and self.type.is_int: suitable_type = self.type else: suitable_type = PyrexTypes.c_long_type else: suitable_type = PyrexTypes.py_object_type return suitable_type def coerce_to(self, dst_type, env): if self.type is dst_type: return self elif dst_type.is_float: if self.has_constant_result(): return FloatNode(self.pos, value='%d.0' % int(self.constant_result), type=dst_type, constant_result=float(self.constant_result)) else: return FloatNode(self.pos, value=self.value, type=dst_type, constant_result=not_a_constant) if dst_type.is_numeric and not dst_type.is_complex: node = IntNode(self.pos, value=self.value, constant_result=self.constant_result, type = dst_type, is_c_literal = True, unsigned=self.unsigned, longness=self.longness) return node elif dst_type.is_pyobject: node = IntNode(self.pos, value=self.value, constant_result=self.constant_result, type = PyrexTypes.py_object_type, is_c_literal = False, unsigned=self.unsigned, longness=self.longness) else: # FIXME: not setting the type here to keep it working with # complex numbers. Should they be special cased? node = IntNode(self.pos, value=self.value, constant_result=self.constant_result, unsigned=self.unsigned, longness=self.longness) # We still need to perform normal coerce_to processing on the # result, because we might be coercing to an extension type, # in which case a type test node will be needed. return ConstNode.coerce_to(node, dst_type, env) def coerce_to_boolean(self, env): return IntNode( self.pos, value=self.value, constant_result=self.constant_result, type=PyrexTypes.c_bint_type, unsigned=self.unsigned, longness=self.longness) def generate_evaluation_code(self, code): if self.type.is_pyobject: # pre-allocate a Python version of the number plain_integer_string = str(Utils.str_to_number(self.value)) self.result_code = code.get_py_int(plain_integer_string, self.longness) else: self.result_code = self.get_constant_c_result_code() def get_constant_c_result_code(self): return self.value_as_c_integer_string() + self.unsigned + self.longness def value_as_c_integer_string(self): value = self.value if len(value) > 2: # convert C-incompatible Py3 oct/bin notations if value[1] in 'oO': value = value[0] + value[2:] # '0o123' => '0123' elif value[1] in 'bB': value = int(value[2:], 2) return str(value) def calculate_result_code(self): return self.result_code def calculate_constant_result(self): self.constant_result = Utils.str_to_number(self.value) def compile_time_value(self, denv): return Utils.str_to_number(self.value) class FloatNode(ConstNode): type = PyrexTypes.c_double_type def calculate_constant_result(self): self.constant_result = float(self.value) def compile_time_value(self, denv): return float(self.value) def coerce_to(self, dst_type, env): if dst_type.is_pyobject and self.type.is_float: return FloatNode( self.pos, value=self.value, constant_result=self.constant_result, type=Builtin.float_type) if dst_type.is_float and self.type.is_pyobject: return FloatNode( self.pos, value=self.value, constant_result=self.constant_result, type=dst_type) return ConstNode.coerce_to(self, dst_type, env) def calculate_result_code(self): return self.result_code def get_constant_c_result_code(self): strval = self.value assert isinstance(strval, (str, unicode)) cmpval = repr(float(strval)) if cmpval == 'nan': return "(Py_HUGE_VAL * 0)" elif cmpval == 'inf': return "Py_HUGE_VAL" elif cmpval == '-inf': return "(-Py_HUGE_VAL)" else: return strval def generate_evaluation_code(self, code): c_value = self.get_constant_c_result_code() if self.type.is_pyobject: self.result_code = code.get_py_float(self.value, c_value) else: self.result_code = c_value class BytesNode(ConstNode): # A char* or bytes literal # # value BytesLiteral is_string_literal = True # start off as Python 'bytes' to support len() in O(1) type = bytes_type def calculate_constant_result(self): self.constant_result = self.value def as_sliced_node(self, start, stop, step=None): value = StringEncoding.BytesLiteral(self.value[start:stop:step]) value.encoding = self.value.encoding return BytesNode( self.pos, value=value, constant_result=value) def compile_time_value(self, denv): return self.value def analyse_as_type(self, env): type = PyrexTypes.parse_basic_type(self.value) if type is not None: return type from TreeFragment import TreeFragment pos = (self.pos[0], self.pos[1], self.pos[2]-7) declaration = TreeFragment(u"sizeof(%s)" % self.value, name=pos[0].filename, initial_pos=pos) sizeof_node = declaration.root.stats[0].expr sizeof_node = sizeof_node.analyse_types(env) if isinstance(sizeof_node, SizeofTypeNode): return sizeof_node.arg_type def can_coerce_to_char_literal(self): return len(self.value) == 1 def coerce_to_boolean(self, env): # This is special because testing a C char* for truth directly # would yield the wrong result. bool_value = bool(self.value) return BoolNode(self.pos, value=bool_value, constant_result=bool_value) def coerce_to(self, dst_type, env): if self.type == dst_type: return self if dst_type.is_int: if not self.can_coerce_to_char_literal(): error(self.pos, "Only single-character string literals can be coerced into ints.") return self if dst_type.is_unicode_char: error(self.pos, "Bytes literals cannot coerce to Py_UNICODE/Py_UCS4, use a unicode literal instead.") return self return CharNode(self.pos, value=self.value, constant_result=ord(self.value)) node = BytesNode(self.pos, value=self.value, constant_result=self.constant_result) if dst_type.is_pyobject: if dst_type in (py_object_type, Builtin.bytes_type): node.type = Builtin.bytes_type else: self.check_for_coercion_error(dst_type, env, fail=True) return node elif dst_type == PyrexTypes.c_char_ptr_type: node.type = dst_type return node elif dst_type == PyrexTypes.c_uchar_ptr_type: node.type = PyrexTypes.c_char_ptr_type return CastNode(node, PyrexTypes.c_uchar_ptr_type) elif dst_type.assignable_from(PyrexTypes.c_char_ptr_type): node.type = dst_type return node # We still need to perform normal coerce_to processing on the # result, because we might be coercing to an extension type, # in which case a type test node will be needed. return ConstNode.coerce_to(node, dst_type, env) def generate_evaluation_code(self, code): if self.type.is_pyobject: self.result_code = code.get_py_string_const(self.value) else: self.result_code = code.get_string_const(self.value) def get_constant_c_result_code(self): return None # FIXME def calculate_result_code(self): return self.result_code class UnicodeNode(ConstNode): # A Py_UNICODE* or unicode literal # # value EncodedString # bytes_value BytesLiteral the literal parsed as bytes string # ('-3' unicode literals only) is_string_literal = True bytes_value = None type = unicode_type def calculate_constant_result(self): self.constant_result = self.value def as_sliced_node(self, start, stop, step=None): if StringEncoding.string_contains_surrogates(self.value[:stop]): # this is unsafe as it may give different results # in different runtimes return None value = StringEncoding.EncodedString(self.value[start:stop:step]) value.encoding = self.value.encoding if self.bytes_value is not None: bytes_value = StringEncoding.BytesLiteral( self.bytes_value[start:stop:step]) bytes_value.encoding = self.bytes_value.encoding else: bytes_value = None return UnicodeNode( self.pos, value=value, bytes_value=bytes_value, constant_result=value) def coerce_to(self, dst_type, env): if dst_type is self.type: pass elif dst_type.is_unicode_char: if not self.can_coerce_to_char_literal(): error(self.pos, "Only single-character Unicode string literals or " "surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.") return self int_value = ord(self.value) return IntNode(self.pos, type=dst_type, value=str(int_value), constant_result=int_value) elif not dst_type.is_pyobject: if dst_type.is_string and self.bytes_value is not None: # special case: '-3' enforced unicode literal used in a # C char* context return BytesNode(self.pos, value=self.bytes_value ).coerce_to(dst_type, env) if dst_type.is_pyunicode_ptr: node = UnicodeNode(self.pos, value=self.value) node.type = dst_type return node error(self.pos, "Unicode literals do not support coercion to C types other " "than Py_UNICODE/Py_UCS4 (for characters) or Py_UNICODE* " "(for strings).") elif dst_type not in (py_object_type, Builtin.basestring_type): self.check_for_coercion_error(dst_type, env, fail=True) return self def can_coerce_to_char_literal(self): return len(self.value) == 1 ## or (len(self.value) == 2 ## and (0xD800 <= self.value[0] <= 0xDBFF) ## and (0xDC00 <= self.value[1] <= 0xDFFF)) def coerce_to_boolean(self, env): bool_value = bool(self.value) return BoolNode(self.pos, value=bool_value, constant_result=bool_value) def contains_surrogates(self): return StringEncoding.string_contains_surrogates(self.value) def generate_evaluation_code(self, code): if self.type.is_pyobject: if self.contains_surrogates(): # surrogates are not really portable and cannot be # decoded by the UTF-8 codec in Py3.3 self.result_code = code.get_py_const(py_object_type, 'ustring') data_cname = code.get_pyunicode_ptr_const(self.value) code = code.get_cached_constants_writer() code.mark_pos(self.pos) code.putln( "%s = PyUnicode_FromUnicode(%s, (sizeof(%s) / sizeof(Py_UNICODE))-1); %s" % ( self.result_code, data_cname, data_cname, code.error_goto_if_null(self.result_code, self.pos))) code.putln("#if CYTHON_PEP393_ENABLED") code.put_error_if_neg( self.pos, "PyUnicode_READY(%s)" % self.result_code) code.putln("#endif") else: self.result_code = code.get_py_string_const(self.value) else: self.result_code = code.get_pyunicode_ptr_const(self.value) def calculate_result_code(self): return self.result_code def compile_time_value(self, env): return self.value class StringNode(PyConstNode): # A Python str object, i.e. a byte string in Python 2.x and a # unicode string in Python 3.x # # value BytesLiteral (or EncodedString with ASCII content) # unicode_value EncodedString or None # is_identifier boolean type = str_type is_string_literal = True is_identifier = None unicode_value = None def calculate_constant_result(self): if self.unicode_value is not None: # only the Unicode value is portable across Py2/3 self.constant_result = self.unicode_value def as_sliced_node(self, start, stop, step=None): value = type(self.value)(self.value[start:stop:step]) value.encoding = self.value.encoding if self.unicode_value is not None: if StringEncoding.string_contains_surrogates(self.unicode_value[:stop]): # this is unsafe as it may give different results in different runtimes return None unicode_value = StringEncoding.EncodedString( self.unicode_value[start:stop:step]) else: unicode_value = None return StringNode( self.pos, value=value, unicode_value=unicode_value, constant_result=value, is_identifier=self.is_identifier) def coerce_to(self, dst_type, env): if dst_type is not py_object_type and not str_type.subtype_of(dst_type): # if dst_type is Builtin.bytes_type: # # special case: bytes = 'str literal' # return BytesNode(self.pos, value=self.value) if not dst_type.is_pyobject: return BytesNode(self.pos, value=self.value).coerce_to(dst_type, env) if dst_type is not Builtin.basestring_type: self.check_for_coercion_error(dst_type, env, fail=True) return self def can_coerce_to_char_literal(self): return not self.is_identifier and len(self.value) == 1 def generate_evaluation_code(self, code): self.result_code = code.get_py_string_const( self.value, identifier=self.is_identifier, is_str=True, unicode_value=self.unicode_value) def get_constant_c_result_code(self): return None def calculate_result_code(self): return self.result_code def compile_time_value(self, env): return self.value class IdentifierStringNode(StringNode): # A special str value that represents an identifier (bytes in Py2, # unicode in Py3). is_identifier = True class ImagNode(AtomicExprNode): # Imaginary number literal # # value float imaginary part type = PyrexTypes.c_double_complex_type def calculate_constant_result(self): self.constant_result = complex(0.0, self.value) def compile_time_value(self, denv): return complex(0.0, self.value) def analyse_types(self, env): self.type.create_declaration_utility_code(env) return self def may_be_none(self): return False def coerce_to(self, dst_type, env): if self.type is dst_type: return self node = ImagNode(self.pos, value=self.value) if dst_type.is_pyobject: node.is_temp = 1 node.type = PyrexTypes.py_object_type # We still need to perform normal coerce_to processing on the # result, because we might be coercing to an extension type, # in which case a type test node will be needed. return AtomicExprNode.coerce_to(node, dst_type, env) gil_message = "Constructing complex number" def calculate_result_code(self): if self.type.is_pyobject: return self.result() else: return "%s(0, %r)" % (self.type.from_parts, float(self.value)) def generate_result_code(self, code): if self.type.is_pyobject: code.putln( "%s = PyComplex_FromDoubles(0.0, %r); %s" % ( self.result(), float(self.value), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class NewExprNode(AtomicExprNode): # C++ new statement # # cppclass node c++ class to create type = None def infer_type(self, env): type = self.cppclass.analyse_as_type(env) if type is None or not type.is_cpp_class: error(self.pos, "new operator can only be applied to a C++ class") self.type = error_type return self.cpp_check(env) constructor = type.scope.lookup(u'') if constructor is None: func_type = PyrexTypes.CFuncType(type, [], exception_check='+') type.scope.declare_cfunction(u'', func_type, self.pos) constructor = type.scope.lookup(u'') self.class_type = type self.entry = constructor self.type = constructor.type return self.type def analyse_types(self, env): if self.type is None: self.infer_type(env) return self def may_be_none(self): return False def generate_result_code(self, code): pass def calculate_result_code(self): return "new " + self.class_type.declaration_code("") class NameNode(AtomicExprNode): # Reference to a local or global variable name. # # name string Python name of the variable # entry Entry Symbol table entry # type_entry Entry For extension type names, the original type entry # cf_is_null boolean Is uninitialized before this node # cf_maybe_null boolean Maybe uninitialized before this node # allow_null boolean Don't raise UnboundLocalError # nogil boolean Whether it is used in a nogil context is_name = True is_cython_module = False cython_attribute = None lhs_of_first_assignment = False # TODO: remove me is_used_as_rvalue = 0 entry = None type_entry = None cf_maybe_null = True cf_is_null = False allow_null = False nogil = False inferred_type = None def as_cython_attribute(self): return self.cython_attribute def type_dependencies(self, env): if self.entry is None: self.entry = env.lookup(self.name) if self.entry is not None and self.entry.type.is_unspecified: return (self,) else: return () def infer_type(self, env): if self.entry is None: self.entry = env.lookup(self.name) if self.entry is None or self.entry.type is unspecified_type: if self.inferred_type is not None: return self.inferred_type return py_object_type elif (self.entry.type.is_extension_type or self.entry.type.is_builtin_type) and \ self.name == self.entry.type.name: # Unfortunately the type attribute of type objects # is used for the pointer to the type they represent. return type_type elif self.entry.type.is_cfunction: if self.entry.scope.is_builtin_scope: # special case: optimised builtin functions must be treated as Python objects return py_object_type else: # special case: referring to a C function must return its pointer return PyrexTypes.CPtrType(self.entry.type) else: # If entry is inferred as pyobject it's safe to use local # NameNode's inferred_type. if self.entry.type.is_pyobject and self.inferred_type: # Overflow may happen if integer if not (self.inferred_type.is_int and self.entry.might_overflow): return self.inferred_type return self.entry.type def compile_time_value(self, denv): try: return denv.lookup(self.name) except KeyError: error(self.pos, "Compile-time name '%s' not defined" % self.name) def get_constant_c_result_code(self): if not self.entry or self.entry.type.is_pyobject: return None return self.entry.cname def coerce_to(self, dst_type, env): # If coercing to a generic pyobject and this is a builtin # C function with a Python equivalent, manufacture a NameNode # referring to the Python builtin. #print "NameNode.coerce_to:", self.name, dst_type ### if dst_type is py_object_type: entry = self.entry if entry and entry.is_cfunction: var_entry = entry.as_variable if var_entry: if var_entry.is_builtin and var_entry.is_const: var_entry = env.declare_builtin(var_entry.name, self.pos) node = NameNode(self.pos, name = self.name) node.entry = var_entry node.analyse_rvalue_entry(env) return node return super(NameNode, self).coerce_to(dst_type, env) def analyse_as_module(self, env): # Try to interpret this as a reference to a cimported module. # Returns the module scope, or None. entry = self.entry if not entry: entry = env.lookup(self.name) if entry and entry.as_module: return entry.as_module return None def analyse_as_type(self, env): if self.cython_attribute: type = PyrexTypes.parse_basic_type(self.cython_attribute) else: type = PyrexTypes.parse_basic_type(self.name) if type: return type entry = self.entry if not entry: entry = env.lookup(self.name) if entry and entry.is_type: return entry.type else: return None def analyse_as_extension_type(self, env): # Try to interpret this as a reference to an extension type. # Returns the extension type, or None. entry = self.entry if not entry: entry = env.lookup(self.name) if entry and entry.is_type: if entry.type.is_extension_type or entry.type.is_builtin_type: return entry.type return None def analyse_target_declaration(self, env): if not self.entry: self.entry = env.lookup_here(self.name) if not self.entry: if env.directives['warn.undeclared']: warning(self.pos, "implicit declaration of '%s'" % self.name, 1) if env.directives['infer_types'] != False: type = unspecified_type else: type = py_object_type self.entry = env.declare_var(self.name, type, self.pos) if self.entry.is_declared_generic: self.result_ctype = py_object_type def analyse_types(self, env): self.initialized_check = env.directives['initializedcheck'] if self.entry is None: self.entry = env.lookup(self.name) if not self.entry: self.entry = env.declare_builtin(self.name, self.pos) if not self.entry: self.type = PyrexTypes.error_type return self entry = self.entry if entry: entry.used = 1 if entry.type.is_buffer: import Buffer Buffer.used_buffer_aux_vars(entry) self.analyse_rvalue_entry(env) return self def analyse_target_types(self, env): self.analyse_entry(env, is_target=True) if (not self.is_lvalue() and self.entry.is_cfunction and self.entry.fused_cfunction and self.entry.as_variable): # We need this for the fused 'def' TreeFragment self.entry = self.entry.as_variable self.type = self.entry.type if self.type.is_const: error(self.pos, "Assignment to const '%s'" % self.name) if self.type.is_reference: error(self.pos, "Assignment to reference '%s'" % self.name) if not self.is_lvalue(): error(self.pos, "Assignment to non-lvalue '%s'" % self.name) self.type = PyrexTypes.error_type self.entry.used = 1 if self.entry.type.is_buffer: import Buffer Buffer.used_buffer_aux_vars(self.entry) return self def analyse_rvalue_entry(self, env): #print "NameNode.analyse_rvalue_entry:", self.name ### #print "Entry:", self.entry.__dict__ ### self.analyse_entry(env) entry = self.entry if entry.is_declared_generic: self.result_ctype = py_object_type if entry.is_pyglobal or entry.is_builtin: if entry.is_builtin and entry.is_const: self.is_temp = 0 else: self.is_temp = 1 self.is_used_as_rvalue = 1 elif entry.type.is_memoryviewslice: self.is_temp = False self.is_used_as_rvalue = True self.use_managed_ref = True return self def nogil_check(self, env): self.nogil = True if self.is_used_as_rvalue: entry = self.entry if entry.is_builtin: if not entry.is_const: # cached builtins are ok self.gil_error() elif entry.is_pyglobal: self.gil_error() elif self.entry.type.is_memoryviewslice: if self.cf_is_null or self.cf_maybe_null: import MemoryView MemoryView.err_if_nogil_initialized_check(self.pos, env) gil_message = "Accessing Python global or builtin" def analyse_entry(self, env, is_target=False): #print "NameNode.analyse_entry:", self.name ### self.check_identifier_kind() entry = self.entry type = entry.type if (not is_target and type.is_pyobject and self.inferred_type and self.inferred_type.is_builtin_type): # assume that type inference is smarter than the static entry type = self.inferred_type self.type = type def check_identifier_kind(self): # Check that this is an appropriate kind of name for use in an # expression. Also finds the variable entry associated with # an extension type. entry = self.entry if entry.is_type and entry.type.is_extension_type: self.type_entry = entry if not (entry.is_const or entry.is_variable or entry.is_builtin or entry.is_cfunction or entry.is_cpp_class): if self.entry.as_variable: self.entry = self.entry.as_variable else: error(self.pos, "'%s' is not a constant, variable or function identifier" % self.name) def is_simple(self): # If it's not a C variable, it'll be in a temp. return 1 def may_be_none(self): if self.cf_state and self.type and (self.type.is_pyobject or self.type.is_memoryviewslice): # gard against infinite recursion on self-dependencies if getattr(self, '_none_checking', False): # self-dependency - either this node receives a None # value from *another* node, or it can not reference # None at this point => safe to assume "not None" return False self._none_checking = True # evaluate control flow state to see if there were any # potential None values assigned to the node so far may_be_none = False for assignment in self.cf_state: if assignment.rhs.may_be_none(): may_be_none = True break del self._none_checking return may_be_none return super(NameNode, self).may_be_none() def nonlocally_immutable(self): if ExprNode.nonlocally_immutable(self): return True entry = self.entry if not entry or entry.in_closure: return False return entry.is_local or entry.is_arg or entry.is_builtin or entry.is_readonly def calculate_target_results(self, env): pass def check_const(self): entry = self.entry if entry is not None and not (entry.is_const or entry.is_cfunction or entry.is_builtin): self.not_const() return False return True def check_const_addr(self): entry = self.entry if not (entry.is_cglobal or entry.is_cfunction or entry.is_builtin): self.addr_not_const() return False return True def is_lvalue(self): return self.entry.is_variable and \ not self.entry.type.is_array and \ not self.entry.is_readonly def is_addressable(self): return self.entry.is_variable and not self.type.is_memoryviewslice def is_ephemeral(self): # Name nodes are never ephemeral, even if the # result is in a temporary. return 0 def calculate_result_code(self): entry = self.entry if not entry: return "" # There was an error earlier return entry.cname def generate_result_code(self, code): assert hasattr(self, 'entry') entry = self.entry if entry is None: return # There was an error earlier if entry.is_builtin and entry.is_const: return # Lookup already cached elif entry.is_pyclass_attr: assert entry.type.is_pyobject, "Python global or builtin not a Python object" interned_cname = code.intern_identifier(self.entry.name) if entry.is_builtin: namespace = Naming.builtins_cname else: # entry.is_pyglobal namespace = entry.scope.namespace_cname if not self.cf_is_null: code.putln( '%s = PyObject_GetItem(%s, %s);' % ( self.result(), namespace, interned_cname)) code.putln('if (unlikely(!%s)) {' % self.result()) code.putln('PyErr_Clear();') code.globalstate.use_utility_code( UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c")) code.putln( '%s = __Pyx_GetModuleGlobalName(%s);' % ( self.result(), interned_cname)) if not self.cf_is_null: code.putln("}") code.putln(code.error_goto_if_null(self.result(), self.pos)) code.put_gotref(self.py_result()) elif entry.is_builtin: assert entry.type.is_pyobject, "Python global or builtin not a Python object" interned_cname = code.intern_identifier(self.entry.name) code.globalstate.use_utility_code( UtilityCode.load_cached("GetBuiltinName", "ObjectHandling.c")) code.putln( '%s = __Pyx_GetBuiltinName(%s); %s' % ( self.result(), interned_cname, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) elif entry.is_pyglobal: assert entry.type.is_pyobject, "Python global or builtin not a Python object" interned_cname = code.intern_identifier(self.entry.name) if entry.scope.is_module_scope: code.globalstate.use_utility_code( UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c")) code.putln( '%s = __Pyx_GetModuleGlobalName(%s); %s' % ( self.result(), interned_cname, code.error_goto_if_null(self.result(), self.pos))) else: # FIXME: is_pyglobal is also used for class namespace code.globalstate.use_utility_code( UtilityCode.load_cached("GetNameInClass", "ObjectHandling.c")) code.putln( '%s = __Pyx_GetNameInClass(%s, %s); %s' % ( self.result(), entry.scope.namespace_cname, interned_cname, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) elif entry.is_local or entry.in_closure or entry.from_closure or entry.type.is_memoryviewslice: # Raise UnboundLocalError for objects and memoryviewslices raise_unbound = ( (self.cf_maybe_null or self.cf_is_null) and not self.allow_null) null_code = entry.type.check_for_null_code(entry.cname) memslice_check = entry.type.is_memoryviewslice and self.initialized_check if null_code and raise_unbound and (entry.type.is_pyobject or memslice_check): code.put_error_if_unbound(self.pos, entry, self.in_nogil_context) def generate_assignment_code(self, rhs, code): #print "NameNode.generate_assignment_code:", self.name ### entry = self.entry if entry is None: return # There was an error earlier if (self.entry.type.is_ptr and isinstance(rhs, ListNode) and not self.lhs_of_first_assignment and not rhs.in_module_scope): error(self.pos, "Literal list must be assigned to pointer at time of declaration") # is_pyglobal seems to be True for module level-globals only. # We use this to access class->tp_dict if necessary. if entry.is_pyglobal: assert entry.type.is_pyobject, "Python global or builtin not a Python object" interned_cname = code.intern_identifier(self.entry.name) namespace = self.entry.scope.namespace_cname if entry.is_member: # if the entry is a member we have to cheat: SetAttr does not work # on types, so we create a descriptor which is then added to tp_dict setter = 'PyDict_SetItem' namespace = '%s->tp_dict' % namespace elif entry.scope.is_module_scope: setter = 'PyDict_SetItem' namespace = Naming.moddict_cname elif entry.is_pyclass_attr: setter = 'PyObject_SetItem' else: assert False, repr(entry) code.put_error_if_neg( self.pos, '%s(%s, %s, %s)' % ( setter, namespace, interned_cname, rhs.py_result())) if debug_disposal_code: print("NameNode.generate_assignment_code:") print("...generating disposal code for %s" % rhs) rhs.generate_disposal_code(code) rhs.free_temps(code) if entry.is_member: # in Py2.6+, we need to invalidate the method cache code.putln("PyType_Modified(%s);" % entry.scope.parent_type.typeptr_cname) else: if self.type.is_memoryviewslice: self.generate_acquire_memoryviewslice(rhs, code) elif self.type.is_buffer: # Generate code for doing the buffer release/acquisition. # This might raise an exception in which case the assignment (done # below) will not happen. # # The reason this is not in a typetest-like node is because the # variables that the acquired buffer info is stored to is allocated # per entry and coupled with it. self.generate_acquire_buffer(rhs, code) assigned = False if self.type.is_pyobject: #print "NameNode.generate_assignment_code: to", self.name ### #print "...from", rhs ### #print "...LHS type", self.type, "ctype", self.ctype() ### #print "...RHS type", rhs.type, "ctype", rhs.ctype() ### if self.use_managed_ref: rhs.make_owned_reference(code) is_external_ref = entry.is_cglobal or self.entry.in_closure or self.entry.from_closure if is_external_ref: if not self.cf_is_null: if self.cf_maybe_null: code.put_xgotref(self.py_result()) else: code.put_gotref(self.py_result()) assigned = True if entry.is_cglobal: code.put_decref_set( self.result(), rhs.result_as(self.ctype())) else: if not self.cf_is_null: if self.cf_maybe_null: code.put_xdecref_set( self.result(), rhs.result_as(self.ctype())) else: code.put_decref_set( self.result(), rhs.result_as(self.ctype())) else: assigned = False if is_external_ref: code.put_giveref(rhs.py_result()) if not self.type.is_memoryviewslice: if not assigned: code.putln('%s = %s;' % ( self.result(), rhs.result_as(self.ctype()))) if debug_disposal_code: print("NameNode.generate_assignment_code:") print("...generating post-assignment code for %s" % rhs) rhs.generate_post_assignment_code(code) elif rhs.result_in_temp(): rhs.generate_post_assignment_code(code) rhs.free_temps(code) def generate_acquire_memoryviewslice(self, rhs, code): """ Slices, coercions from objects, return values etc are new references. We have a borrowed reference in case of dst = src """ import MemoryView MemoryView.put_acquire_memoryviewslice( lhs_cname=self.result(), lhs_type=self.type, lhs_pos=self.pos, rhs=rhs, code=code, have_gil=not self.in_nogil_context, first_assignment=self.cf_is_null) def generate_acquire_buffer(self, rhs, code): # rhstmp is only used in case the rhs is a complicated expression leading to # the object, to avoid repeating the same C expression for every reference # to the rhs. It does NOT hold a reference. pretty_rhs = isinstance(rhs, NameNode) or rhs.is_temp if pretty_rhs: rhstmp = rhs.result_as(self.ctype()) else: rhstmp = code.funcstate.allocate_temp(self.entry.type, manage_ref=False) code.putln('%s = %s;' % (rhstmp, rhs.result_as(self.ctype()))) import Buffer Buffer.put_assign_to_buffer(self.result(), rhstmp, self.entry, is_initialized=not self.lhs_of_first_assignment, pos=self.pos, code=code) if not pretty_rhs: code.putln("%s = 0;" % rhstmp) code.funcstate.release_temp(rhstmp) def generate_deletion_code(self, code, ignore_nonexisting=False): if self.entry is None: return # There was an error earlier elif self.entry.is_pyclass_attr: namespace = self.entry.scope.namespace_cname interned_cname = code.intern_identifier(self.entry.name) if ignore_nonexisting: key_error_code = 'PyErr_Clear(); else' else: # minor hack: fake a NameError on KeyError key_error_code = ( '{ PyErr_Clear(); PyErr_Format(PyExc_NameError, "name \'%%s\' is not defined", "%s"); }' % self.entry.name) code.putln( 'if (unlikely(PyObject_DelItem(%s, %s) < 0)) {' ' if (likely(PyErr_ExceptionMatches(PyExc_KeyError))) %s' ' %s ' '}' % (namespace, interned_cname, key_error_code, code.error_goto(self.pos))) elif self.entry.is_pyglobal: code.globalstate.use_utility_code( UtilityCode.load_cached("PyObjectSetAttrStr", "ObjectHandling.c")) interned_cname = code.intern_identifier(self.entry.name) del_code = '__Pyx_PyObject_DelAttrStr(%s, %s)' % ( Naming.module_cname, interned_cname) if ignore_nonexisting: code.putln('if (unlikely(%s < 0)) { if (likely(PyErr_ExceptionMatches(PyExc_AttributeError))) PyErr_Clear(); else %s }' % ( del_code, code.error_goto(self.pos))) else: code.put_error_if_neg(self.pos, del_code) elif self.entry.type.is_pyobject or self.entry.type.is_memoryviewslice: if not self.cf_is_null: if self.cf_maybe_null and not ignore_nonexisting: code.put_error_if_unbound(self.pos, self.entry) if self.entry.type.is_pyobject: if self.entry.in_closure: # generator if ignore_nonexisting and self.cf_maybe_null: code.put_xgotref(self.result()) else: code.put_gotref(self.result()) if ignore_nonexisting and self.cf_maybe_null: code.put_xdecref(self.result(), self.ctype()) else: code.put_decref(self.result(), self.ctype()) code.putln('%s = NULL;' % self.result()) else: code.put_xdecref_memoryviewslice(self.entry.cname, have_gil=not self.nogil) else: error(self.pos, "Deletion of C names not supported") def annotate(self, code): if hasattr(self, 'is_called') and self.is_called: pos = (self.pos[0], self.pos[1], self.pos[2] - len(self.name) - 1) if self.type.is_pyobject: style, text = 'py_call', 'python function (%s)' else: style, text = 'c_call', 'c function (%s)' code.annotate(pos, AnnotationItem(style, text % self.type, size=len(self.name))) class BackquoteNode(ExprNode): # `expr` # # arg ExprNode type = py_object_type subexprs = ['arg'] def analyse_types(self, env): self.arg = self.arg.analyse_types(env) self.arg = self.arg.coerce_to_pyobject(env) self.is_temp = 1 return self gil_message = "Backquote expression" def calculate_constant_result(self): self.constant_result = repr(self.arg.constant_result) def generate_result_code(self, code): code.putln( "%s = PyObject_Repr(%s); %s" % ( self.result(), self.arg.py_result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class ImportNode(ExprNode): # Used as part of import statement implementation. # Implements result = # __import__(module_name, globals(), None, name_list, level) # # module_name StringNode dotted name of module. Empty module # name means importing the parent package according # to level # name_list ListNode or None list of names to be imported # level int relative import level: # -1: attempt both relative import and absolute import; # 0: absolute import; # >0: the number of parent directories to search # relative to the current module. # None: decide the level according to language level and # directives type = py_object_type subexprs = ['module_name', 'name_list'] def analyse_types(self, env): if self.level is None: if (env.directives['py2_import'] or Future.absolute_import not in env.global_scope().context.future_directives): self.level = -1 else: self.level = 0 module_name = self.module_name.analyse_types(env) self.module_name = module_name.coerce_to_pyobject(env) if self.name_list: name_list = self.name_list.analyse_types(env) self.name_list = name_list.coerce_to_pyobject(env) self.is_temp = 1 env.use_utility_code(UtilityCode.load_cached("Import", "ImportExport.c")) return self gil_message = "Python import" def generate_result_code(self, code): if self.name_list: name_list_code = self.name_list.py_result() else: name_list_code = "0" code.putln( "%s = __Pyx_Import(%s, %s, %d); %s" % ( self.result(), self.module_name.py_result(), name_list_code, self.level, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class IteratorNode(ExprNode): # Used as part of for statement implementation. # # Implements result = iter(sequence) # # sequence ExprNode type = py_object_type iter_func_ptr = None counter_cname = None cpp_iterator_cname = None reversed = False # currently only used for list/tuple types (see Optimize.py) subexprs = ['sequence'] def analyse_types(self, env): self.sequence = self.sequence.analyse_types(env) if (self.sequence.type.is_array or self.sequence.type.is_ptr) and \ not self.sequence.type.is_string: # C array iteration will be transformed later on self.type = self.sequence.type elif self.sequence.type.is_cpp_class: self.analyse_cpp_types(env) else: self.sequence = self.sequence.coerce_to_pyobject(env) if self.sequence.type is list_type or \ self.sequence.type is tuple_type: self.sequence = self.sequence.as_none_safe_node("'NoneType' object is not iterable") self.is_temp = 1 return self gil_message = "Iterating over Python object" _func_iternext_type = PyrexTypes.CPtrType(PyrexTypes.CFuncType( PyrexTypes.py_object_type, [ PyrexTypes.CFuncTypeArg("it", PyrexTypes.py_object_type, None), ])) def type_dependencies(self, env): return self.sequence.type_dependencies(env) def infer_type(self, env): sequence_type = self.sequence.infer_type(env) if sequence_type.is_array or sequence_type.is_ptr: return sequence_type elif sequence_type.is_cpp_class: begin = sequence_type.scope.lookup("begin") if begin is not None: return begin.type.return_type elif sequence_type.is_pyobject: return sequence_type return py_object_type def analyse_cpp_types(self, env): sequence_type = self.sequence.type if sequence_type.is_ptr: sequence_type = sequence_type.base_type begin = sequence_type.scope.lookup("begin") end = sequence_type.scope.lookup("end") if (begin is None or not begin.type.is_cfunction or begin.type.args): error(self.pos, "missing begin() on %s" % self.sequence.type) self.type = error_type return if (end is None or not end.type.is_cfunction or end.type.args): error(self.pos, "missing end() on %s" % self.sequence.type) self.type = error_type return iter_type = begin.type.return_type if iter_type.is_cpp_class: if env.lookup_operator_for_types( self.pos, "!=", [iter_type, end.type.return_type]) is None: error(self.pos, "missing operator!= on result of begin() on %s" % self.sequence.type) self.type = error_type return if env.lookup_operator_for_types(self.pos, '++', [iter_type]) is None: error(self.pos, "missing operator++ on result of begin() on %s" % self.sequence.type) self.type = error_type return if env.lookup_operator_for_types(self.pos, '*', [iter_type]) is None: error(self.pos, "missing operator* on result of begin() on %s" % self.sequence.type) self.type = error_type return self.type = iter_type elif iter_type.is_ptr: if not (iter_type == end.type.return_type): error(self.pos, "incompatible types for begin() and end()") self.type = iter_type else: error(self.pos, "result type of begin() on %s must be a C++ class or pointer" % self.sequence.type) self.type = error_type return def generate_result_code(self, code): sequence_type = self.sequence.type if sequence_type.is_cpp_class: if self.sequence.is_name: # safe: C++ won't allow you to reassign to class references begin_func = "%s.begin" % self.sequence.result() else: sequence_type = PyrexTypes.c_ptr_type(sequence_type) self.cpp_iterator_cname = code.funcstate.allocate_temp(sequence_type, manage_ref=False) code.putln("%s = &%s;" % (self.cpp_iterator_cname, self.sequence.result())) begin_func = "%s->begin" % self.cpp_iterator_cname # TODO: Limit scope. code.putln("%s = %s();" % (self.result(), begin_func)) return if sequence_type.is_array or sequence_type.is_ptr: raise InternalError("for in carray slice not transformed") is_builtin_sequence = sequence_type is list_type or \ sequence_type is tuple_type if not is_builtin_sequence: # reversed() not currently optimised (see Optimize.py) assert not self.reversed, "internal error: reversed() only implemented for list/tuple objects" self.may_be_a_sequence = not sequence_type.is_builtin_type if self.may_be_a_sequence: code.putln( "if (PyList_CheckExact(%s) || PyTuple_CheckExact(%s)) {" % ( self.sequence.py_result(), self.sequence.py_result())) if is_builtin_sequence or self.may_be_a_sequence: self.counter_cname = code.funcstate.allocate_temp( PyrexTypes.c_py_ssize_t_type, manage_ref=False) if self.reversed: if sequence_type is list_type: init_value = 'PyList_GET_SIZE(%s) - 1' % self.result() else: init_value = 'PyTuple_GET_SIZE(%s) - 1' % self.result() else: init_value = '0' code.putln( "%s = %s; __Pyx_INCREF(%s); %s = %s;" % ( self.result(), self.sequence.py_result(), self.result(), self.counter_cname, init_value )) if not is_builtin_sequence: self.iter_func_ptr = code.funcstate.allocate_temp(self._func_iternext_type, manage_ref=False) if self.may_be_a_sequence: code.putln("%s = NULL;" % self.iter_func_ptr) code.putln("} else {") code.put("%s = -1; " % self.counter_cname) code.putln("%s = PyObject_GetIter(%s); %s" % ( self.result(), self.sequence.py_result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) code.putln("%s = Py_TYPE(%s)->tp_iternext;" % (self.iter_func_ptr, self.py_result())) if self.may_be_a_sequence: code.putln("}") def generate_next_sequence_item(self, test_name, result_name, code): assert self.counter_cname, "internal error: counter_cname temp not prepared" final_size = 'Py%s_GET_SIZE(%s)' % (test_name, self.py_result()) if self.sequence.is_sequence_constructor: item_count = len(self.sequence.args) if self.sequence.mult_factor is None: final_size = item_count elif isinstance(self.sequence.mult_factor.constant_result, (int, long)): final_size = item_count * self.sequence.mult_factor.constant_result code.putln("if (%s >= %s) break;" % (self.counter_cname, final_size)) if self.reversed: inc_dec = '--' else: inc_dec = '++' code.putln("#if CYTHON_COMPILING_IN_CPYTHON") code.putln( "%s = Py%s_GET_ITEM(%s, %s); __Pyx_INCREF(%s); %s%s; %s" % ( result_name, test_name, self.py_result(), self.counter_cname, result_name, self.counter_cname, inc_dec, # use the error label to avoid C compiler warnings if we only use it below code.error_goto_if_neg('0', self.pos) )) code.putln("#else") code.putln( "%s = PySequence_ITEM(%s, %s); %s%s; %s" % ( result_name, self.py_result(), self.counter_cname, self.counter_cname, inc_dec, code.error_goto_if_null(result_name, self.pos))) code.putln("#endif") def generate_iter_next_result_code(self, result_name, code): sequence_type = self.sequence.type if self.reversed: code.putln("if (%s < 0) break;" % self.counter_cname) if sequence_type.is_cpp_class: if self.cpp_iterator_cname: end_func = "%s->end" % self.cpp_iterator_cname else: end_func = "%s.end" % self.sequence.result() # TODO: Cache end() call? code.putln("if (!(%s != %s())) break;" % ( self.result(), end_func)) code.putln("%s = *%s;" % ( result_name, self.result())) code.putln("++%s;" % self.result()) return elif sequence_type is list_type: self.generate_next_sequence_item('List', result_name, code) return elif sequence_type is tuple_type: self.generate_next_sequence_item('Tuple', result_name, code) return if self.may_be_a_sequence: for test_name in ('List', 'Tuple'): code.putln("if (!%s && Py%s_CheckExact(%s)) {" % ( self.iter_func_ptr, test_name, self.py_result())) self.generate_next_sequence_item(test_name, result_name, code) code.put("} else ") code.putln("{") code.putln( "%s = %s(%s);" % ( result_name, self.iter_func_ptr, self.py_result())) code.putln("if (unlikely(!%s)) {" % result_name) code.putln("PyObject* exc_type = PyErr_Occurred();") code.putln("if (exc_type) {") code.putln("if (likely(exc_type == PyExc_StopIteration ||" " PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();") code.putln("else %s" % code.error_goto(self.pos)) code.putln("}") code.putln("break;") code.putln("}") code.put_gotref(result_name) code.putln("}") def free_temps(self, code): if self.counter_cname: code.funcstate.release_temp(self.counter_cname) if self.iter_func_ptr: code.funcstate.release_temp(self.iter_func_ptr) self.iter_func_ptr = None if self.cpp_iterator_cname: code.funcstate.release_temp(self.cpp_iterator_cname) ExprNode.free_temps(self, code) class NextNode(AtomicExprNode): # Used as part of for statement implementation. # Implements result = iterator.next() # Created during analyse_types phase. # The iterator is not owned by this node. # # iterator IteratorNode def __init__(self, iterator): AtomicExprNode.__init__(self, iterator.pos) self.iterator = iterator def type_dependencies(self, env): return self.iterator.type_dependencies(env) def infer_type(self, env, iterator_type = None): if iterator_type is None: iterator_type = self.iterator.infer_type(env) if iterator_type.is_ptr or iterator_type.is_array: return iterator_type.base_type elif iterator_type.is_cpp_class: item_type = env.lookup_operator_for_types(self.pos, "*", [iterator_type]).type.return_type if item_type.is_reference: item_type = item_type.ref_base_type if item_type.is_const: item_type = item_type.const_base_type return item_type else: # Avoid duplication of complicated logic. fake_index_node = IndexNode( self.pos, base=self.iterator.sequence, index=IntNode(self.pos, value='PY_SSIZE_T_MAX', type=PyrexTypes.c_py_ssize_t_type)) return fake_index_node.infer_type(env) def analyse_types(self, env): self.type = self.infer_type(env, self.iterator.type) self.is_temp = 1 return self def generate_result_code(self, code): self.iterator.generate_iter_next_result_code(self.result(), code) class WithExitCallNode(ExprNode): # The __exit__() call of a 'with' statement. Used in both the # except and finally clauses. # with_stat WithStatNode the surrounding 'with' statement # args TupleNode or ResultStatNode the exception info tuple subexprs = ['args'] test_if_run = True def analyse_types(self, env): self.args = self.args.analyse_types(env) self.type = PyrexTypes.c_bint_type self.is_temp = True return self def generate_evaluation_code(self, code): if self.test_if_run: # call only if it was not already called (and decref-cleared) code.putln("if (%s) {" % self.with_stat.exit_var) self.args.generate_evaluation_code(code) result_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False) code.mark_pos(self.pos) code.globalstate.use_utility_code(UtilityCode.load_cached( "PyObjectCall", "ObjectHandling.c")) code.putln("%s = __Pyx_PyObject_Call(%s, %s, NULL);" % ( result_var, self.with_stat.exit_var, self.args.result())) code.put_decref_clear(self.with_stat.exit_var, type=py_object_type) self.args.generate_disposal_code(code) self.args.free_temps(code) code.putln(code.error_goto_if_null(result_var, self.pos)) code.put_gotref(result_var) if self.result_is_used: self.allocate_temp_result(code) code.putln("%s = __Pyx_PyObject_IsTrue(%s);" % (self.result(), result_var)) code.put_decref_clear(result_var, type=py_object_type) if self.result_is_used: code.put_error_if_neg(self.pos, self.result()) code.funcstate.release_temp(result_var) if self.test_if_run: code.putln("}") class ExcValueNode(AtomicExprNode): # Node created during analyse_types phase # of an ExceptClauseNode to fetch the current # exception value. type = py_object_type def __init__(self, pos): ExprNode.__init__(self, pos) def set_var(self, var): self.var = var def calculate_result_code(self): return self.var def generate_result_code(self, code): pass def analyse_types(self, env): return self class TempNode(ExprNode): # Node created during analyse_types phase # of some nodes to hold a temporary value. # # Note: One must call "allocate" and "release" on # the node during code generation to get/release the temp. # This is because the temp result is often used outside of # the regular cycle. subexprs = [] def __init__(self, pos, type, env=None): ExprNode.__init__(self, pos) self.type = type if type.is_pyobject: self.result_ctype = py_object_type self.is_temp = 1 def analyse_types(self, env): return self def analyse_target_declaration(self, env): pass def generate_result_code(self, code): pass def allocate(self, code): self.temp_cname = code.funcstate.allocate_temp(self.type, manage_ref=True) def release(self, code): code.funcstate.release_temp(self.temp_cname) self.temp_cname = None def result(self): try: return self.temp_cname except: assert False, "Remember to call allocate/release on TempNode" raise # Do not participate in normal temp alloc/dealloc: def allocate_temp_result(self, code): pass def release_temp_result(self, code): pass class PyTempNode(TempNode): # TempNode holding a Python value. def __init__(self, pos, env): TempNode.__init__(self, pos, PyrexTypes.py_object_type, env) class RawCNameExprNode(ExprNode): subexprs = [] def __init__(self, pos, type=None, cname=None): ExprNode.__init__(self, pos, type=type) if cname is not None: self.cname = cname def analyse_types(self, env): return self def set_cname(self, cname): self.cname = cname def result(self): return self.cname def generate_result_code(self, code): pass #------------------------------------------------------------------- # # Parallel nodes (cython.parallel.thread(savailable|id)) # #------------------------------------------------------------------- class ParallelThreadsAvailableNode(AtomicExprNode): """ Note: this is disabled and not a valid directive at this moment Implements cython.parallel.threadsavailable(). If we are called from the sequential part of the application, we need to call omp_get_max_threads(), and in the parallel part we can just call omp_get_num_threads() """ type = PyrexTypes.c_int_type def analyse_types(self, env): self.is_temp = True # env.add_include_file("omp.h") return self def generate_result_code(self, code): code.putln("#ifdef _OPENMP") code.putln("if (omp_in_parallel()) %s = omp_get_max_threads();" % self.temp_code) code.putln("else %s = omp_get_num_threads();" % self.temp_code) code.putln("#else") code.putln("%s = 1;" % self.temp_code) code.putln("#endif") def result(self): return self.temp_code class ParallelThreadIdNode(AtomicExprNode): #, Nodes.ParallelNode): """ Implements cython.parallel.threadid() """ type = PyrexTypes.c_int_type def analyse_types(self, env): self.is_temp = True # env.add_include_file("omp.h") return self def generate_result_code(self, code): code.putln("#ifdef _OPENMP") code.putln("%s = omp_get_thread_num();" % self.temp_code) code.putln("#else") code.putln("%s = 0;" % self.temp_code) code.putln("#endif") def result(self): return self.temp_code #------------------------------------------------------------------- # # Trailer nodes # #------------------------------------------------------------------- class IndexNode(ExprNode): # Sequence indexing. # # base ExprNode # index ExprNode # indices [ExprNode] # type_indices [PyrexType] # is_buffer_access boolean Whether this is a buffer access. # # indices is used on buffer access, index on non-buffer access. # The former contains a clean list of index parameters, the # latter whatever Python object is needed for index access. # # is_fused_index boolean Whether the index is used to specialize a # c(p)def function subexprs = ['base', 'index', 'indices'] indices = None type_indices = None is_subscript = True is_fused_index = False # Whether we're assigning to a buffer (in that case it needs to be # writable) writable_needed = False # Whether we are indexing or slicing a memoryviewslice memslice_index = False memslice_slice = False is_memslice_copy = False memslice_ellipsis_noop = False warned_untyped_idx = False # set by SingleAssignmentNode after analyse_types() is_memslice_scalar_assignment = False def __init__(self, pos, index, **kw): ExprNode.__init__(self, pos, index=index, **kw) self._index = index def calculate_constant_result(self): self.constant_result = \ self.base.constant_result[self.index.constant_result] def compile_time_value(self, denv): base = self.base.compile_time_value(denv) index = self.index.compile_time_value(denv) try: return base[index] except Exception, e: self.compile_time_value_error(e) def is_ephemeral(self): return self.base.is_ephemeral() def is_simple(self): if self.is_buffer_access or self.memslice_index: return False elif self.memslice_slice: return True base = self.base return (base.is_simple() and self.index.is_simple() and base.type and (base.type.is_ptr or base.type.is_array)) def may_be_none(self): base_type = self.base.type if base_type: if base_type.is_string: return False if isinstance(self.index, SliceNode): # slicing! if base_type in (bytes_type, str_type, unicode_type, basestring_type, list_type, tuple_type): return False return ExprNode.may_be_none(self) def analyse_target_declaration(self, env): pass def analyse_as_type(self, env): base_type = self.base.analyse_as_type(env) if base_type and not base_type.is_pyobject: if base_type.is_cpp_class: if isinstance(self.index, TupleNode): template_values = self.index.args else: template_values = [self.index] import Nodes type_node = Nodes.TemplatedTypeNode( pos = self.pos, positional_args = template_values, keyword_args = None) return type_node.analyse(env, base_type = base_type) else: index = self.index.compile_time_value(env) if index is not None: return PyrexTypes.CArrayType(base_type, int(index)) error(self.pos, "Array size must be a compile time constant") return None def type_dependencies(self, env): return self.base.type_dependencies(env) + self.index.type_dependencies(env) def infer_type(self, env): base_type = self.base.infer_type(env) if isinstance(self.index, SliceNode): # slicing! if base_type.is_string: # sliced C strings must coerce to Python return bytes_type elif base_type.is_pyunicode_ptr: # sliced Py_UNICODE* strings must coerce to Python return unicode_type elif base_type in (unicode_type, bytes_type, str_type, bytearray_type, list_type, tuple_type): # slicing these returns the same type return base_type else: # TODO: Handle buffers (hopefully without too much redundancy). return py_object_type index_type = self.index.infer_type(env) if index_type and index_type.is_int or isinstance(self.index, IntNode): # indexing! if base_type is unicode_type: # Py_UCS4 will automatically coerce to a unicode string # if required, so this is safe. We only infer Py_UCS4 # when the index is a C integer type. Otherwise, we may # need to use normal Python item access, in which case # it's faster to return the one-char unicode string than # to receive it, throw it away, and potentially rebuild it # on a subsequent PyObject coercion. return PyrexTypes.c_py_ucs4_type elif base_type is str_type: # always returns str - Py2: bytes, Py3: unicode return base_type elif base_type is bytearray_type: return PyrexTypes.c_uchar_type elif isinstance(self.base, BytesNode): #if env.global_scope().context.language_level >= 3: # # inferring 'char' can be made to work in Python 3 mode # return PyrexTypes.c_char_type # Py2/3 return different types on indexing bytes objects return py_object_type elif base_type in (tuple_type, list_type): # if base is a literal, take a look at its values item_type = infer_sequence_item_type( env, self.base, self.index, seq_type=base_type) if item_type is not None: return item_type elif base_type.is_ptr or base_type.is_array: return base_type.base_type if base_type.is_cpp_class: class FakeOperand: def __init__(self, **kwds): self.__dict__.update(kwds) operands = [ FakeOperand(pos=self.pos, type=base_type), FakeOperand(pos=self.pos, type=index_type), ] index_func = env.lookup_operator('[]', operands) if index_func is not None: return index_func.type.return_type # may be slicing or indexing, we don't know if base_type in (unicode_type, str_type): # these types always returns their own type on Python indexing/slicing return base_type else: # TODO: Handle buffers (hopefully without too much redundancy). return py_object_type def analyse_types(self, env): return self.analyse_base_and_index_types(env, getting=True) def analyse_target_types(self, env): node = self.analyse_base_and_index_types(env, setting=True) if node.type.is_const: error(self.pos, "Assignment to const dereference") if not node.is_lvalue(): error(self.pos, "Assignment to non-lvalue of type '%s'" % node.type) return node def analyse_base_and_index_types(self, env, getting=False, setting=False, analyse_base=True): # Note: This might be cleaned up by having IndexNode # parsed in a saner way and only construct the tuple if # needed. # Note that this function must leave IndexNode in a cloneable state. # For buffers, self.index is packed out on the initial analysis, and # when cloning self.indices is copied. self.is_buffer_access = False # a[...] = b self.is_memslice_copy = False # incomplete indexing, Ellipsis indexing or slicing self.memslice_slice = False # integer indexing self.memslice_index = False if analyse_base: self.base = self.base.analyse_types(env) if self.base.type.is_error: # Do not visit child tree if base is undeclared to avoid confusing # error messages self.type = PyrexTypes.error_type return self is_slice = isinstance(self.index, SliceNode) if not env.directives['wraparound']: if is_slice: check_negative_indices(self.index.start, self.index.stop) else: check_negative_indices(self.index) # Potentially overflowing index value. if not is_slice and isinstance(self.index, IntNode) and Utils.long_literal(self.index.value): self.index = self.index.coerce_to_pyobject(env) is_memslice = self.base.type.is_memoryviewslice # Handle the case where base is a literal char* (and we expect a string, not an int) if not is_memslice and (isinstance(self.base, BytesNode) or is_slice): if self.base.type.is_string or not (self.base.type.is_ptr or self.base.type.is_array): self.base = self.base.coerce_to_pyobject(env) skip_child_analysis = False buffer_access = False if self.indices: indices = self.indices elif isinstance(self.index, TupleNode): indices = self.index.args else: indices = [self.index] if (is_memslice and not self.indices and isinstance(self.index, EllipsisNode)): # Memoryviewslice copying self.is_memslice_copy = True elif is_memslice: # memoryviewslice indexing or slicing import MemoryView skip_child_analysis = True newaxes = [newaxis for newaxis in indices if newaxis.is_none] have_slices, indices = MemoryView.unellipsify(indices, newaxes, self.base.type.ndim) self.memslice_index = (not newaxes and len(indices) == self.base.type.ndim) axes = [] index_type = PyrexTypes.c_py_ssize_t_type new_indices = [] if len(indices) - len(newaxes) > self.base.type.ndim: self.type = error_type error(indices[self.base.type.ndim].pos, "Too many indices specified for type %s" % self.base.type) return self axis_idx = 0 for i, index in enumerate(indices[:]): index = index.analyse_types(env) if not index.is_none: access, packing = self.base.type.axes[axis_idx] axis_idx += 1 if isinstance(index, SliceNode): self.memslice_slice = True if index.step.is_none: axes.append((access, packing)) else: axes.append((access, 'strided')) # Coerce start, stop and step to temps of the right type for attr in ('start', 'stop', 'step'): value = getattr(index, attr) if not value.is_none: value = value.coerce_to(index_type, env) #value = value.coerce_to_temp(env) setattr(index, attr, value) new_indices.append(value) elif index.is_none: self.memslice_slice = True new_indices.append(index) axes.append(('direct', 'strided')) elif index.type.is_int or index.type.is_pyobject: if index.type.is_pyobject and not self.warned_untyped_idx: warning(index.pos, "Index should be typed for more " "efficient access", level=2) IndexNode.warned_untyped_idx = True self.memslice_index = True index = index.coerce_to(index_type, env) indices[i] = index new_indices.append(index) else: self.type = error_type error(index.pos, "Invalid index for memoryview specified") return self self.memslice_index = self.memslice_index and not self.memslice_slice self.original_indices = indices # All indices with all start/stop/step for slices. # We need to keep this around self.indices = new_indices self.env = env elif self.base.type.is_buffer: # Buffer indexing if len(indices) == self.base.type.ndim: buffer_access = True skip_child_analysis = True for x in indices: x = x.analyse_types(env) if not x.type.is_int: buffer_access = False if buffer_access and not self.base.type.is_memoryviewslice: assert hasattr(self.base, "entry") # Must be a NameNode-like node # On cloning, indices is cloned. Otherwise, unpack index into indices assert not (buffer_access and isinstance(self.index, CloneNode)) self.nogil = env.nogil if buffer_access or self.memslice_index: #if self.base.type.is_memoryviewslice and not self.base.is_name: # self.base = self.base.coerce_to_temp(env) self.base = self.base.coerce_to_simple(env) self.indices = indices self.index = None self.type = self.base.type.dtype self.is_buffer_access = True self.buffer_type = self.base.type #self.base.entry.type if getting and self.type.is_pyobject: self.is_temp = True if setting and self.base.type.is_memoryviewslice: self.base.type.writable_needed = True elif setting: if not self.base.entry.type.writable: error(self.pos, "Writing to readonly buffer") else: self.writable_needed = True if self.base.type.is_buffer: self.base.entry.buffer_aux.writable_needed = True elif self.is_memslice_copy: self.type = self.base.type if getting: self.memslice_ellipsis_noop = True else: self.memslice_broadcast = True elif self.memslice_slice: self.index = None self.is_temp = True self.use_managed_ref = True if not MemoryView.validate_axes(self.pos, axes): self.type = error_type return self self.type = PyrexTypes.MemoryViewSliceType( self.base.type.dtype, axes) if (self.base.type.is_memoryviewslice and not self.base.is_name and not self.base.result_in_temp()): self.base = self.base.coerce_to_temp(env) if setting: self.memslice_broadcast = True else: base_type = self.base.type if not base_type.is_cfunction: if isinstance(self.index, TupleNode): self.index = self.index.analyse_types( env, skip_children=skip_child_analysis) elif not skip_child_analysis: self.index = self.index.analyse_types(env) self.original_index_type = self.index.type if base_type.is_unicode_char: # we infer Py_UNICODE/Py_UCS4 for unicode strings in some # cases, but indexing must still work for them if setting: warning(self.pos, "cannot assign to Unicode string index", level=1) elif self.index.constant_result in (0, -1): # uchar[0] => uchar return self.base self.base = self.base.coerce_to_pyobject(env) base_type = self.base.type if base_type.is_pyobject: if self.index.type.is_int and base_type is not dict_type: if (getting and (base_type in (list_type, tuple_type, bytearray_type)) and (not self.index.type.signed or not env.directives['wraparound'] or (isinstance(self.index, IntNode) and self.index.has_constant_result() and self.index.constant_result >= 0)) and not env.directives['boundscheck']): self.is_temp = 0 else: self.is_temp = 1 self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env) self.original_index_type.create_to_py_utility_code(env) else: self.index = self.index.coerce_to_pyobject(env) self.is_temp = 1 if self.index.type.is_int and base_type is unicode_type: # Py_UNICODE/Py_UCS4 will automatically coerce to a unicode string # if required, so this is fast and safe self.type = PyrexTypes.c_py_ucs4_type elif self.index.type.is_int and base_type is bytearray_type: if setting: self.type = PyrexTypes.c_uchar_type else: # not using 'uchar' to enable fast and safe error reporting as '-1' self.type = PyrexTypes.c_int_type elif is_slice and base_type in (bytes_type, str_type, unicode_type, list_type, tuple_type): self.type = base_type else: item_type = None if base_type in (list_type, tuple_type) and self.index.type.is_int: item_type = infer_sequence_item_type( env, self.base, self.index, seq_type=base_type) if item_type is None: item_type = py_object_type self.type = item_type if base_type in (list_type, tuple_type, dict_type): # do the None check explicitly (not in a helper) to allow optimising it away self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable") else: if base_type.is_ptr or base_type.is_array: self.type = base_type.base_type if is_slice: self.type = base_type elif self.index.type.is_pyobject: self.index = self.index.coerce_to( PyrexTypes.c_py_ssize_t_type, env) elif not self.index.type.is_int: error(self.pos, "Invalid index type '%s'" % self.index.type) elif base_type.is_cpp_class: function = env.lookup_operator("[]", [self.base, self.index]) if function is None: error(self.pos, "Indexing '%s' not supported for index type '%s'" % (base_type, self.index.type)) self.type = PyrexTypes.error_type self.result_code = "" return self func_type = function.type if func_type.is_ptr: func_type = func_type.base_type self.index = self.index.coerce_to(func_type.args[0].type, env) self.type = func_type.return_type if setting and not func_type.return_type.is_reference: error(self.pos, "Can't set non-reference result '%s'" % self.type) elif base_type.is_cfunction: if base_type.is_fused: self.parse_indexed_fused_cdef(env) else: self.type_indices = self.parse_index_as_types(env) if base_type.templates is None: error(self.pos, "Can only parameterize template functions.") elif len(base_type.templates) != len(self.type_indices): error(self.pos, "Wrong number of template arguments: expected %s, got %s" % ( (len(base_type.templates), len(self.type_indices)))) self.type = base_type.specialize(dict(zip(base_type.templates, self.type_indices))) else: error(self.pos, "Attempting to index non-array type '%s'" % base_type) self.type = PyrexTypes.error_type self.wrap_in_nonecheck_node(env, getting) return self def wrap_in_nonecheck_node(self, env, getting): if not env.directives['nonecheck'] or not self.base.may_be_none(): return if self.base.type.is_memoryviewslice: if self.is_memslice_copy and not getting: msg = "Cannot assign to None memoryview slice" elif self.memslice_slice: msg = "Cannot slice None memoryview slice" else: msg = "Cannot index None memoryview slice" else: msg = "'NoneType' object is not subscriptable" self.base = self.base.as_none_safe_node(msg) def parse_index_as_types(self, env, required=True): if isinstance(self.index, TupleNode): indices = self.index.args else: indices = [self.index] type_indices = [] for index in indices: type_indices.append(index.analyse_as_type(env)) if type_indices[-1] is None: if required: error(index.pos, "not parsable as a type") return None return type_indices def parse_indexed_fused_cdef(self, env): """ Interpret fused_cdef_func[specific_type1, ...] Note that if this method is called, we are an indexed cdef function with fused argument types, and this IndexNode will be replaced by the NameNode with specific entry just after analysis of expressions by AnalyseExpressionsTransform. """ self.type = PyrexTypes.error_type self.is_fused_index = True base_type = self.base.type specific_types = [] positions = [] if self.index.is_name or self.index.is_attribute: positions.append(self.index.pos) elif isinstance(self.index, TupleNode): for arg in self.index.args: positions.append(arg.pos) specific_types = self.parse_index_as_types(env, required=False) if specific_types is None: self.index = self.index.analyse_types(env) if not self.base.entry.as_variable: error(self.pos, "Can only index fused functions with types") else: # A cpdef function indexed with Python objects self.base.entry = self.entry = self.base.entry.as_variable self.base.type = self.type = self.entry.type self.base.is_temp = True self.is_temp = True self.entry.used = True self.is_fused_index = False return for i, type in enumerate(specific_types): specific_types[i] = type.specialize_fused(env) fused_types = base_type.get_fused_types() if len(specific_types) > len(fused_types): return error(self.pos, "Too many types specified") elif len(specific_types) < len(fused_types): t = fused_types[len(specific_types)] return error(self.pos, "Not enough types specified to specialize " "the function, %s is still fused" % t) # See if our index types form valid specializations for pos, specific_type, fused_type in zip(positions, specific_types, fused_types): if not Utils.any([specific_type.same_as(t) for t in fused_type.types]): return error(pos, "Type not in fused type") if specific_type is None or specific_type.is_error: return fused_to_specific = dict(zip(fused_types, specific_types)) type = base_type.specialize(fused_to_specific) if type.is_fused: # Only partially specific, this is invalid error(self.pos, "Index operation makes function only partially specific") else: # Fully specific, find the signature with the specialized entry for signature in self.base.type.get_all_specialized_function_types(): if type.same_as(signature): self.type = signature if self.base.is_attribute: # Pretend to be a normal attribute, for cdef extension # methods self.entry = signature.entry self.is_attribute = True self.obj = self.base.obj self.type.entry.used = True self.base.type = signature self.base.entry = signature.entry break else: # This is a bug raise InternalError("Couldn't find the right signature") gil_message = "Indexing Python object" def nogil_check(self, env): if self.is_buffer_access or self.memslice_index or self.memslice_slice: if not self.memslice_slice and env.directives['boundscheck']: # error(self.pos, "Cannot check buffer index bounds without gil; " # "use boundscheck(False) directive") warning(self.pos, "Use boundscheck(False) for faster access", level=1) if self.type.is_pyobject: error(self.pos, "Cannot access buffer with object dtype without gil") return super(IndexNode, self).nogil_check(env) def check_const_addr(self): return self.base.check_const_addr() and self.index.check_const() def is_lvalue(self): # NOTE: references currently have both is_reference and is_ptr # set. Since pointers and references have different lvalue # rules, we must be careful to separate the two. if self.type.is_reference: if self.type.ref_base_type.is_array: # fixed-sized arrays aren't l-values return False elif self.type.is_ptr: # non-const pointers can always be reassigned return True elif self.type.is_array: # fixed-sized arrays aren't l-values return False # Just about everything else returned by the index operator # can be an lvalue. return True def calculate_result_code(self): if self.is_buffer_access: return "(*%s)" % self.buffer_ptr_code elif self.is_memslice_copy: return self.base.result() elif self.base.type in (list_type, tuple_type, bytearray_type): if self.base.type is list_type: index_code = "PyList_GET_ITEM(%s, %s)" elif self.base.type is tuple_type: index_code = "PyTuple_GET_ITEM(%s, %s)" elif self.base.type is bytearray_type: index_code = "((unsigned char)(PyByteArray_AS_STRING(%s)[%s]))" else: assert False, "unexpected base type in indexing: %s" % self.base.type elif self.base.type.is_cfunction: return "%s<%s>" % ( self.base.result(), ",".join([param.declaration_code("") for param in self.type_indices])) else: if (self.type.is_ptr or self.type.is_array) and self.type == self.base.type: error(self.pos, "Invalid use of pointer slice") return index_code = "(%s[%s])" return index_code % (self.base.result(), self.index.result()) def extra_index_params(self, code): if self.index.type.is_int: is_list = self.base.type is list_type wraparound = ( bool(code.globalstate.directives['wraparound']) and self.original_index_type.signed and not (isinstance(self.index.constant_result, (int, long)) and self.index.constant_result >= 0)) boundscheck = bool(code.globalstate.directives['boundscheck']) return ", %s, %d, %s, %d, %d, %d" % ( self.original_index_type.declaration_code(""), self.original_index_type.signed and 1 or 0, self.original_index_type.to_py_function, is_list, wraparound, boundscheck) else: return "" def generate_subexpr_evaluation_code(self, code): self.base.generate_evaluation_code(code) if self.type_indices is not None: pass elif self.indices is None: self.index.generate_evaluation_code(code) else: for i in self.indices: i.generate_evaluation_code(code) def generate_subexpr_disposal_code(self, code): self.base.generate_disposal_code(code) if self.type_indices is not None: pass elif self.indices is None: self.index.generate_disposal_code(code) else: for i in self.indices: i.generate_disposal_code(code) def free_subexpr_temps(self, code): self.base.free_temps(code) if self.indices is None: self.index.free_temps(code) else: for i in self.indices: i.free_temps(code) def generate_result_code(self, code): if self.is_buffer_access or self.memslice_index: buffer_entry, self.buffer_ptr_code = self.buffer_lookup_code(code) if self.type.is_pyobject: # is_temp is True, so must pull out value and incref it. # NOTE: object temporary results for nodes are declared # as PyObject *, so we need a cast code.putln("%s = (PyObject *) *%s;" % (self.temp_code, self.buffer_ptr_code)) code.putln("__Pyx_INCREF((PyObject*)%s);" % self.temp_code) elif self.memslice_slice: self.put_memoryviewslice_slice_code(code) elif self.is_temp: if self.type.is_pyobject: error_value = 'NULL' if self.index.type.is_int: if self.base.type is list_type: function = "__Pyx_GetItemInt_List" elif self.base.type is tuple_type: function = "__Pyx_GetItemInt_Tuple" else: function = "__Pyx_GetItemInt" code.globalstate.use_utility_code( TempitaUtilityCode.load_cached("GetItemInt", "ObjectHandling.c")) else: if self.base.type is dict_type: function = "__Pyx_PyDict_GetItem" code.globalstate.use_utility_code( UtilityCode.load_cached("DictGetItem", "ObjectHandling.c")) else: function = "PyObject_GetItem" elif self.type.is_unicode_char and self.base.type is unicode_type: assert self.index.type.is_int function = "__Pyx_GetItemInt_Unicode" error_value = '(Py_UCS4)-1' code.globalstate.use_utility_code( UtilityCode.load_cached("GetItemIntUnicode", "StringTools.c")) elif self.base.type is bytearray_type: assert self.index.type.is_int assert self.type.is_int function = "__Pyx_GetItemInt_ByteArray" error_value = '-1' code.globalstate.use_utility_code( UtilityCode.load_cached("GetItemIntByteArray", "StringTools.c")) else: assert False, "unexpected type %s and base type %s for indexing" % ( self.type, self.base.type) if self.index.type.is_int: index_code = self.index.result() else: index_code = self.index.py_result() code.putln( "%s = %s(%s, %s%s); if (unlikely(%s == %s)) %s;" % ( self.result(), function, self.base.py_result(), index_code, self.extra_index_params(code), self.result(), error_value, code.error_goto(self.pos))) if self.type.is_pyobject: code.put_gotref(self.py_result()) def generate_setitem_code(self, value_code, code): if self.index.type.is_int: if self.base.type is bytearray_type: code.globalstate.use_utility_code( UtilityCode.load_cached("SetItemIntByteArray", "StringTools.c")) function = "__Pyx_SetItemInt_ByteArray" else: code.globalstate.use_utility_code( UtilityCode.load_cached("SetItemInt", "ObjectHandling.c")) function = "__Pyx_SetItemInt" index_code = self.index.result() else: index_code = self.index.py_result() if self.base.type is dict_type: function = "PyDict_SetItem" # It would seem that we could specialized lists/tuples, but that # shouldn't happen here. # Both PyList_SetItem() and PyTuple_SetItem() take a Py_ssize_t as # index instead of an object, and bad conversion here would give # the wrong exception. Also, tuples are supposed to be immutable, # and raise a TypeError when trying to set their entries # (PyTuple_SetItem() is for creating new tuples from scratch). else: function = "PyObject_SetItem" code.putln( "if (unlikely(%s(%s, %s, %s%s) < 0)) %s" % ( function, self.base.py_result(), index_code, value_code, self.extra_index_params(code), code.error_goto(self.pos))) def generate_buffer_setitem_code(self, rhs, code, op=""): # Used from generate_assignment_code and InPlaceAssignmentNode buffer_entry, ptrexpr = self.buffer_lookup_code(code) if self.buffer_type.dtype.is_pyobject: # Must manage refcounts. Decref what is already there # and incref what we put in. ptr = code.funcstate.allocate_temp(buffer_entry.buf_ptr_type, manage_ref=False) rhs_code = rhs.result() code.putln("%s = %s;" % (ptr, ptrexpr)) code.put_gotref("*%s" % ptr) code.putln("__Pyx_INCREF(%s); __Pyx_DECREF(*%s);" % ( rhs_code, ptr)) code.putln("*%s %s= %s;" % (ptr, op, rhs_code)) code.put_giveref("*%s" % ptr) code.funcstate.release_temp(ptr) else: # Simple case code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result())) def generate_assignment_code(self, rhs, code): generate_evaluation_code = (self.is_memslice_scalar_assignment or self.memslice_slice) if generate_evaluation_code: self.generate_evaluation_code(code) else: self.generate_subexpr_evaluation_code(code) if self.is_buffer_access or self.memslice_index: self.generate_buffer_setitem_code(rhs, code) elif self.is_memslice_scalar_assignment: self.generate_memoryviewslice_assign_scalar_code(rhs, code) elif self.memslice_slice or self.is_memslice_copy: self.generate_memoryviewslice_setslice_code(rhs, code) elif self.type.is_pyobject: self.generate_setitem_code(rhs.py_result(), code) elif self.base.type is bytearray_type: value_code = self._check_byte_value(code, rhs) self.generate_setitem_code(value_code, code) else: code.putln( "%s = %s;" % ( self.result(), rhs.result())) if generate_evaluation_code: self.generate_disposal_code(code) else: self.generate_subexpr_disposal_code(code) self.free_subexpr_temps(code) rhs.generate_disposal_code(code) rhs.free_temps(code) def _check_byte_value(self, code, rhs): # TODO: should we do this generally on downcasts, or just here? assert rhs.type.is_int, repr(rhs.type) value_code = rhs.result() if rhs.has_constant_result(): if 0 <= rhs.constant_result < 256: return value_code needs_cast = True # make at least the C compiler happy warning(rhs.pos, "value outside of range(0, 256)" " when assigning to byte: %s" % rhs.constant_result, level=1) else: needs_cast = rhs.type != PyrexTypes.c_uchar_type if not self.nogil: conditions = [] if rhs.is_literal or rhs.type.signed: conditions.append('%s < 0' % value_code) if (rhs.is_literal or not (rhs.is_temp and rhs.type in ( PyrexTypes.c_uchar_type, PyrexTypes.c_char_type, PyrexTypes.c_schar_type))): conditions.append('%s > 255' % value_code) if conditions: code.putln("if (unlikely(%s)) {" % ' || '.join(conditions)) code.putln( 'PyErr_SetString(PyExc_ValueError,' ' "byte must be in range(0, 256)"); %s' % code.error_goto(self.pos)) code.putln("}") if needs_cast: value_code = '((unsigned char)%s)' % value_code return value_code def generate_deletion_code(self, code, ignore_nonexisting=False): self.generate_subexpr_evaluation_code(code) #if self.type.is_pyobject: if self.index.type.is_int: function = "__Pyx_DelItemInt" index_code = self.index.result() code.globalstate.use_utility_code( UtilityCode.load_cached("DelItemInt", "ObjectHandling.c")) else: index_code = self.index.py_result() if self.base.type is dict_type: function = "PyDict_DelItem" else: function = "PyObject_DelItem" code.putln( "if (%s(%s, %s%s) < 0) %s" % ( function, self.base.py_result(), index_code, self.extra_index_params(code), code.error_goto(self.pos))) self.generate_subexpr_disposal_code(code) self.free_subexpr_temps(code) def buffer_entry(self): import Buffer, MemoryView base = self.base if self.base.is_nonecheck: base = base.arg if base.is_name: entry = base.entry else: # SimpleCallNode is_simple is not consistent with coerce_to_simple assert base.is_simple() or base.is_temp cname = base.result() entry = Symtab.Entry(cname, cname, self.base.type, self.base.pos) if entry.type.is_buffer: buffer_entry = Buffer.BufferEntry(entry) else: buffer_entry = MemoryView.MemoryViewSliceBufferEntry(entry) return buffer_entry def buffer_lookup_code(self, code): "ndarray[1, 2, 3] and memslice[1, 2, 3]" # Assign indices to temps index_temps = [code.funcstate.allocate_temp(i.type, manage_ref=False) for i in self.indices] for temp, index in zip(index_temps, self.indices): code.putln("%s = %s;" % (temp, index.result())) # Generate buffer access code using these temps import Buffer buffer_entry = self.buffer_entry() if buffer_entry.type.is_buffer: negative_indices = buffer_entry.type.negative_indices else: negative_indices = Buffer.buffer_defaults['negative_indices'] return buffer_entry, Buffer.put_buffer_lookup_code( entry=buffer_entry, index_signeds=[i.type.signed for i in self.indices], index_cnames=index_temps, directives=code.globalstate.directives, pos=self.pos, code=code, negative_indices=negative_indices, in_nogil_context=self.in_nogil_context) def put_memoryviewslice_slice_code(self, code): "memslice[:]" buffer_entry = self.buffer_entry() have_gil = not self.in_nogil_context if sys.version_info < (3,): def next_(it): return it.next() else: next_ = next have_slices = False it = iter(self.indices) for index in self.original_indices: is_slice = isinstance(index, SliceNode) have_slices = have_slices or is_slice if is_slice: if not index.start.is_none: index.start = next_(it) if not index.stop.is_none: index.stop = next_(it) if not index.step.is_none: index.step = next_(it) else: next_(it) assert not list(it) buffer_entry.generate_buffer_slice_code(code, self.original_indices, self.result(), have_gil=have_gil, have_slices=have_slices, directives=code.globalstate.directives) def generate_memoryviewslice_setslice_code(self, rhs, code): "memslice1[...] = memslice2 or memslice1[:] = memslice2" import MemoryView MemoryView.copy_broadcast_memview_src_to_dst(rhs, self, code) def generate_memoryviewslice_assign_scalar_code(self, rhs, code): "memslice1[...] = 0.0 or memslice1[:] = 0.0" import MemoryView MemoryView.assign_scalar(self, rhs, code) class SliceIndexNode(ExprNode): # 2-element slice indexing # # base ExprNode # start ExprNode or None # stop ExprNode or None # slice ExprNode or None constant slice object subexprs = ['base', 'start', 'stop', 'slice'] slice = None def infer_type(self, env): base_type = self.base.infer_type(env) if base_type.is_string or base_type.is_cpp_class: return bytes_type elif base_type.is_pyunicode_ptr: return unicode_type elif base_type in (bytes_type, str_type, unicode_type, basestring_type, list_type, tuple_type): return base_type elif base_type.is_ptr or base_type.is_array: return PyrexTypes.c_array_type(base_type.base_type, None) return py_object_type def may_be_none(self): base_type = self.base.type if base_type: if base_type.is_string: return False if base_type in (bytes_type, str_type, unicode_type, basestring_type, list_type, tuple_type): return False return ExprNode.may_be_none(self) def calculate_constant_result(self): if self.start is None: start = None else: start = self.start.constant_result if self.stop is None: stop = None else: stop = self.stop.constant_result self.constant_result = self.base.constant_result[start:stop] def compile_time_value(self, denv): base = self.base.compile_time_value(denv) if self.start is None: start = 0 else: start = self.start.compile_time_value(denv) if self.stop is None: stop = None else: stop = self.stop.compile_time_value(denv) try: return base[start:stop] except Exception, e: self.compile_time_value_error(e) def analyse_target_declaration(self, env): pass def analyse_target_types(self, env): node = self.analyse_types(env, getting=False) # when assigning, we must accept any Python type if node.type.is_pyobject: node.type = py_object_type return node def analyse_types(self, env, getting=True): self.base = self.base.analyse_types(env) if self.base.type.is_memoryviewslice: none_node = NoneNode(self.pos) index = SliceNode(self.pos, start=self.start or none_node, stop=self.stop or none_node, step=none_node) index_node = IndexNode(self.pos, index, base=self.base) return index_node.analyse_base_and_index_types( env, getting=getting, setting=not getting, analyse_base=False) if self.start: self.start = self.start.analyse_types(env) if self.stop: self.stop = self.stop.analyse_types(env) if not env.directives['wraparound']: check_negative_indices(self.start, self.stop) base_type = self.base.type if base_type.is_string or base_type.is_cpp_string: self.type = default_str_type(env) elif base_type.is_pyunicode_ptr: self.type = unicode_type elif base_type.is_ptr: self.type = base_type elif base_type.is_array: # we need a ptr type here instead of an array type, as # array types can result in invalid type casts in the C # code self.type = PyrexTypes.CPtrType(base_type.base_type) else: self.base = self.base.coerce_to_pyobject(env) self.type = py_object_type if base_type.is_builtin_type: # slicing builtin types returns something of the same type self.type = base_type self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable") if self.type is py_object_type: if (not self.start or self.start.is_literal) and \ (not self.stop or self.stop.is_literal): # cache the constant slice object, in case we need it none_node = NoneNode(self.pos) self.slice = SliceNode( self.pos, start=copy.deepcopy(self.start or none_node), stop=copy.deepcopy(self.stop or none_node), step=none_node ).analyse_types(env) else: c_int = PyrexTypes.c_py_ssize_t_type if self.start: self.start = self.start.coerce_to(c_int, env) if self.stop: self.stop = self.stop.coerce_to(c_int, env) self.is_temp = 1 return self nogil_check = Node.gil_error gil_message = "Slicing Python object" get_slice_utility_code = TempitaUtilityCode.load( "SliceObject", "ObjectHandling.c", context={'access': 'Get'}) set_slice_utility_code = TempitaUtilityCode.load( "SliceObject", "ObjectHandling.c", context={'access': 'Set'}) def coerce_to(self, dst_type, env): if ((self.base.type.is_string or self.base.type.is_cpp_string) and dst_type in (bytes_type, bytearray_type, str_type, unicode_type)): if (dst_type not in (bytes_type, bytearray_type) and not env.directives['c_string_encoding']): error(self.pos, "default encoding required for conversion from '%s' to '%s'" % (self.base.type, dst_type)) self.type = dst_type return super(SliceIndexNode, self).coerce_to(dst_type, env) def generate_result_code(self, code): if not self.type.is_pyobject: error(self.pos, "Slicing is not currently supported for '%s'." % self.type) return base_result = self.base.result() result = self.result() start_code = self.start_code() stop_code = self.stop_code() if self.base.type.is_string: base_result = self.base.result() if self.base.type != PyrexTypes.c_char_ptr_type: base_result = '((const char*)%s)' % base_result if self.type is bytearray_type: type_name = 'ByteArray' else: type_name = self.type.name.title() if self.stop is None: code.putln( "%s = __Pyx_Py%s_FromString(%s + %s); %s" % ( result, type_name, base_result, start_code, code.error_goto_if_null(result, self.pos))) else: code.putln( "%s = __Pyx_Py%s_FromStringAndSize(%s + %s, %s - %s); %s" % ( result, type_name, base_result, start_code, stop_code, start_code, code.error_goto_if_null(result, self.pos))) elif self.base.type.is_pyunicode_ptr: base_result = self.base.result() if self.base.type != PyrexTypes.c_py_unicode_ptr_type: base_result = '((const Py_UNICODE*)%s)' % base_result if self.stop is None: code.putln( "%s = __Pyx_PyUnicode_FromUnicode(%s + %s); %s" % ( result, base_result, start_code, code.error_goto_if_null(result, self.pos))) else: code.putln( "%s = __Pyx_PyUnicode_FromUnicodeAndLength(%s + %s, %s - %s); %s" % ( result, base_result, start_code, stop_code, start_code, code.error_goto_if_null(result, self.pos))) elif self.base.type is unicode_type: code.globalstate.use_utility_code( UtilityCode.load_cached("PyUnicode_Substring", "StringTools.c")) code.putln( "%s = __Pyx_PyUnicode_Substring(%s, %s, %s); %s" % ( result, base_result, start_code, stop_code, code.error_goto_if_null(result, self.pos))) elif self.type is py_object_type: code.globalstate.use_utility_code(self.get_slice_utility_code) (has_c_start, has_c_stop, c_start, c_stop, py_start, py_stop, py_slice) = self.get_slice_config() code.putln( "%s = __Pyx_PyObject_GetSlice(%s, %s, %s, %s, %s, %s, %d, %d, %d); %s" % ( result, self.base.py_result(), c_start, c_stop, py_start, py_stop, py_slice, has_c_start, has_c_stop, bool(code.globalstate.directives['wraparound']), code.error_goto_if_null(result, self.pos))) else: if self.base.type is list_type: code.globalstate.use_utility_code( TempitaUtilityCode.load_cached("SliceTupleAndList", "ObjectHandling.c")) cfunc = '__Pyx_PyList_GetSlice' elif self.base.type is tuple_type: code.globalstate.use_utility_code( TempitaUtilityCode.load_cached("SliceTupleAndList", "ObjectHandling.c")) cfunc = '__Pyx_PyTuple_GetSlice' else: cfunc = '__Pyx_PySequence_GetSlice' code.putln( "%s = %s(%s, %s, %s); %s" % ( result, cfunc, self.base.py_result(), start_code, stop_code, code.error_goto_if_null(result, self.pos))) code.put_gotref(self.py_result()) def generate_assignment_code(self, rhs, code): self.generate_subexpr_evaluation_code(code) if self.type.is_pyobject: code.globalstate.use_utility_code(self.set_slice_utility_code) (has_c_start, has_c_stop, c_start, c_stop, py_start, py_stop, py_slice) = self.get_slice_config() code.put_error_if_neg(self.pos, "__Pyx_PyObject_SetSlice(%s, %s, %s, %s, %s, %s, %s, %d, %d, %d)" % ( self.base.py_result(), rhs.py_result(), c_start, c_stop, py_start, py_stop, py_slice, has_c_start, has_c_stop, bool(code.globalstate.directives['wraparound']))) else: start_offset = '' if self.start: start_offset = self.start_code() if start_offset == '0': start_offset = '' else: start_offset += '+' if rhs.type.is_array: array_length = rhs.type.size self.generate_slice_guard_code(code, array_length) else: error(self.pos, "Slice assignments from pointers are not yet supported.") # FIXME: fix the array size according to start/stop array_length = self.base.type.size for i in range(array_length): code.putln("%s[%s%s] = %s[%d];" % ( self.base.result(), start_offset, i, rhs.result(), i)) self.generate_subexpr_disposal_code(code) self.free_subexpr_temps(code) rhs.generate_disposal_code(code) rhs.free_temps(code) def generate_deletion_code(self, code, ignore_nonexisting=False): if not self.base.type.is_pyobject: error(self.pos, "Deleting slices is only supported for Python types, not '%s'." % self.type) return self.generate_subexpr_evaluation_code(code) code.globalstate.use_utility_code(self.set_slice_utility_code) (has_c_start, has_c_stop, c_start, c_stop, py_start, py_stop, py_slice) = self.get_slice_config() code.put_error_if_neg(self.pos, "__Pyx_PyObject_DelSlice(%s, %s, %s, %s, %s, %s, %d, %d, %d)" % ( self.base.py_result(), c_start, c_stop, py_start, py_stop, py_slice, has_c_start, has_c_stop, bool(code.globalstate.directives['wraparound']))) self.generate_subexpr_disposal_code(code) self.free_subexpr_temps(code) def get_slice_config(self): has_c_start, c_start, py_start = False, '0', 'NULL' if self.start: has_c_start = not self.start.type.is_pyobject if has_c_start: c_start = self.start.result() else: py_start = '&%s' % self.start.py_result() has_c_stop, c_stop, py_stop = False, '0', 'NULL' if self.stop: has_c_stop = not self.stop.type.is_pyobject if has_c_stop: c_stop = self.stop.result() else: py_stop = '&%s' % self.stop.py_result() py_slice = self.slice and '&%s' % self.slice.py_result() or 'NULL' return (has_c_start, has_c_stop, c_start, c_stop, py_start, py_stop, py_slice) def generate_slice_guard_code(self, code, target_size): if not self.base.type.is_array: return slice_size = self.base.type.size start = stop = None if self.stop: stop = self.stop.result() try: stop = int(stop) if stop < 0: slice_size = self.base.type.size + stop else: slice_size = stop stop = None except ValueError: pass if self.start: start = self.start.result() try: start = int(start) if start < 0: start = self.base.type.size + start slice_size -= start start = None except ValueError: pass check = None if slice_size < 0: if target_size > 0: error(self.pos, "Assignment to empty slice.") elif start is None and stop is None: # we know the exact slice length if target_size != slice_size: error(self.pos, "Assignment to slice of wrong length, expected %d, got %d" % ( slice_size, target_size)) elif start is not None: if stop is None: stop = slice_size check = "(%s)-(%s)" % (stop, start) else: # stop is not None: check = stop if check: code.putln("if (unlikely((%s) != %d)) {" % (check, target_size)) code.putln('PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length, expected %%" CYTHON_FORMAT_SSIZE_T "d, got %%" CYTHON_FORMAT_SSIZE_T "d", (Py_ssize_t)%d, (Py_ssize_t)(%s));' % ( target_size, check)) code.putln(code.error_goto(self.pos)) code.putln("}") def start_code(self): if self.start: return self.start.result() else: return "0" def stop_code(self): if self.stop: return self.stop.result() elif self.base.type.is_array: return self.base.type.size else: return "PY_SSIZE_T_MAX" def calculate_result_code(self): # self.result() is not used, but this method must exist return "" class SliceNode(ExprNode): # start:stop:step in subscript list # # start ExprNode # stop ExprNode # step ExprNode subexprs = ['start', 'stop', 'step'] type = slice_type is_temp = 1 def calculate_constant_result(self): self.constant_result = slice( self.start.constant_result, self.stop.constant_result, self.step.constant_result) def compile_time_value(self, denv): start = self.start.compile_time_value(denv) stop = self.stop.compile_time_value(denv) step = self.step.compile_time_value(denv) try: return slice(start, stop, step) except Exception, e: self.compile_time_value_error(e) def may_be_none(self): return False def analyse_types(self, env): start = self.start.analyse_types(env) stop = self.stop.analyse_types(env) step = self.step.analyse_types(env) self.start = start.coerce_to_pyobject(env) self.stop = stop.coerce_to_pyobject(env) self.step = step.coerce_to_pyobject(env) if self.start.is_literal and self.stop.is_literal and self.step.is_literal: self.is_literal = True self.is_temp = False return self gil_message = "Constructing Python slice object" def calculate_result_code(self): return self.result_code def generate_result_code(self, code): if self.is_literal: self.result_code = code.get_py_const(py_object_type, 'slice', cleanup_level=2) code = code.get_cached_constants_writer() code.mark_pos(self.pos) code.putln( "%s = PySlice_New(%s, %s, %s); %s" % ( self.result(), self.start.py_result(), self.stop.py_result(), self.step.py_result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) if self.is_literal: code.put_giveref(self.py_result()) def __deepcopy__(self, memo): """ There is a copy bug in python 2.4 for slice objects. """ return SliceNode( self.pos, start=copy.deepcopy(self.start, memo), stop=copy.deepcopy(self.stop, memo), step=copy.deepcopy(self.step, memo), is_temp=self.is_temp, is_literal=self.is_literal, constant_result=self.constant_result) class CallNode(ExprNode): # allow overriding the default 'may_be_none' behaviour may_return_none = None def infer_type(self, env): function = self.function func_type = function.infer_type(env) if isinstance(function, NewExprNode): # note: needs call to infer_type() above return PyrexTypes.CPtrType(function.class_type) if func_type is py_object_type: # function might have lied for safety => try to find better type entry = getattr(function, 'entry', None) if entry is not None: func_type = entry.type or func_type if func_type.is_ptr: func_type = func_type.base_type if func_type.is_cfunction: return func_type.return_type elif func_type is type_type: if function.is_name and function.entry and function.entry.type: result_type = function.entry.type if result_type.is_extension_type: return result_type elif result_type.is_builtin_type: if function.entry.name == 'float': return PyrexTypes.c_double_type elif function.entry.name in Builtin.types_that_construct_their_instance: return result_type return py_object_type def type_dependencies(self, env): # TODO: Update when Danilo's C++ code merged in to handle the # the case of function overloading. return self.function.type_dependencies(env) def is_simple(self): # C function calls could be considered simple, but they may # have side-effects that may hit when multiple operations must # be effected in order, e.g. when constructing the argument # sequence for a function call or comparing values. return False def may_be_none(self): if self.may_return_none is not None: return self.may_return_none func_type = self.function.type if func_type is type_type and self.function.is_name: entry = self.function.entry if entry.type.is_extension_type: return False if (entry.type.is_builtin_type and entry.name in Builtin.types_that_construct_their_instance): return False return ExprNode.may_be_none(self) def analyse_as_type_constructor(self, env): type = self.function.analyse_as_type(env) if type and type.is_struct_or_union: args, kwds = self.explicit_args_kwds() items = [] for arg, member in zip(args, type.scope.var_entries): items.append(DictItemNode(pos=arg.pos, key=StringNode(pos=arg.pos, value=member.name), value=arg)) if kwds: items += kwds.key_value_pairs self.key_value_pairs = items self.__class__ = DictNode self.analyse_types(env) # FIXME self.coerce_to(type, env) return True elif type and type.is_cpp_class: self.args = [ arg.analyse_types(env) for arg in self.args ] constructor = type.scope.lookup("") self.function = RawCNameExprNode(self.function.pos, constructor.type) self.function.entry = constructor self.function.set_cname(type.declaration_code("")) self.analyse_c_function_call(env) self.type = type return True def is_lvalue(self): return self.type.is_reference def nogil_check(self, env): func_type = self.function_type() if func_type.is_pyobject: self.gil_error() elif not getattr(func_type, 'nogil', False): self.gil_error() gil_message = "Calling gil-requiring function" class SimpleCallNode(CallNode): # Function call without keyword, * or ** args. # # function ExprNode # args [ExprNode] # arg_tuple ExprNode or None used internally # self ExprNode or None used internally # coerced_self ExprNode or None used internally # wrapper_call bool used internally # has_optional_args bool used internally # nogil bool used internally subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple'] self = None coerced_self = None arg_tuple = None wrapper_call = False has_optional_args = False nogil = False analysed = False def compile_time_value(self, denv): function = self.function.compile_time_value(denv) args = [arg.compile_time_value(denv) for arg in self.args] try: return function(*args) except Exception, e: self.compile_time_value_error(e) def analyse_as_type(self, env): attr = self.function.as_cython_attribute() if attr == 'pointer': if len(self.args) != 1: error(self.args.pos, "only one type allowed.") else: type = self.args[0].analyse_as_type(env) if not type: error(self.args[0].pos, "Unknown type") else: return PyrexTypes.CPtrType(type) def explicit_args_kwds(self): return self.args, None def analyse_types(self, env): if self.analyse_as_type_constructor(env): return self if self.analysed: return self self.analysed = True self.function.is_called = 1 self.function = self.function.analyse_types(env) function = self.function if function.is_attribute and function.entry and function.entry.is_cmethod: # Take ownership of the object from which the attribute # was obtained, because we need to pass it as 'self'. self.self = function.obj function.obj = CloneNode(self.self) func_type = self.function_type() if func_type.is_pyobject: self.arg_tuple = TupleNode(self.pos, args = self.args) self.arg_tuple = self.arg_tuple.analyse_types(env) self.args = None if func_type is Builtin.type_type and function.is_name and \ function.entry and \ function.entry.is_builtin and \ function.entry.name in Builtin.types_that_construct_their_instance: # calling a builtin type that returns a specific object type if function.entry.name == 'float': # the following will come true later on in a transform self.type = PyrexTypes.c_double_type self.result_ctype = PyrexTypes.c_double_type else: self.type = Builtin.builtin_types[function.entry.name] self.result_ctype = py_object_type self.may_return_none = False elif function.is_name and function.type_entry: # We are calling an extension type constructor. As # long as we do not support __new__(), the result type # is clear self.type = function.type_entry.type self.result_ctype = py_object_type self.may_return_none = False else: self.type = py_object_type self.is_temp = 1 else: self.args = [ arg.analyse_types(env) for arg in self.args ] self.analyse_c_function_call(env) return self def function_type(self): # Return the type of the function being called, coercing a function # pointer to a function if necessary. If the function has fused # arguments, return the specific type. func_type = self.function.type if func_type.is_ptr: func_type = func_type.base_type return func_type def analyse_c_function_call(self, env): if self.function.type is error_type: self.type = error_type return if self.self: args = [self.self] + self.args else: args = self.args if self.function.type.is_cpp_class: overloaded_entry = self.function.type.scope.lookup("operator()") if overloaded_entry is None: self.type = PyrexTypes.error_type self.result_code = "" return elif hasattr(self.function, 'entry'): overloaded_entry = self.function.entry elif (isinstance(self.function, IndexNode) and self.function.is_fused_index): overloaded_entry = self.function.type.entry else: overloaded_entry = None if overloaded_entry: if self.function.type.is_fused: functypes = self.function.type.get_all_specialized_function_types() alternatives = [f.entry for f in functypes] else: alternatives = overloaded_entry.all_alternatives() entry = PyrexTypes.best_match(args, alternatives, self.pos, env) if not entry: self.type = PyrexTypes.error_type self.result_code = "" return entry.used = True self.function.entry = entry self.function.type = entry.type func_type = self.function_type() else: entry = None func_type = self.function_type() if not func_type.is_cfunction: error(self.pos, "Calling non-function type '%s'" % func_type) self.type = PyrexTypes.error_type self.result_code = "" return # Check no. of args max_nargs = len(func_type.args) expected_nargs = max_nargs - func_type.optional_arg_count actual_nargs = len(args) if func_type.optional_arg_count and expected_nargs != actual_nargs: self.has_optional_args = 1 self.is_temp = 1 # check 'self' argument if entry and entry.is_cmethod and func_type.args: formal_arg = func_type.args[0] arg = args[0] if formal_arg.not_none: if self.self: self.self = self.self.as_none_safe_node( "'NoneType' object has no attribute '%s'", error='PyExc_AttributeError', format_args=[entry.name]) else: # unbound method arg = arg.as_none_safe_node( "descriptor '%s' requires a '%s' object but received a 'NoneType'", format_args=[entry.name, formal_arg.type.name]) if self.self: if formal_arg.accept_builtin_subtypes: arg = CMethodSelfCloneNode(self.self) else: arg = CloneNode(self.self) arg = self.coerced_self = arg.coerce_to(formal_arg.type, env) elif formal_arg.type.is_builtin_type: # special case: unbound methods of builtins accept subtypes arg = arg.coerce_to(formal_arg.type, env) if arg.type.is_builtin_type and isinstance(arg, PyTypeTestNode): arg.exact_builtin_type = False args[0] = arg # Coerce arguments some_args_in_temps = False for i in xrange(min(max_nargs, actual_nargs)): formal_arg = func_type.args[i] formal_type = formal_arg.type arg = args[i].coerce_to(formal_type, env) if formal_arg.not_none: # C methods must do the None checks at *call* time arg = arg.as_none_safe_node( "cannot pass None into a C function argument that is declared 'not None'") if arg.is_temp: if i > 0: # first argument in temp doesn't impact subsequent arguments some_args_in_temps = True elif arg.type.is_pyobject and not env.nogil: if i == 0 and self.self is not None: # a method's cloned "self" argument is ok pass elif arg.nonlocally_immutable(): # plain local variables are ok pass else: # we do not safely own the argument's reference, # but we must make sure it cannot be collected # before we return from the function, so we create # an owned temp reference to it if i > 0: # first argument doesn't matter some_args_in_temps = True arg = arg.coerce_to_temp(env) args[i] = arg # handle additional varargs parameters for i in xrange(max_nargs, actual_nargs): arg = args[i] if arg.type.is_pyobject: arg_ctype = arg.type.default_coerced_ctype() if arg_ctype is None: error(self.args[i].pos, "Python object cannot be passed as a varargs parameter") else: args[i] = arg = arg.coerce_to(arg_ctype, env) if arg.is_temp and i > 0: some_args_in_temps = True if some_args_in_temps: # if some args are temps and others are not, they may get # constructed in the wrong order (temps first) => make # sure they are either all temps or all not temps (except # for the last argument, which is evaluated last in any # case) for i in xrange(actual_nargs-1): if i == 0 and self.self is not None: continue # self is ok arg = args[i] if arg.nonlocally_immutable(): # locals, C functions, unassignable types are safe. pass elif arg.type.is_cpp_class: # Assignment has side effects, avoid. pass elif env.nogil and arg.type.is_pyobject: # can't copy a Python reference into a temp in nogil # env (this is safe: a construction would fail in # nogil anyway) pass else: #self.args[i] = arg.coerce_to_temp(env) # instead: issue a warning if i > 0 or i == 1 and self.self is not None: # skip first arg warning(arg.pos, "Argument evaluation order in C function call is undefined and may not be as expected", 0) break self.args[:] = args # Calc result type and code fragment if isinstance(self.function, NewExprNode): self.type = PyrexTypes.CPtrType(self.function.class_type) else: self.type = func_type.return_type if self.function.is_name or self.function.is_attribute: if self.function.entry and self.function.entry.utility_code: self.is_temp = 1 # currently doesn't work for self.calculate_result_code() if self.type.is_pyobject: self.result_ctype = py_object_type self.is_temp = 1 elif func_type.exception_value is not None \ or func_type.exception_check: self.is_temp = 1 elif self.type.is_memoryviewslice: self.is_temp = 1 # func_type.exception_check = True # Called in 'nogil' context? self.nogil = env.nogil if (self.nogil and func_type.exception_check and func_type.exception_check != '+'): env.use_utility_code(pyerr_occurred_withgil_utility_code) # C++ exception handler if func_type.exception_check == '+': if func_type.exception_value is None: env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) def calculate_result_code(self): return self.c_call_code() def c_call_code(self): func_type = self.function_type() if self.type is PyrexTypes.error_type or not func_type.is_cfunction: return "" formal_args = func_type.args arg_list_code = [] args = list(zip(formal_args, self.args)) max_nargs = len(func_type.args) expected_nargs = max_nargs - func_type.optional_arg_count actual_nargs = len(self.args) for formal_arg, actual_arg in args[:expected_nargs]: arg_code = actual_arg.result_as(formal_arg.type) arg_list_code.append(arg_code) if func_type.is_overridable: arg_list_code.append(str(int(self.wrapper_call or self.function.entry.is_unbound_cmethod))) if func_type.optional_arg_count: if expected_nargs == actual_nargs: optional_args = 'NULL' else: optional_args = "&%s" % self.opt_arg_struct arg_list_code.append(optional_args) for actual_arg in self.args[len(formal_args):]: arg_list_code.append(actual_arg.result()) result = "%s(%s)" % (self.function.result(), ', '.join(arg_list_code)) return result def generate_result_code(self, code): func_type = self.function_type() if self.function.is_name or self.function.is_attribute: if self.function.entry and self.function.entry.utility_code: code.globalstate.use_utility_code(self.function.entry.utility_code) if func_type.is_pyobject: arg_code = self.arg_tuple.py_result() code.globalstate.use_utility_code(UtilityCode.load_cached( "PyObjectCall", "ObjectHandling.c")) code.putln( "%s = __Pyx_PyObject_Call(%s, %s, NULL); %s" % ( self.result(), self.function.py_result(), arg_code, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) elif func_type.is_cfunction: if self.has_optional_args: actual_nargs = len(self.args) expected_nargs = len(func_type.args) - func_type.optional_arg_count self.opt_arg_struct = code.funcstate.allocate_temp( func_type.op_arg_struct.base_type, manage_ref=True) code.putln("%s.%s = %s;" % ( self.opt_arg_struct, Naming.pyrex_prefix + "n", len(self.args) - expected_nargs)) args = list(zip(func_type.args, self.args)) for formal_arg, actual_arg in args[expected_nargs:actual_nargs]: code.putln("%s.%s = %s;" % ( self.opt_arg_struct, func_type.opt_arg_cname(formal_arg.name), actual_arg.result_as(formal_arg.type))) exc_checks = [] if self.type.is_pyobject and self.is_temp: exc_checks.append("!%s" % self.result()) elif self.type.is_memoryviewslice: assert self.is_temp exc_checks.append(self.type.error_condition(self.result())) else: exc_val = func_type.exception_value exc_check = func_type.exception_check if exc_val is not None: exc_checks.append("%s == %s" % (self.result(), exc_val)) if exc_check: if self.nogil: exc_checks.append("__Pyx_ErrOccurredWithGIL()") else: exc_checks.append("PyErr_Occurred()") if self.is_temp or exc_checks: rhs = self.c_call_code() if self.result(): lhs = "%s = " % self.result() if self.is_temp and self.type.is_pyobject: #return_type = self.type # func_type.return_type #print "SimpleCallNode.generate_result_code: casting", rhs, \ # "from", return_type, "to pyobject" ### rhs = typecast(py_object_type, self.type, rhs) else: lhs = "" if func_type.exception_check == '+': if func_type.exception_value is None: raise_py_exception = "__Pyx_CppExn2PyErr();" elif func_type.exception_value.type.is_pyobject: raise_py_exception = 'try { throw; } catch(const std::exception& exn) { PyErr_SetString(%s, exn.what()); } catch(...) { PyErr_SetNone(%s); }' % ( func_type.exception_value.entry.cname, func_type.exception_value.entry.cname) else: raise_py_exception = '%s(); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError , "Error converting c++ exception.");' % func_type.exception_value.entry.cname code.putln("try {") code.putln("%s%s;" % (lhs, rhs)) code.putln("} catch(...) {") if self.nogil: code.put_ensure_gil(declare_gilstate=True) code.putln(raise_py_exception) if self.nogil: code.put_release_ensured_gil() code.putln(code.error_goto(self.pos)) code.putln("}") else: if exc_checks: goto_error = code.error_goto_if(" && ".join(exc_checks), self.pos) else: goto_error = "" code.putln("%s%s; %s" % (lhs, rhs, goto_error)) if self.type.is_pyobject and self.result(): code.put_gotref(self.py_result()) if self.has_optional_args: code.funcstate.release_temp(self.opt_arg_struct) class InlinedDefNodeCallNode(CallNode): # Inline call to defnode # # function PyCFunctionNode # function_name NameNode # args [ExprNode] subexprs = ['args', 'function_name'] is_temp = 1 type = py_object_type function = None function_name = None def can_be_inlined(self): func_type= self.function.def_node if func_type.star_arg or func_type.starstar_arg: return False if len(func_type.args) != len(self.args): return False return True def analyse_types(self, env): self.function_name = self.function_name.analyse_types(env) self.args = [ arg.analyse_types(env) for arg in self.args ] func_type = self.function.def_node actual_nargs = len(self.args) # Coerce arguments some_args_in_temps = False for i in xrange(actual_nargs): formal_type = func_type.args[i].type arg = self.args[i].coerce_to(formal_type, env) if arg.is_temp: if i > 0: # first argument in temp doesn't impact subsequent arguments some_args_in_temps = True elif arg.type.is_pyobject and not env.nogil: if arg.nonlocally_immutable(): # plain local variables are ok pass else: # we do not safely own the argument's reference, # but we must make sure it cannot be collected # before we return from the function, so we create # an owned temp reference to it if i > 0: # first argument doesn't matter some_args_in_temps = True arg = arg.coerce_to_temp(env) self.args[i] = arg if some_args_in_temps: # if some args are temps and others are not, they may get # constructed in the wrong order (temps first) => make # sure they are either all temps or all not temps (except # for the last argument, which is evaluated last in any # case) for i in xrange(actual_nargs-1): arg = self.args[i] if arg.nonlocally_immutable(): # locals, C functions, unassignable types are safe. pass elif arg.type.is_cpp_class: # Assignment has side effects, avoid. pass elif env.nogil and arg.type.is_pyobject: # can't copy a Python reference into a temp in nogil # env (this is safe: a construction would fail in # nogil anyway) pass else: #self.args[i] = arg.coerce_to_temp(env) # instead: issue a warning if i > 0: warning(arg.pos, "Argument evaluation order in C function call is undefined and may not be as expected", 0) break return self def generate_result_code(self, code): arg_code = [self.function_name.py_result()] func_type = self.function.def_node for arg, proto_arg in zip(self.args, func_type.args): if arg.type.is_pyobject: arg_code.append(arg.result_as(proto_arg.type)) else: arg_code.append(arg.result()) arg_code = ', '.join(arg_code) code.putln( "%s = %s(%s); %s" % ( self.result(), self.function.def_node.entry.pyfunc_cname, arg_code, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class PythonCapiFunctionNode(ExprNode): subexprs = [] def __init__(self, pos, py_name, cname, func_type, utility_code = None): ExprNode.__init__(self, pos, name=py_name, cname=cname, type=func_type, utility_code=utility_code) def analyse_types(self, env): return self def generate_result_code(self, code): if self.utility_code: code.globalstate.use_utility_code(self.utility_code) def calculate_result_code(self): return self.cname class PythonCapiCallNode(SimpleCallNode): # Python C-API Function call (only created in transforms) # By default, we assume that the call never returns None, as this # is true for most C-API functions in CPython. If this does not # apply to a call, set the following to True (or None to inherit # the default behaviour). may_return_none = False def __init__(self, pos, function_name, func_type, utility_code = None, py_name=None, **kwargs): self.type = func_type.return_type self.result_ctype = self.type self.function = PythonCapiFunctionNode( pos, py_name, function_name, func_type, utility_code = utility_code) # call this last so that we can override the constructed # attributes above with explicit keyword arguments if required SimpleCallNode.__init__(self, pos, **kwargs) class GeneralCallNode(CallNode): # General Python function call, including keyword, # * and ** arguments. # # function ExprNode # positional_args ExprNode Tuple of positional arguments # keyword_args ExprNode or None Dict of keyword arguments type = py_object_type subexprs = ['function', 'positional_args', 'keyword_args'] nogil_check = Node.gil_error def compile_time_value(self, denv): function = self.function.compile_time_value(denv) positional_args = self.positional_args.compile_time_value(denv) keyword_args = self.keyword_args.compile_time_value(denv) try: return function(*positional_args, **keyword_args) except Exception, e: self.compile_time_value_error(e) def explicit_args_kwds(self): if (self.keyword_args and not isinstance(self.keyword_args, DictNode) or not isinstance(self.positional_args, TupleNode)): raise CompileError(self.pos, 'Compile-time keyword arguments must be explicit.') return self.positional_args.args, self.keyword_args def analyse_types(self, env): if self.analyse_as_type_constructor(env): return self self.function = self.function.analyse_types(env) if not self.function.type.is_pyobject: if self.function.type.is_error: self.type = error_type return self if hasattr(self.function, 'entry'): node = self.map_to_simple_call_node() if node is not None and node is not self: return node.analyse_types(env) elif self.function.entry.as_variable: self.function = self.function.coerce_to_pyobject(env) elif node is self: error(self.pos, "Non-trivial keyword arguments and starred " "arguments not allowed in cdef functions.") else: # error was already reported pass else: self.function = self.function.coerce_to_pyobject(env) if self.keyword_args: self.keyword_args = self.keyword_args.analyse_types(env) self.positional_args = self.positional_args.analyse_types(env) self.positional_args = \ self.positional_args.coerce_to_pyobject(env) function = self.function if function.is_name and function.type_entry: # We are calling an extension type constructor. As long # as we do not support __new__(), the result type is clear self.type = function.type_entry.type self.result_ctype = py_object_type self.may_return_none = False else: self.type = py_object_type self.is_temp = 1 return self def map_to_simple_call_node(self): """ Tries to map keyword arguments to declared positional arguments. Returns self to try a Python call, None to report an error or a SimpleCallNode if the mapping succeeds. """ if not isinstance(self.positional_args, TupleNode): # has starred argument return self if not isinstance(self.keyword_args, DictNode): # keywords come from arbitrary expression => nothing to do here return self function = self.function entry = getattr(function, 'entry', None) if not entry: return self function_type = entry.type if function_type.is_ptr: function_type = function_type.base_type if not function_type.is_cfunction: return self pos_args = self.positional_args.args kwargs = self.keyword_args declared_args = function_type.args if entry.is_cmethod: declared_args = declared_args[1:] # skip 'self' if len(pos_args) > len(declared_args): error(self.pos, "function call got too many positional arguments, " "expected %d, got %s" % (len(declared_args), len(pos_args))) return None matched_args = set([ arg.name for arg in declared_args[:len(pos_args)] if arg.name ]) unmatched_args = declared_args[len(pos_args):] matched_kwargs_count = 0 args = list(pos_args) # check for duplicate keywords seen = set(matched_args) has_errors = False for arg in kwargs.key_value_pairs: name = arg.key.value if name in seen: error(arg.pos, "argument '%s' passed twice" % name) has_errors = True # continue to report more errors if there are any seen.add(name) # match keywords that are passed in order for decl_arg, arg in zip(unmatched_args, kwargs.key_value_pairs): name = arg.key.value if decl_arg.name == name: matched_args.add(name) matched_kwargs_count += 1 args.append(arg.value) else: break # match keyword arguments that are passed out-of-order, but keep # the evaluation of non-simple arguments in order by moving them # into temps from Cython.Compiler.UtilNodes import EvalWithTempExprNode, LetRefNode temps = [] if len(kwargs.key_value_pairs) > matched_kwargs_count: unmatched_args = declared_args[len(args):] keywords = dict([ (arg.key.value, (i+len(pos_args), arg)) for i, arg in enumerate(kwargs.key_value_pairs) ]) first_missing_keyword = None for decl_arg in unmatched_args: name = decl_arg.name if name not in keywords: # missing keyword argument => either done or error if not first_missing_keyword: first_missing_keyword = name continue elif first_missing_keyword: if entry.as_variable: # we might be able to convert the function to a Python # object, which then allows full calling semantics # with default values in gaps - currently, we only # support optional arguments at the end return self # wasn't the last keyword => gaps are not supported error(self.pos, "C function call is missing " "argument '%s'" % first_missing_keyword) return None pos, arg = keywords[name] matched_args.add(name) matched_kwargs_count += 1 if arg.value.is_simple(): args.append(arg.value) else: temp = LetRefNode(arg.value) assert temp.is_simple() args.append(temp) temps.append((pos, temp)) if temps: # may have to move preceding non-simple args into temps final_args = [] new_temps = [] first_temp_arg = temps[0][-1] for arg_value in args: if arg_value is first_temp_arg: break # done if arg_value.is_simple(): final_args.append(arg_value) else: temp = LetRefNode(arg_value) new_temps.append(temp) final_args.append(temp) if new_temps: args = final_args temps = new_temps + [ arg for i,arg in sorted(temps) ] # check for unexpected keywords for arg in kwargs.key_value_pairs: name = arg.key.value if name not in matched_args: has_errors = True error(arg.pos, "C function got unexpected keyword argument '%s'" % name) if has_errors: # error was reported already return None # all keywords mapped to positional arguments # if we are missing arguments, SimpleCallNode will figure it out node = SimpleCallNode(self.pos, function=function, args=args) for temp in temps[::-1]: node = EvalWithTempExprNode(temp, node) return node def generate_result_code(self, code): if self.type.is_error: return if self.keyword_args: kwargs = self.keyword_args.py_result() else: kwargs = 'NULL' code.globalstate.use_utility_code(UtilityCode.load_cached( "PyObjectCall", "ObjectHandling.c")) code.putln( "%s = __Pyx_PyObject_Call(%s, %s, %s); %s" % ( self.result(), self.function.py_result(), self.positional_args.py_result(), kwargs, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class AsTupleNode(ExprNode): # Convert argument to tuple. Used for normalising # the * argument of a function call. # # arg ExprNode subexprs = ['arg'] def calculate_constant_result(self): self.constant_result = tuple(self.arg.constant_result) def compile_time_value(self, denv): arg = self.arg.compile_time_value(denv) try: return tuple(arg) except Exception, e: self.compile_time_value_error(e) def analyse_types(self, env): self.arg = self.arg.analyse_types(env) self.arg = self.arg.coerce_to_pyobject(env) self.type = tuple_type self.is_temp = 1 return self def may_be_none(self): return False nogil_check = Node.gil_error gil_message = "Constructing Python tuple" def generate_result_code(self, code): code.putln( "%s = PySequence_Tuple(%s); %s" % ( self.result(), self.arg.py_result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class AttributeNode(ExprNode): # obj.attribute # # obj ExprNode # attribute string # needs_none_check boolean Used if obj is an extension type. # If set to True, it is known that the type is not None. # # Used internally: # # is_py_attr boolean Is a Python getattr operation # member string C name of struct member # is_called boolean Function call is being done on result # entry Entry Symbol table entry of attribute is_attribute = 1 subexprs = ['obj'] type = PyrexTypes.error_type entry = None is_called = 0 needs_none_check = True is_memslice_transpose = False is_special_lookup = False def as_cython_attribute(self): if (isinstance(self.obj, NameNode) and self.obj.is_cython_module and not self.attribute == u"parallel"): return self.attribute cy = self.obj.as_cython_attribute() if cy: return "%s.%s" % (cy, self.attribute) return None def coerce_to(self, dst_type, env): # If coercing to a generic pyobject and this is a cpdef function # we can create the corresponding attribute if dst_type is py_object_type: entry = self.entry if entry and entry.is_cfunction and entry.as_variable: # must be a cpdef function self.is_temp = 1 self.entry = entry.as_variable self.analyse_as_python_attribute(env) return self return ExprNode.coerce_to(self, dst_type, env) def calculate_constant_result(self): attr = self.attribute if attr.startswith("__") and attr.endswith("__"): return self.constant_result = getattr(self.obj.constant_result, attr) def compile_time_value(self, denv): attr = self.attribute if attr.startswith("__") and attr.endswith("__"): error(self.pos, "Invalid attribute name '%s' in compile-time expression" % attr) return None obj = self.obj.compile_time_value(denv) try: return getattr(obj, attr) except Exception, e: self.compile_time_value_error(e) def type_dependencies(self, env): return self.obj.type_dependencies(env) def infer_type(self, env): # FIXME: this is way too redundant with analyse_types() node = self.analyse_as_cimported_attribute_node(env, target=False) if node is not None: return node.entry.type node = self.analyse_as_unbound_cmethod_node(env) if node is not None: return node.entry.type obj_type = self.obj.infer_type(env) self.analyse_attribute(env, obj_type=obj_type) if obj_type.is_builtin_type and self.type.is_cfunction: # special case: C-API replacements for C methods of # builtin types cannot be inferred as C functions as # that would prevent their use as bound methods return py_object_type return self.type def analyse_target_declaration(self, env): pass def analyse_target_types(self, env): node = self.analyse_types(env, target = 1) if node.type.is_const: error(self.pos, "Assignment to const attribute '%s'" % self.attribute) if not node.is_lvalue(): error(self.pos, "Assignment to non-lvalue of type '%s'" % self.type) return node def analyse_types(self, env, target = 0): self.initialized_check = env.directives['initializedcheck'] node = self.analyse_as_cimported_attribute_node(env, target) if node is None and not target: node = self.analyse_as_unbound_cmethod_node(env) if node is None: node = self.analyse_as_ordinary_attribute_node(env, target) assert node is not None if node.entry: node.entry.used = True if node.is_attribute: node.wrap_obj_in_nonecheck(env) return node def analyse_as_cimported_attribute_node(self, env, target): # Try to interpret this as a reference to an imported # C const, type, var or function. If successful, mutates # this node into a NameNode and returns 1, otherwise # returns 0. module_scope = self.obj.analyse_as_module(env) if module_scope: entry = module_scope.lookup_here(self.attribute) if entry and ( entry.is_cglobal or entry.is_cfunction or entry.is_type or entry.is_const): return self.as_name_node(env, entry, target) return None def analyse_as_unbound_cmethod_node(self, env): # Try to interpret this as a reference to an unbound # C method of an extension type or builtin type. If successful, # creates a corresponding NameNode and returns it, otherwise # returns None. type = self.obj.analyse_as_extension_type(env) if type: entry = type.scope.lookup_here(self.attribute) if entry and entry.is_cmethod: if type.is_builtin_type: if not self.is_called: # must handle this as Python object return None ubcm_entry = entry else: # Create a temporary entry describing the C method # as an ordinary function. ubcm_entry = Symtab.Entry(entry.name, "%s->%s" % (type.vtabptr_cname, entry.cname), entry.type) ubcm_entry.is_cfunction = 1 ubcm_entry.func_cname = entry.func_cname ubcm_entry.is_unbound_cmethod = 1 return self.as_name_node(env, ubcm_entry, target=False) return None def analyse_as_type(self, env): module_scope = self.obj.analyse_as_module(env) if module_scope: return module_scope.lookup_type(self.attribute) if not self.obj.is_string_literal: base_type = self.obj.analyse_as_type(env) if base_type and hasattr(base_type, 'scope') and base_type.scope is not None: return base_type.scope.lookup_type(self.attribute) return None def analyse_as_extension_type(self, env): # Try to interpret this as a reference to an extension type # in a cimported module. Returns the extension type, or None. module_scope = self.obj.analyse_as_module(env) if module_scope: entry = module_scope.lookup_here(self.attribute) if entry and entry.is_type: if entry.type.is_extension_type or entry.type.is_builtin_type: return entry.type return None def analyse_as_module(self, env): # Try to interpret this as a reference to a cimported module # in another cimported module. Returns the module scope, or None. module_scope = self.obj.analyse_as_module(env) if module_scope: entry = module_scope.lookup_here(self.attribute) if entry and entry.as_module: return entry.as_module return None def as_name_node(self, env, entry, target): # Create a corresponding NameNode from this node and complete the # analyse_types phase. node = NameNode.from_node(self, name=self.attribute, entry=entry) if target: node = node.analyse_target_types(env) else: node = node.analyse_rvalue_entry(env) node.entry.used = 1 return node def analyse_as_ordinary_attribute_node(self, env, target): self.obj = self.obj.analyse_types(env) self.analyse_attribute(env) if self.entry and self.entry.is_cmethod and not self.is_called: # error(self.pos, "C method can only be called") pass ## Reference to C array turns into pointer to first element. #while self.type.is_array: # self.type = self.type.element_ptr_type() if self.is_py_attr: if not target: self.is_temp = 1 self.result_ctype = py_object_type elif target and self.obj.type.is_builtin_type: error(self.pos, "Assignment to an immutable object field") #elif self.type.is_memoryviewslice and not target: # self.is_temp = True return self def analyse_attribute(self, env, obj_type = None): # Look up attribute and set self.type and self.member. immutable_obj = obj_type is not None # used during type inference self.is_py_attr = 0 self.member = self.attribute if obj_type is None: if self.obj.type.is_string or self.obj.type.is_pyunicode_ptr: self.obj = self.obj.coerce_to_pyobject(env) obj_type = self.obj.type else: if obj_type.is_string or obj_type.is_pyunicode_ptr: obj_type = py_object_type if obj_type.is_ptr or obj_type.is_array: obj_type = obj_type.base_type self.op = "->" elif obj_type.is_extension_type or obj_type.is_builtin_type: self.op = "->" else: self.op = "." if obj_type.has_attributes: if obj_type.attributes_known(): if (obj_type.is_memoryviewslice and not obj_type.scope.lookup_here(self.attribute)): if self.attribute == 'T': self.is_memslice_transpose = True self.is_temp = True self.use_managed_ref = True self.type = self.obj.type return else: obj_type.declare_attribute(self.attribute, env, self.pos) entry = obj_type.scope.lookup_here(self.attribute) if entry and entry.is_member: entry = None else: error(self.pos, "Cannot select attribute of incomplete type '%s'" % obj_type) self.type = PyrexTypes.error_type return self.entry = entry if entry: if obj_type.is_extension_type and entry.name == "__weakref__": error(self.pos, "Illegal use of special attribute __weakref__") # def methods need the normal attribute lookup # because they do not have struct entries # fused function go through assignment synthesis # (foo = pycfunction(foo_func_obj)) and need to go through # regular Python lookup as well if (entry.is_variable and not entry.fused_cfunction) or entry.is_cmethod: self.type = entry.type self.member = entry.cname return else: # If it's not a variable or C method, it must be a Python # method of an extension type, so we treat it like a Python # attribute. pass # If we get here, the base object is not a struct/union/extension # type, or it is an extension type and the attribute is either not # declared or is declared as a Python method. Treat it as a Python # attribute reference. self.analyse_as_python_attribute(env, obj_type, immutable_obj) def analyse_as_python_attribute(self, env, obj_type=None, immutable_obj=False): if obj_type is None: obj_type = self.obj.type # mangle private '__*' Python attributes used inside of a class self.attribute = env.mangle_class_private_name(self.attribute) self.member = self.attribute self.type = py_object_type self.is_py_attr = 1 if not obj_type.is_pyobject and not obj_type.is_error: if obj_type.can_coerce_to_pyobject(env): if not immutable_obj: self.obj = self.obj.coerce_to_pyobject(env) elif (obj_type.is_cfunction and self.obj.is_name and self.obj.entry.as_variable and self.obj.entry.as_variable.type.is_pyobject): # might be an optimised builtin function => unpack it if not immutable_obj: self.obj = self.obj.coerce_to_pyobject(env) else: error(self.pos, "Object of type '%s' has no attribute '%s'" % (obj_type, self.attribute)) def wrap_obj_in_nonecheck(self, env): if not env.directives['nonecheck']: return msg = None format_args = () if (self.obj.type.is_extension_type and self.needs_none_check and not self.is_py_attr): msg = "'NoneType' object has no attribute '%s'" format_args = (self.attribute,) elif self.obj.type.is_memoryviewslice: if self.is_memslice_transpose: msg = "Cannot transpose None memoryview slice" else: entry = self.obj.type.scope.lookup_here(self.attribute) if entry: # copy/is_c_contig/shape/strides etc msg = "Cannot access '%s' attribute of None memoryview slice" format_args = (entry.name,) if msg: self.obj = self.obj.as_none_safe_node(msg, 'PyExc_AttributeError', format_args=format_args) def nogil_check(self, env): if self.is_py_attr: self.gil_error() elif self.type.is_memoryviewslice: import MemoryView MemoryView.err_if_nogil_initialized_check(self.pos, env, 'attribute') gil_message = "Accessing Python attribute" def is_simple(self): if self.obj: return self.result_in_temp() or self.obj.is_simple() else: return NameNode.is_simple(self) def is_lvalue(self): if self.obj: return not self.type.is_array else: return NameNode.is_lvalue(self) def is_ephemeral(self): if self.obj: return self.obj.is_ephemeral() else: return NameNode.is_ephemeral(self) def calculate_result_code(self): #print "AttributeNode.calculate_result_code:", self.member ### #print "...obj node =", self.obj, "code", self.obj.result() ### #print "...obj type", self.obj.type, "ctype", self.obj.ctype() ### obj = self.obj obj_code = obj.result_as(obj.type) #print "...obj_code =", obj_code ### if self.entry and self.entry.is_cmethod: if obj.type.is_extension_type and not self.entry.is_builtin_cmethod: if self.entry.final_func_cname: return self.entry.final_func_cname if self.type.from_fused: # If the attribute was specialized through indexing, make # sure to get the right fused name, as our entry was # replaced by our parent index node # (AnalyseExpressionsTransform) self.member = self.entry.cname return "((struct %s *)%s%s%s)->%s" % ( obj.type.vtabstruct_cname, obj_code, self.op, obj.type.vtabslot_cname, self.member) elif self.result_is_used: return self.member # Generating no code at all for unused access to optimised builtin # methods fixes the problem that some optimisations only exist as # macros, i.e. there is no function pointer to them, so we would # generate invalid C code here. return elif obj.type.is_complex: return "__Pyx_C%s(%s)" % (self.member.upper(), obj_code) else: if obj.type.is_builtin_type and self.entry and self.entry.is_variable: # accessing a field of a builtin type, need to cast better than result_as() does obj_code = obj.type.cast_code(obj.result(), to_object_struct = True) return "%s%s%s" % (obj_code, self.op, self.member) def generate_result_code(self, code): if self.is_py_attr: if self.is_special_lookup: code.globalstate.use_utility_code( UtilityCode.load_cached("PyObjectLookupSpecial", "ObjectHandling.c")) lookup_func_name = '__Pyx_PyObject_LookupSpecial' else: code.globalstate.use_utility_code( UtilityCode.load_cached("PyObjectGetAttrStr", "ObjectHandling.c")) lookup_func_name = '__Pyx_PyObject_GetAttrStr' code.putln( '%s = %s(%s, %s); %s' % ( self.result(), lookup_func_name, self.obj.py_result(), code.intern_identifier(self.attribute), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) elif self.type.is_memoryviewslice: if self.is_memslice_transpose: # transpose the slice for access, packing in self.type.axes: if access == 'ptr': error(self.pos, "Transposing not supported for slices " "with indirect dimensions") return code.putln("%s = %s;" % (self.result(), self.obj.result())) if self.obj.is_name or (self.obj.is_attribute and self.obj.is_memslice_transpose): code.put_incref_memoryviewslice(self.result(), have_gil=True) T = "__pyx_memslice_transpose(&%s) == 0" code.putln(code.error_goto_if(T % self.result(), self.pos)) elif self.initialized_check: code.putln( 'if (unlikely(!%s.memview)) {' 'PyErr_SetString(PyExc_AttributeError,' '"Memoryview is not initialized");' '%s' '}' % (self.result(), code.error_goto(self.pos))) else: # result_code contains what is needed, but we may need to insert # a check and raise an exception if self.obj.type.is_extension_type: pass elif self.entry and self.entry.is_cmethod and self.entry.utility_code: # C method implemented as function call with utility code code.globalstate.use_utility_code(self.entry.utility_code) def generate_disposal_code(self, code): if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose: # mirror condition for putting the memview incref here: if self.obj.is_name or (self.obj.is_attribute and self.obj.is_memslice_transpose): code.put_xdecref_memoryviewslice( self.result(), have_gil=True) else: ExprNode.generate_disposal_code(self, code) def generate_assignment_code(self, rhs, code): self.obj.generate_evaluation_code(code) if self.is_py_attr: code.globalstate.use_utility_code( UtilityCode.load_cached("PyObjectSetAttrStr", "ObjectHandling.c")) code.put_error_if_neg(self.pos, '__Pyx_PyObject_SetAttrStr(%s, %s, %s)' % ( self.obj.py_result(), code.intern_identifier(self.attribute), rhs.py_result())) rhs.generate_disposal_code(code) rhs.free_temps(code) elif self.obj.type.is_complex: code.putln("__Pyx_SET_C%s(%s, %s);" % ( self.member.upper(), self.obj.result_as(self.obj.type), rhs.result_as(self.ctype()))) else: select_code = self.result() if self.type.is_pyobject and self.use_managed_ref: rhs.make_owned_reference(code) code.put_giveref(rhs.py_result()) code.put_gotref(select_code) code.put_decref(select_code, self.ctype()) elif self.type.is_memoryviewslice: import MemoryView MemoryView.put_assign_to_memviewslice( select_code, rhs, rhs.result(), self.type, code) if not self.type.is_memoryviewslice: code.putln( "%s = %s;" % ( select_code, rhs.result_as(self.ctype()))) #rhs.result())) rhs.generate_post_assignment_code(code) rhs.free_temps(code) self.obj.generate_disposal_code(code) self.obj.free_temps(code) def generate_deletion_code(self, code, ignore_nonexisting=False): self.obj.generate_evaluation_code(code) if self.is_py_attr or (self.entry.scope.is_property_scope and u'__del__' in self.entry.scope.entries): code.globalstate.use_utility_code( UtilityCode.load_cached("PyObjectSetAttrStr", "ObjectHandling.c")) code.put_error_if_neg(self.pos, '__Pyx_PyObject_DelAttrStr(%s, %s)' % ( self.obj.py_result(), code.intern_identifier(self.attribute))) else: error(self.pos, "Cannot delete C attribute of extension type") self.obj.generate_disposal_code(code) self.obj.free_temps(code) def annotate(self, code): if self.is_py_attr: style, text = 'py_attr', 'python attribute (%s)' else: style, text = 'c_attr', 'c attribute (%s)' code.annotate(self.pos, AnnotationItem(style, text % self.type, size=len(self.attribute))) #------------------------------------------------------------------- # # Constructor nodes # #------------------------------------------------------------------- class StarredTargetNode(ExprNode): # A starred expression like "*a" # # This is only allowed in sequence assignment targets such as # # a, *b = (1,2,3,4) => a = 1 ; b = [2,3,4] # # and will be removed during type analysis (or generate an error # if it's found at unexpected places). # # target ExprNode subexprs = ['target'] is_starred = 1 type = py_object_type is_temp = 1 def __init__(self, pos, target): ExprNode.__init__(self, pos) self.target = target def analyse_declarations(self, env): error(self.pos, "can use starred expression only as assignment target") self.target.analyse_declarations(env) def analyse_types(self, env): error(self.pos, "can use starred expression only as assignment target") self.target = self.target.analyse_types(env) self.type = self.target.type return self def analyse_target_declaration(self, env): self.target.analyse_target_declaration(env) def analyse_target_types(self, env): self.target = self.target.analyse_target_types(env) self.type = self.target.type return self def calculate_result_code(self): return "" def generate_result_code(self, code): pass class SequenceNode(ExprNode): # Base class for list and tuple constructor nodes. # Contains common code for performing sequence unpacking. # # args [ExprNode] # unpacked_items [ExprNode] or None # coerced_unpacked_items [ExprNode] or None # mult_factor ExprNode the integer number of content repetitions ([1,2]*3) subexprs = ['args', 'mult_factor'] is_sequence_constructor = 1 unpacked_items = None mult_factor = None slow = False # trade speed for code size (e.g. use PyTuple_Pack()) def compile_time_value_list(self, denv): return [arg.compile_time_value(denv) for arg in self.args] def replace_starred_target_node(self): # replace a starred node in the targets by the contained expression self.starred_assignment = False args = [] for arg in self.args: if arg.is_starred: if self.starred_assignment: error(arg.pos, "more than 1 starred expression in assignment") self.starred_assignment = True arg = arg.target arg.is_starred = True args.append(arg) self.args = args def analyse_target_declaration(self, env): self.replace_starred_target_node() for arg in self.args: arg.analyse_target_declaration(env) def analyse_types(self, env, skip_children=False): for i in range(len(self.args)): arg = self.args[i] if not skip_children: arg = arg.analyse_types(env) self.args[i] = arg.coerce_to_pyobject(env) if self.mult_factor: self.mult_factor = self.mult_factor.analyse_types(env) if not self.mult_factor.type.is_int: self.mult_factor = self.mult_factor.coerce_to_pyobject(env) self.is_temp = 1 # not setting self.type here, subtypes do this return self def may_be_none(self): return False def analyse_target_types(self, env): if self.mult_factor: error(self.pos, "can't assign to multiplied sequence") self.unpacked_items = [] self.coerced_unpacked_items = [] self.any_coerced_items = False for i, arg in enumerate(self.args): arg = self.args[i] = arg.analyse_target_types(env) if arg.is_starred: if not arg.type.assignable_from(Builtin.list_type): error(arg.pos, "starred target must have Python object (list) type") if arg.type is py_object_type: arg.type = Builtin.list_type unpacked_item = PyTempNode(self.pos, env) coerced_unpacked_item = unpacked_item.coerce_to(arg.type, env) if unpacked_item is not coerced_unpacked_item: self.any_coerced_items = True self.unpacked_items.append(unpacked_item) self.coerced_unpacked_items.append(coerced_unpacked_item) self.type = py_object_type return self def generate_result_code(self, code): self.generate_operation_code(code) def generate_sequence_packing_code(self, code, target=None, plain=False): if target is None: target = self.result() size_factor = c_mult = '' mult_factor = None if self.mult_factor and not plain: mult_factor = self.mult_factor if mult_factor.type.is_int: c_mult = mult_factor.result() if isinstance(mult_factor.constant_result, (int,long)) \ and mult_factor.constant_result > 0: size_factor = ' * %s' % mult_factor.constant_result else: size_factor = ' * ((%s<0) ? 0:%s)' % (c_mult, c_mult) if self.type is Builtin.tuple_type and (self.is_literal or self.slow) and not c_mult: # use PyTuple_Pack() to avoid generating huge amounts of one-time code code.putln('%s = PyTuple_Pack(%d, %s); %s' % ( target, len(self.args), ', '.join([ arg.py_result() for arg in self.args ]), code.error_goto_if_null(target, self.pos))) code.put_gotref(target) else: # build the tuple/list step by step, potentially multiplying it as we go if self.type is Builtin.list_type: create_func, set_item_func = 'PyList_New', 'PyList_SET_ITEM' elif self.type is Builtin.tuple_type: create_func, set_item_func = 'PyTuple_New', 'PyTuple_SET_ITEM' else: raise InternalError("sequence packing for unexpected type %s" % self.type) arg_count = len(self.args) code.putln("%s = %s(%s%s); %s" % ( target, create_func, arg_count, size_factor, code.error_goto_if_null(target, self.pos))) code.put_gotref(target) if c_mult: # FIXME: can't use a temp variable here as the code may # end up in the constant building function. Temps # currently don't work there. #counter = code.funcstate.allocate_temp(mult_factor.type, manage_ref=False) counter = Naming.quick_temp_cname code.putln('{ Py_ssize_t %s;' % counter) if arg_count == 1: offset = counter else: offset = '%s * %s' % (counter, arg_count) code.putln('for (%s=0; %s < %s; %s++) {' % ( counter, counter, c_mult, counter )) else: offset = '' for i in xrange(arg_count): arg = self.args[i] if c_mult or not arg.result_in_temp(): code.put_incref(arg.result(), arg.ctype()) code.putln("%s(%s, %s, %s);" % ( set_item_func, target, (offset and i) and ('%s + %s' % (offset, i)) or (offset or i), arg.py_result())) code.put_giveref(arg.py_result()) if c_mult: code.putln('}') #code.funcstate.release_temp(counter) code.putln('}') if mult_factor is not None and mult_factor.type.is_pyobject: code.putln('{ PyObject* %s = PyNumber_InPlaceMultiply(%s, %s); %s' % ( Naming.quick_temp_cname, target, mult_factor.py_result(), code.error_goto_if_null(Naming.quick_temp_cname, self.pos) )) code.put_gotref(Naming.quick_temp_cname) code.put_decref(target, py_object_type) code.putln('%s = %s;' % (target, Naming.quick_temp_cname)) code.putln('}') def generate_subexpr_disposal_code(self, code): if self.mult_factor and self.mult_factor.type.is_int: super(SequenceNode, self).generate_subexpr_disposal_code(code) elif self.type is Builtin.tuple_type and (self.is_literal or self.slow): super(SequenceNode, self).generate_subexpr_disposal_code(code) else: # We call generate_post_assignment_code here instead # of generate_disposal_code, because values were stored # in the tuple using a reference-stealing operation. for arg in self.args: arg.generate_post_assignment_code(code) # Should NOT call free_temps -- this is invoked by the default # generate_evaluation_code which will do that. if self.mult_factor: self.mult_factor.generate_disposal_code(code) def generate_assignment_code(self, rhs, code): if self.starred_assignment: self.generate_starred_assignment_code(rhs, code) else: self.generate_parallel_assignment_code(rhs, code) for item in self.unpacked_items: item.release(code) rhs.free_temps(code) _func_iternext_type = PyrexTypes.CPtrType(PyrexTypes.CFuncType( PyrexTypes.py_object_type, [ PyrexTypes.CFuncTypeArg("it", PyrexTypes.py_object_type, None), ])) def generate_parallel_assignment_code(self, rhs, code): # Need to work around the fact that generate_evaluation_code # allocates the temps in a rather hacky way -- the assignment # is evaluated twice, within each if-block. for item in self.unpacked_items: item.allocate(code) special_unpack = (rhs.type is py_object_type or rhs.type in (tuple_type, list_type) or not rhs.type.is_builtin_type) long_enough_for_a_loop = len(self.unpacked_items) > 3 if special_unpack: self.generate_special_parallel_unpacking_code( code, rhs, use_loop=long_enough_for_a_loop) else: code.putln("{") self.generate_generic_parallel_unpacking_code( code, rhs, self.unpacked_items, use_loop=long_enough_for_a_loop) code.putln("}") for value_node in self.coerced_unpacked_items: value_node.generate_evaluation_code(code) for i in range(len(self.args)): self.args[i].generate_assignment_code( self.coerced_unpacked_items[i], code) def generate_special_parallel_unpacking_code(self, code, rhs, use_loop): sequence_type_test = '1' none_check = "likely(%s != Py_None)" % rhs.py_result() if rhs.type is list_type: sequence_types = ['List'] if rhs.may_be_none(): sequence_type_test = none_check elif rhs.type is tuple_type: sequence_types = ['Tuple'] if rhs.may_be_none(): sequence_type_test = none_check else: sequence_types = ['Tuple', 'List'] tuple_check = 'likely(PyTuple_CheckExact(%s))' % rhs.py_result() list_check = 'PyList_CheckExact(%s)' % rhs.py_result() sequence_type_test = "(%s) || (%s)" % (tuple_check, list_check) code.putln("if (%s) {" % sequence_type_test) code.putln("PyObject* sequence = %s;" % rhs.py_result()) # list/tuple => check size code.putln("#if CYTHON_COMPILING_IN_CPYTHON") code.putln("Py_ssize_t size = Py_SIZE(sequence);") code.putln("#else") code.putln("Py_ssize_t size = PySequence_Size(sequence);") # < 0 => exception code.putln("#endif") code.putln("if (unlikely(size != %d)) {" % len(self.args)) code.globalstate.use_utility_code(raise_too_many_values_to_unpack) code.putln("if (size > %d) __Pyx_RaiseTooManyValuesError(%d);" % ( len(self.args), len(self.args))) code.globalstate.use_utility_code(raise_need_more_values_to_unpack) code.putln("else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);") code.putln(code.error_goto(self.pos)) code.putln("}") code.putln("#if CYTHON_COMPILING_IN_CPYTHON") # unpack items from list/tuple in unrolled loop (can't fail) if len(sequence_types) == 2: code.putln("if (likely(Py%s_CheckExact(sequence))) {" % sequence_types[0]) for i, item in enumerate(self.unpacked_items): code.putln("%s = Py%s_GET_ITEM(sequence, %d); " % ( item.result(), sequence_types[0], i)) if len(sequence_types) == 2: code.putln("} else {") for i, item in enumerate(self.unpacked_items): code.putln("%s = Py%s_GET_ITEM(sequence, %d); " % ( item.result(), sequence_types[1], i)) code.putln("}") for item in self.unpacked_items: code.put_incref(item.result(), item.ctype()) code.putln("#else") # in non-CPython, use the PySequence protocol (which can fail) if not use_loop: for i, item in enumerate(self.unpacked_items): code.putln("%s = PySequence_ITEM(sequence, %d); %s" % ( item.result(), i, code.error_goto_if_null(item.result(), self.pos))) code.put_gotref(item.result()) else: code.putln("{") code.putln("Py_ssize_t i;") code.putln("PyObject** temps[%s] = {%s};" % ( len(self.unpacked_items), ','.join(['&%s' % item.result() for item in self.unpacked_items]))) code.putln("for (i=0; i < %s; i++) {" % len(self.unpacked_items)) code.putln("PyObject* item = PySequence_ITEM(sequence, i); %s" % ( code.error_goto_if_null('item', self.pos))) code.put_gotref('item') code.putln("*(temps[i]) = item;") code.putln("}") code.putln("}") code.putln("#endif") rhs.generate_disposal_code(code) if sequence_type_test == '1': code.putln("}") # all done elif sequence_type_test == none_check: # either tuple/list or None => save some code by generating the error directly code.putln("} else {") code.globalstate.use_utility_code( UtilityCode.load_cached("RaiseNoneIterError", "ObjectHandling.c")) code.putln("__Pyx_RaiseNoneNotIterableError(); %s" % code.error_goto(self.pos)) code.putln("}") # all done else: code.putln("} else {") # needs iteration fallback code self.generate_generic_parallel_unpacking_code( code, rhs, self.unpacked_items, use_loop=use_loop) code.putln("}") def generate_generic_parallel_unpacking_code(self, code, rhs, unpacked_items, use_loop, terminate=True): code.globalstate.use_utility_code(raise_need_more_values_to_unpack) code.globalstate.use_utility_code(UtilityCode.load_cached("IterFinish", "ObjectHandling.c")) code.putln("Py_ssize_t index = -1;") # must be at the start of a C block! if use_loop: code.putln("PyObject** temps[%s] = {%s};" % ( len(self.unpacked_items), ','.join(['&%s' % item.result() for item in unpacked_items]))) iterator_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) code.putln( "%s = PyObject_GetIter(%s); %s" % ( iterator_temp, rhs.py_result(), code.error_goto_if_null(iterator_temp, self.pos))) code.put_gotref(iterator_temp) rhs.generate_disposal_code(code) iternext_func = code.funcstate.allocate_temp(self._func_iternext_type, manage_ref=False) code.putln("%s = Py_TYPE(%s)->tp_iternext;" % ( iternext_func, iterator_temp)) unpacking_error_label = code.new_label('unpacking_failed') unpack_code = "%s(%s)" % (iternext_func, iterator_temp) if use_loop: code.putln("for (index=0; index < %s; index++) {" % len(unpacked_items)) code.put("PyObject* item = %s; if (unlikely(!item)) " % unpack_code) code.put_goto(unpacking_error_label) code.put_gotref("item") code.putln("*(temps[index]) = item;") code.putln("}") else: for i, item in enumerate(unpacked_items): code.put( "index = %d; %s = %s; if (unlikely(!%s)) " % ( i, item.result(), unpack_code, item.result())) code.put_goto(unpacking_error_label) code.put_gotref(item.py_result()) if terminate: code.globalstate.use_utility_code( UtilityCode.load_cached("UnpackItemEndCheck", "ObjectHandling.c")) code.put_error_if_neg(self.pos, "__Pyx_IternextUnpackEndCheck(%s, %d)" % ( unpack_code, len(unpacked_items))) code.putln("%s = NULL;" % iternext_func) code.put_decref_clear(iterator_temp, py_object_type) unpacking_done_label = code.new_label('unpacking_done') code.put_goto(unpacking_done_label) code.put_label(unpacking_error_label) code.put_decref_clear(iterator_temp, py_object_type) code.putln("%s = NULL;" % iternext_func) code.putln("if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);") code.putln(code.error_goto(self.pos)) code.put_label(unpacking_done_label) code.funcstate.release_temp(iternext_func) if terminate: code.funcstate.release_temp(iterator_temp) iterator_temp = None return iterator_temp def generate_starred_assignment_code(self, rhs, code): for i, arg in enumerate(self.args): if arg.is_starred: starred_target = self.unpacked_items[i] unpacked_fixed_items_left = self.unpacked_items[:i] unpacked_fixed_items_right = self.unpacked_items[i+1:] break else: assert False iterator_temp = None if unpacked_fixed_items_left: for item in unpacked_fixed_items_left: item.allocate(code) code.putln('{') iterator_temp = self.generate_generic_parallel_unpacking_code( code, rhs, unpacked_fixed_items_left, use_loop=True, terminate=False) for i, item in enumerate(unpacked_fixed_items_left): value_node = self.coerced_unpacked_items[i] value_node.generate_evaluation_code(code) code.putln('}') starred_target.allocate(code) target_list = starred_target.result() code.putln("%s = PySequence_List(%s); %s" % ( target_list, iterator_temp or rhs.py_result(), code.error_goto_if_null(target_list, self.pos))) code.put_gotref(target_list) if iterator_temp: code.put_decref_clear(iterator_temp, py_object_type) code.funcstate.release_temp(iterator_temp) else: rhs.generate_disposal_code(code) if unpacked_fixed_items_right: code.globalstate.use_utility_code(raise_need_more_values_to_unpack) length_temp = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False) code.putln('%s = PyList_GET_SIZE(%s);' % (length_temp, target_list)) code.putln("if (unlikely(%s < %d)) {" % (length_temp, len(unpacked_fixed_items_right))) code.putln("__Pyx_RaiseNeedMoreValuesError(%d+%s); %s" % ( len(unpacked_fixed_items_left), length_temp, code.error_goto(self.pos))) code.putln('}') for item in unpacked_fixed_items_right[::-1]: item.allocate(code) for i, (item, coerced_arg) in enumerate(zip(unpacked_fixed_items_right[::-1], self.coerced_unpacked_items[::-1])): code.putln('#if CYTHON_COMPILING_IN_CPYTHON') code.putln("%s = PyList_GET_ITEM(%s, %s-%d); " % ( item.py_result(), target_list, length_temp, i+1)) # resize the list the hard way code.putln("((PyVarObject*)%s)->ob_size--;" % target_list) code.putln('#else') code.putln("%s = PySequence_ITEM(%s, %s-%d); " % ( item.py_result(), target_list, length_temp, i+1)) code.putln('#endif') code.put_gotref(item.py_result()) coerced_arg.generate_evaluation_code(code) code.putln('#if !CYTHON_COMPILING_IN_CPYTHON') sublist_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) code.putln('%s = PySequence_GetSlice(%s, 0, %s-%d); %s' % ( sublist_temp, target_list, length_temp, len(unpacked_fixed_items_right), code.error_goto_if_null(sublist_temp, self.pos))) code.put_gotref(sublist_temp) code.funcstate.release_temp(length_temp) code.put_decref(target_list, py_object_type) code.putln('%s = %s; %s = NULL;' % (target_list, sublist_temp, sublist_temp)) code.putln('#else') code.putln('%s = %s;' % (sublist_temp, sublist_temp)) # avoid warning about unused variable code.funcstate.release_temp(sublist_temp) code.putln('#endif') for i, arg in enumerate(self.args): arg.generate_assignment_code(self.coerced_unpacked_items[i], code) def annotate(self, code): for arg in self.args: arg.annotate(code) if self.unpacked_items: for arg in self.unpacked_items: arg.annotate(code) for arg in self.coerced_unpacked_items: arg.annotate(code) class TupleNode(SequenceNode): # Tuple constructor. type = tuple_type is_partly_literal = False gil_message = "Constructing Python tuple" def analyse_types(self, env, skip_children=False): if len(self.args) == 0: node = self node.is_temp = False node.is_literal = True else: node = SequenceNode.analyse_types(self, env, skip_children) for child in node.args: if not child.is_literal: break else: if not node.mult_factor or node.mult_factor.is_literal and \ isinstance(node.mult_factor.constant_result, (int, long)): node.is_temp = False node.is_literal = True else: if not node.mult_factor.type.is_pyobject: node.mult_factor = node.mult_factor.coerce_to_pyobject(env) node.is_temp = True node.is_partly_literal = True return node def is_simple(self): # either temp or constant => always simple return True def nonlocally_immutable(self): # either temp or constant => always safe return True def calculate_result_code(self): if len(self.args) > 0: return self.result_code else: return Naming.empty_tuple def calculate_constant_result(self): self.constant_result = tuple([ arg.constant_result for arg in self.args]) def compile_time_value(self, denv): values = self.compile_time_value_list(denv) try: return tuple(values) except Exception, e: self.compile_time_value_error(e) def generate_operation_code(self, code): if len(self.args) == 0: # result_code is Naming.empty_tuple return if self.is_partly_literal: # underlying tuple is const, but factor is not tuple_target = code.get_py_const(py_object_type, 'tuple', cleanup_level=2) const_code = code.get_cached_constants_writer() const_code.mark_pos(self.pos) self.generate_sequence_packing_code(const_code, tuple_target, plain=True) const_code.put_giveref(tuple_target) code.putln('%s = PyNumber_Multiply(%s, %s); %s' % ( self.result(), tuple_target, self.mult_factor.py_result(), code.error_goto_if_null(self.result(), self.pos) )) code.put_gotref(self.py_result()) elif self.is_literal: # non-empty cached tuple => result is global constant, # creation code goes into separate code writer self.result_code = code.get_py_const(py_object_type, 'tuple', cleanup_level=2) code = code.get_cached_constants_writer() code.mark_pos(self.pos) self.generate_sequence_packing_code(code) code.put_giveref(self.py_result()) else: self.generate_sequence_packing_code(code) class ListNode(SequenceNode): # List constructor. # obj_conversion_errors [PyrexError] used internally # orignial_args [ExprNode] used internally obj_conversion_errors = [] type = list_type in_module_scope = False gil_message = "Constructing Python list" def type_dependencies(self, env): return () def infer_type(self, env): # TOOD: Infer non-object list arrays. return list_type def analyse_expressions(self, env): node = SequenceNode.analyse_expressions(self, env) return node.coerce_to_pyobject(env) def analyse_types(self, env): hold_errors() self.original_args = list(self.args) node = SequenceNode.analyse_types(self, env) node.obj_conversion_errors = held_errors() release_errors(ignore=True) if env.is_module_scope: self.in_module_scope = True return node def coerce_to(self, dst_type, env): if dst_type.is_pyobject: for err in self.obj_conversion_errors: report_error(err) self.obj_conversion_errors = [] if not self.type.subtype_of(dst_type): error(self.pos, "Cannot coerce list to type '%s'" % dst_type) elif self.mult_factor: error(self.pos, "Cannot coerce multiplied list to '%s'" % dst_type) elif dst_type.is_ptr and dst_type.base_type is not PyrexTypes.c_void_type: base_type = dst_type.base_type self.type = PyrexTypes.CArrayType(base_type, len(self.args)) for i in range(len(self.original_args)): arg = self.args[i] if isinstance(arg, CoerceToPyTypeNode): arg = arg.arg self.args[i] = arg.coerce_to(base_type, env) elif dst_type.is_struct: if len(self.args) > len(dst_type.scope.var_entries): error(self.pos, "Too may members for '%s'" % dst_type) else: if len(self.args) < len(dst_type.scope.var_entries): warning(self.pos, "Too few members for '%s'" % dst_type, 1) for i, (arg, member) in enumerate(zip(self.original_args, dst_type.scope.var_entries)): if isinstance(arg, CoerceToPyTypeNode): arg = arg.arg self.args[i] = arg.coerce_to(member.type, env) self.type = dst_type else: self.type = error_type error(self.pos, "Cannot coerce list to type '%s'" % dst_type) return self def as_tuple(self): t = TupleNode(self.pos, args=self.args, mult_factor=self.mult_factor) if isinstance(self.constant_result, list): t.constant_result = tuple(self.constant_result) return t def allocate_temp_result(self, code): if self.type.is_array and self.in_module_scope: self.temp_code = code.funcstate.allocate_temp( self.type, manage_ref=False, static=True) else: SequenceNode.allocate_temp_result(self, code) def release_temp_result(self, env): if self.type.is_array: # To be valid C++, we must allocate the memory on the stack # manually and be sure not to reuse it for something else. pass else: SequenceNode.release_temp_result(self, env) def calculate_constant_result(self): if self.mult_factor: raise ValueError() # may exceed the compile time memory self.constant_result = [ arg.constant_result for arg in self.args] def compile_time_value(self, denv): l = self.compile_time_value_list(denv) if self.mult_factor: l *= self.mult_factor.compile_time_value(denv) return l def generate_operation_code(self, code): if self.type.is_pyobject: for err in self.obj_conversion_errors: report_error(err) self.generate_sequence_packing_code(code) elif self.type.is_array: for i, arg in enumerate(self.args): code.putln("%s[%s] = %s;" % ( self.result(), i, arg.result())) elif self.type.is_struct: for arg, member in zip(self.args, self.type.scope.var_entries): code.putln("%s.%s = %s;" % ( self.result(), member.cname, arg.result())) else: raise InternalError("List type never specified") class ScopedExprNode(ExprNode): # Abstract base class for ExprNodes that have their own local # scope, such as generator expressions. # # expr_scope Scope the inner scope of the expression subexprs = [] expr_scope = None # does this node really have a local scope, e.g. does it leak loop # variables or not? non-leaking Py3 behaviour is default, except # for list comprehensions where the behaviour differs in Py2 and # Py3 (set in Parsing.py based on parser context) has_local_scope = True def init_scope(self, outer_scope, expr_scope=None): if expr_scope is not None: self.expr_scope = expr_scope elif self.has_local_scope: self.expr_scope = Symtab.GeneratorExpressionScope(outer_scope) else: self.expr_scope = None def analyse_declarations(self, env): self.init_scope(env) def analyse_scoped_declarations(self, env): # this is called with the expr_scope as env pass def analyse_types(self, env): # no recursion here, the children will be analysed separately below return self def analyse_scoped_expressions(self, env): # this is called with the expr_scope as env return self def generate_evaluation_code(self, code): # set up local variables and free their references on exit generate_inner_evaluation_code = super(ScopedExprNode, self).generate_evaluation_code if not self.has_local_scope or not self.expr_scope.var_entries: # no local variables => delegate, done generate_inner_evaluation_code(code) return code.putln('{ /* enter inner scope */') py_entries = [] for entry in self.expr_scope.var_entries: if not entry.in_closure: code.put_var_declaration(entry) if entry.type.is_pyobject and entry.used: py_entries.append(entry) if not py_entries: # no local Python references => no cleanup required generate_inner_evaluation_code(code) code.putln('} /* exit inner scope */') return # must free all local Python references at each exit point old_loop_labels = tuple(code.new_loop_labels()) old_error_label = code.new_error_label() generate_inner_evaluation_code(code) # normal (non-error) exit for entry in py_entries: code.put_var_decref(entry) # error/loop body exit points exit_scope = code.new_label('exit_scope') code.put_goto(exit_scope) for label, old_label in ([(code.error_label, old_error_label)] + list(zip(code.get_loop_labels(), old_loop_labels))): if code.label_used(label): code.put_label(label) for entry in py_entries: code.put_var_decref(entry) code.put_goto(old_label) code.put_label(exit_scope) code.putln('} /* exit inner scope */') code.set_loop_labels(old_loop_labels) code.error_label = old_error_label class ComprehensionNode(ScopedExprNode): # A list/set/dict comprehension child_attrs = ["loop"] is_temp = True def infer_type(self, env): return self.type def analyse_declarations(self, env): self.append.target = self # this is used in the PyList_Append of the inner loop self.init_scope(env) def analyse_scoped_declarations(self, env): self.loop.analyse_declarations(env) def analyse_types(self, env): if not self.has_local_scope: self.loop = self.loop.analyse_expressions(env) return self def analyse_scoped_expressions(self, env): if self.has_local_scope: self.loop = self.loop.analyse_expressions(env) return self def may_be_none(self): return False def generate_result_code(self, code): self.generate_operation_code(code) def generate_operation_code(self, code): if self.type is Builtin.list_type: create_code = 'PyList_New(0)' elif self.type is Builtin.set_type: create_code = 'PySet_New(NULL)' elif self.type is Builtin.dict_type: create_code = 'PyDict_New()' else: raise InternalError("illegal type for comprehension: %s" % self.type) code.putln('%s = %s; %s' % ( self.result(), create_code, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.result()) self.loop.generate_execution_code(code) def annotate(self, code): self.loop.annotate(code) class ComprehensionAppendNode(Node): # Need to be careful to avoid infinite recursion: # target must not be in child_attrs/subexprs child_attrs = ['expr'] target = None type = PyrexTypes.c_int_type def analyse_expressions(self, env): self.expr = self.expr.analyse_expressions(env) if not self.expr.type.is_pyobject: self.expr = self.expr.coerce_to_pyobject(env) return self def generate_execution_code(self, code): if self.target.type is list_type: code.globalstate.use_utility_code( UtilityCode.load_cached("ListCompAppend", "Optimize.c")) function = "__Pyx_ListComp_Append" elif self.target.type is set_type: function = "PySet_Add" else: raise InternalError( "Invalid type for comprehension node: %s" % self.target.type) self.expr.generate_evaluation_code(code) code.putln(code.error_goto_if("%s(%s, (PyObject*)%s)" % ( function, self.target.result(), self.expr.result() ), self.pos)) self.expr.generate_disposal_code(code) self.expr.free_temps(code) def generate_function_definitions(self, env, code): self.expr.generate_function_definitions(env, code) def annotate(self, code): self.expr.annotate(code) class DictComprehensionAppendNode(ComprehensionAppendNode): child_attrs = ['key_expr', 'value_expr'] def analyse_expressions(self, env): self.key_expr = self.key_expr.analyse_expressions(env) if not self.key_expr.type.is_pyobject: self.key_expr = self.key_expr.coerce_to_pyobject(env) self.value_expr = self.value_expr.analyse_expressions(env) if not self.value_expr.type.is_pyobject: self.value_expr = self.value_expr.coerce_to_pyobject(env) return self def generate_execution_code(self, code): self.key_expr.generate_evaluation_code(code) self.value_expr.generate_evaluation_code(code) code.putln(code.error_goto_if("PyDict_SetItem(%s, (PyObject*)%s, (PyObject*)%s)" % ( self.target.result(), self.key_expr.result(), self.value_expr.result() ), self.pos)) self.key_expr.generate_disposal_code(code) self.key_expr.free_temps(code) self.value_expr.generate_disposal_code(code) self.value_expr.free_temps(code) def generate_function_definitions(self, env, code): self.key_expr.generate_function_definitions(env, code) self.value_expr.generate_function_definitions(env, code) def annotate(self, code): self.key_expr.annotate(code) self.value_expr.annotate(code) class InlinedGeneratorExpressionNode(ScopedExprNode): # An inlined generator expression for which the result is # calculated inside of the loop. This will only be created by # transforms when replacing builtin calls on generator # expressions. # # loop ForStatNode the for-loop, not containing any YieldExprNodes # result_node ResultRefNode the reference to the result value temp # orig_func String the name of the builtin function this node replaces child_attrs = ["loop"] loop_analysed = False type = py_object_type def analyse_scoped_declarations(self, env): self.loop.analyse_declarations(env) def may_be_none(self): return False def annotate(self, code): self.loop.annotate(code) def infer_type(self, env): return self.result_node.infer_type(env) def analyse_types(self, env): if not self.has_local_scope: self.loop_analysed = True self.loop = self.loop.analyse_expressions(env) self.type = self.result_node.type self.is_temp = True return self def analyse_scoped_expressions(self, env): self.loop_analysed = True if self.has_local_scope: self.loop = self.loop.analyse_expressions(env) return self def coerce_to(self, dst_type, env): if self.orig_func == 'sum' and dst_type.is_numeric and not self.loop_analysed: # We can optimise by dropping the aggregation variable and # the add operations into C. This can only be done safely # before analysing the loop body, after that, the result # reference type will have infected expressions and # assignments. self.result_node.type = self.type = dst_type return self return super(InlinedGeneratorExpressionNode, self).coerce_to(dst_type, env) def generate_result_code(self, code): self.result_node.result_code = self.result() self.loop.generate_execution_code(code) class SetNode(ExprNode): # Set constructor. type = set_type subexprs = ['args'] gil_message = "Constructing Python set" def analyse_types(self, env): for i in range(len(self.args)): arg = self.args[i] arg = arg.analyse_types(env) self.args[i] = arg.coerce_to_pyobject(env) self.type = set_type self.is_temp = 1 return self def may_be_none(self): return False def calculate_constant_result(self): self.constant_result = set([ arg.constant_result for arg in self.args]) def compile_time_value(self, denv): values = [arg.compile_time_value(denv) for arg in self.args] try: return set(values) except Exception, e: self.compile_time_value_error(e) def generate_evaluation_code(self, code): code.globalstate.use_utility_code(Builtin.py_set_utility_code) self.allocate_temp_result(code) code.putln( "%s = PySet_New(0); %s" % ( self.result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) for arg in self.args: arg.generate_evaluation_code(code) code.put_error_if_neg( self.pos, "PySet_Add(%s, %s)" % (self.result(), arg.py_result())) arg.generate_disposal_code(code) arg.free_temps(code) class DictNode(ExprNode): # Dictionary constructor. # # key_value_pairs [DictItemNode] # exclude_null_values [boolean] Do not add NULL values to dict # # obj_conversion_errors [PyrexError] used internally subexprs = ['key_value_pairs'] is_temp = 1 exclude_null_values = False type = dict_type obj_conversion_errors = [] @classmethod def from_pairs(cls, pos, pairs): return cls(pos, key_value_pairs=[ DictItemNode(pos, key=k, value=v) for k, v in pairs]) def calculate_constant_result(self): self.constant_result = dict([ item.constant_result for item in self.key_value_pairs]) def compile_time_value(self, denv): pairs = [(item.key.compile_time_value(denv), item.value.compile_time_value(denv)) for item in self.key_value_pairs] try: return dict(pairs) except Exception, e: self.compile_time_value_error(e) def type_dependencies(self, env): return () def infer_type(self, env): # TOOD: Infer struct constructors. return dict_type def analyse_types(self, env): hold_errors() self.key_value_pairs = [ item.analyse_types(env) for item in self.key_value_pairs ] self.obj_conversion_errors = held_errors() release_errors(ignore=True) return self def may_be_none(self): return False def coerce_to(self, dst_type, env): if dst_type.is_pyobject: self.release_errors() if not self.type.subtype_of(dst_type): error(self.pos, "Cannot interpret dict as type '%s'" % dst_type) elif dst_type.is_struct_or_union: self.type = dst_type if not dst_type.is_struct and len(self.key_value_pairs) != 1: error(self.pos, "Exactly one field must be specified to convert to union '%s'" % dst_type) elif dst_type.is_struct and len(self.key_value_pairs) < len(dst_type.scope.var_entries): warning(self.pos, "Not all members given for struct '%s'" % dst_type, 1) for item in self.key_value_pairs: if isinstance(item.key, CoerceToPyTypeNode): item.key = item.key.arg if not item.key.is_string_literal: error(item.key.pos, "Invalid struct field identifier") item.key = StringNode(item.key.pos, value="") else: key = str(item.key.value) # converts string literals to unicode in Py3 member = dst_type.scope.lookup_here(key) if not member: error(item.key.pos, "struct '%s' has no field '%s'" % (dst_type, key)) else: value = item.value if isinstance(value, CoerceToPyTypeNode): value = value.arg item.value = value.coerce_to(member.type, env) else: self.type = error_type error(self.pos, "Cannot interpret dict as type '%s'" % dst_type) return self def release_errors(self): for err in self.obj_conversion_errors: report_error(err) self.obj_conversion_errors = [] gil_message = "Constructing Python dict" def generate_evaluation_code(self, code): # Custom method used here because key-value # pairs are evaluated and used one at a time. code.mark_pos(self.pos) self.allocate_temp_result(code) if self.type.is_pyobject: self.release_errors() code.putln( "%s = PyDict_New(); %s" % ( self.result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) for item in self.key_value_pairs: item.generate_evaluation_code(code) if self.type.is_pyobject: if self.exclude_null_values: code.putln('if (%s) {' % item.value.py_result()) code.put_error_if_neg(self.pos, "PyDict_SetItem(%s, %s, %s)" % ( self.result(), item.key.py_result(), item.value.py_result())) if self.exclude_null_values: code.putln('}') else: code.putln("%s.%s = %s;" % ( self.result(), item.key.value, item.value.result())) item.generate_disposal_code(code) item.free_temps(code) def annotate(self, code): for item in self.key_value_pairs: item.annotate(code) class DictItemNode(ExprNode): # Represents a single item in a DictNode # # key ExprNode # value ExprNode subexprs = ['key', 'value'] nogil_check = None # Parent DictNode takes care of it def calculate_constant_result(self): self.constant_result = ( self.key.constant_result, self.value.constant_result) def analyse_types(self, env): self.key = self.key.analyse_types(env) self.value = self.value.analyse_types(env) self.key = self.key.coerce_to_pyobject(env) self.value = self.value.coerce_to_pyobject(env) return self def generate_evaluation_code(self, code): self.key.generate_evaluation_code(code) self.value.generate_evaluation_code(code) def generate_disposal_code(self, code): self.key.generate_disposal_code(code) self.value.generate_disposal_code(code) def free_temps(self, code): self.key.free_temps(code) self.value.free_temps(code) def __iter__(self): return iter([self.key, self.value]) class SortedDictKeysNode(ExprNode): # build sorted list of dict keys, e.g. for dir() subexprs = ['arg'] is_temp = True def __init__(self, arg): ExprNode.__init__(self, arg.pos, arg=arg) self.type = Builtin.list_type def analyse_types(self, env): arg = self.arg.analyse_types(env) if arg.type is Builtin.dict_type: arg = arg.as_none_safe_node( "'NoneType' object is not iterable") self.arg = arg return self def may_be_none(self): return False def generate_result_code(self, code): dict_result = self.arg.py_result() if self.arg.type is Builtin.dict_type: function = 'PyDict_Keys' else: function = 'PyMapping_Keys' code.putln('%s = %s(%s); %s' % ( self.result(), function, dict_result, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) code.put_error_if_neg( self.pos, 'PyList_Sort(%s)' % self.py_result()) class ModuleNameMixin(object): def get_py_mod_name(self, code): return code.get_py_string_const( self.module_name, identifier=True) def get_py_qualified_name(self, code): return code.get_py_string_const( self.qualname, identifier=True) class ClassNode(ExprNode, ModuleNameMixin): # Helper class used in the implementation of Python # class definitions. Constructs a class object given # a name, tuple of bases and class dictionary. # # name EncodedString Name of the class # bases ExprNode Base class tuple # dict ExprNode Class dict (not owned by this node) # doc ExprNode or None Doc string # module_name EncodedString Name of defining module subexprs = ['bases', 'doc'] def analyse_types(self, env): self.bases = self.bases.analyse_types(env) if self.doc: self.doc = self.doc.analyse_types(env) self.doc = self.doc.coerce_to_pyobject(env) self.type = py_object_type self.is_temp = 1 env.use_utility_code(UtilityCode.load_cached("CreateClass", "ObjectHandling.c")) return self def may_be_none(self): return True gil_message = "Constructing Python class" def generate_result_code(self, code): cname = code.intern_identifier(self.name) if self.doc: code.put_error_if_neg(self.pos, 'PyDict_SetItem(%s, %s, %s)' % ( self.dict.py_result(), code.intern_identifier( StringEncoding.EncodedString("__doc__")), self.doc.py_result())) py_mod_name = self.get_py_mod_name(code) qualname = self.get_py_qualified_name(code) code.putln( '%s = __Pyx_CreateClass(%s, %s, %s, %s, %s); %s' % ( self.result(), self.bases.py_result(), self.dict.py_result(), cname, qualname, py_mod_name, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class Py3ClassNode(ExprNode): # Helper class used in the implementation of Python3+ # class definitions. Constructs a class object given # a name, tuple of bases and class dictionary. # # name EncodedString Name of the class # dict ExprNode Class dict (not owned by this node) # module_name EncodedString Name of defining module # calculate_metaclass bool should call CalculateMetaclass() # allow_py2_metaclass bool should look for Py2 metaclass subexprs = [] def analyse_types(self, env): self.type = py_object_type self.is_temp = 1 return self def may_be_none(self): return True gil_message = "Constructing Python class" def generate_result_code(self, code): code.globalstate.use_utility_code(UtilityCode.load_cached("Py3ClassCreate", "ObjectHandling.c")) cname = code.intern_identifier(self.name) if self.mkw: mkw = self.mkw.py_result() else: mkw = 'NULL' if self.metaclass: metaclass = self.metaclass.result() else: metaclass = "((PyObject*)&__Pyx_DefaultClassType)" code.putln( '%s = __Pyx_Py3ClassCreate(%s, %s, %s, %s, %s, %d, %d); %s' % ( self.result(), metaclass, cname, self.bases.py_result(), self.dict.py_result(), mkw, self.calculate_metaclass, self.allow_py2_metaclass, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class KeywordArgsNode(ExprNode): # Helper class for keyword arguments. # # starstar_arg DictNode # keyword_args [DictItemNode] subexprs = ['starstar_arg', 'keyword_args'] is_temp = 1 type = dict_type def calculate_constant_result(self): result = dict(self.starstar_arg.constant_result) for item in self.keyword_args: key, value = item.constant_result if key in result: raise ValueError("duplicate keyword argument found: %s" % key) result[key] = value self.constant_result = result def compile_time_value(self, denv): result = self.starstar_arg.compile_time_value(denv) pairs = [ (item.key.compile_time_value(denv), item.value.compile_time_value(denv)) for item in self.keyword_args ] try: result = dict(result) for key, value in pairs: if key in result: raise ValueError("duplicate keyword argument found: %s" % key) result[key] = value except Exception, e: self.compile_time_value_error(e) return result def type_dependencies(self, env): return () def infer_type(self, env): return dict_type def analyse_types(self, env): arg = self.starstar_arg.analyse_types(env) arg = arg.coerce_to_pyobject(env) self.starstar_arg = arg.as_none_safe_node( # FIXME: CPython's error message starts with the runtime function name 'argument after ** must be a mapping, not NoneType') self.keyword_args = [ item.analyse_types(env) for item in self.keyword_args ] return self def may_be_none(self): return False gil_message = "Constructing Python dict" def generate_evaluation_code(self, code): code.mark_pos(self.pos) self.allocate_temp_result(code) self.starstar_arg.generate_evaluation_code(code) if self.starstar_arg.type is not Builtin.dict_type: # CPython supports calling functions with non-dicts, so do we code.putln('if (likely(PyDict_Check(%s))) {' % self.starstar_arg.py_result()) if self.keyword_args: code.putln( "%s = PyDict_Copy(%s); %s" % ( self.result(), self.starstar_arg.py_result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) else: code.putln("%s = %s;" % ( self.result(), self.starstar_arg.py_result())) code.put_incref(self.result(), py_object_type) if self.starstar_arg.type is not Builtin.dict_type: code.putln('} else {') code.putln( "%s = PyObject_CallFunctionObjArgs(" "(PyObject*)&PyDict_Type, %s, NULL); %s" % ( self.result(), self.starstar_arg.py_result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) code.putln('}') self.starstar_arg.generate_disposal_code(code) self.starstar_arg.free_temps(code) if not self.keyword_args: return code.globalstate.use_utility_code( UtilityCode.load_cached("RaiseDoubleKeywords", "FunctionArguments.c")) for item in self.keyword_args: item.generate_evaluation_code(code) code.putln("if (unlikely(PyDict_GetItem(%s, %s))) {" % ( self.result(), item.key.py_result())) # FIXME: find out function name at runtime! code.putln('__Pyx_RaiseDoubleKeywordsError("function", %s); %s' % ( item.key.py_result(), code.error_goto(self.pos))) code.putln("}") code.put_error_if_neg(self.pos, "PyDict_SetItem(%s, %s, %s)" % ( self.result(), item.key.py_result(), item.value.py_result())) item.generate_disposal_code(code) item.free_temps(code) def annotate(self, code): self.starstar_arg.annotate(code) for item in self.keyword_args: item.annotate(code) class PyClassMetaclassNode(ExprNode): # Helper class holds Python3 metaclass object # # bases ExprNode Base class tuple (not owned by this node) # mkw ExprNode Class keyword arguments (not owned by this node) subexprs = [] def analyse_types(self, env): self.type = py_object_type self.is_temp = True return self def may_be_none(self): return True def generate_result_code(self, code): if self.mkw: code.globalstate.use_utility_code( UtilityCode.load_cached("Py3MetaclassGet", "ObjectHandling.c")) call = "__Pyx_Py3MetaclassGet(%s, %s)" % ( self.bases.result(), self.mkw.result()) else: code.globalstate.use_utility_code( UtilityCode.load_cached("CalculateMetaclass", "ObjectHandling.c")) call = "__Pyx_CalculateMetaclass(NULL, %s)" % ( self.bases.result()) code.putln( "%s = %s; %s" % ( self.result(), call, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class PyClassNamespaceNode(ExprNode, ModuleNameMixin): # Helper class holds Python3 namespace object # # All this are not owned by this node # metaclass ExprNode Metaclass object # bases ExprNode Base class tuple # mkw ExprNode Class keyword arguments # doc ExprNode or None Doc string (owned) subexprs = ['doc'] def analyse_types(self, env): if self.doc: self.doc = self.doc.analyse_types(env) self.doc = self.doc.coerce_to_pyobject(env) self.type = py_object_type self.is_temp = 1 return self def may_be_none(self): return True def generate_result_code(self, code): cname = code.intern_identifier(self.name) py_mod_name = self.get_py_mod_name(code) qualname = self.get_py_qualified_name(code) if self.doc: doc_code = self.doc.result() else: doc_code = '(PyObject *) NULL' if self.mkw: mkw = self.mkw.py_result() else: mkw = '(PyObject *) NULL' if self.metaclass: metaclass = self.metaclass.result() else: metaclass = "(PyObject *) NULL" code.putln( "%s = __Pyx_Py3MetaclassPrepare(%s, %s, %s, %s, %s, %s, %s); %s" % ( self.result(), metaclass, self.bases.result(), cname, qualname, mkw, py_mod_name, doc_code, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class ClassCellInjectorNode(ExprNode): # Initialize CyFunction.func_classobj is_temp = True type = py_object_type subexprs = [] is_active = False def analyse_expressions(self, env): if self.is_active: env.use_utility_code( UtilityCode.load_cached("CyFunctionClassCell", "CythonFunction.c")) return self def generate_evaluation_code(self, code): if self.is_active: self.allocate_temp_result(code) code.putln( '%s = PyList_New(0); %s' % ( self.result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.result()) def generate_injection_code(self, code, classobj_cname): if self.is_active: code.putln('__Pyx_CyFunction_InitClassCell(%s, %s);' % ( self.result(), classobj_cname)) class ClassCellNode(ExprNode): # Class Cell for noargs super() subexprs = [] is_temp = True is_generator = False type = py_object_type def analyse_types(self, env): return self def generate_result_code(self, code): if not self.is_generator: code.putln('%s = __Pyx_CyFunction_GetClassObj(%s);' % ( self.result(), Naming.self_cname)) else: code.putln('%s = %s->classobj;' % ( self.result(), Naming.generator_cname)) code.putln( 'if (!%s) { PyErr_SetString(PyExc_SystemError, ' '"super(): empty __class__ cell"); %s }' % ( self.result(), code.error_goto(self.pos))) code.put_incref(self.result(), py_object_type) class BoundMethodNode(ExprNode): # Helper class used in the implementation of Python # class definitions. Constructs an bound method # object from a class and a function. # # function ExprNode Function object # self_object ExprNode self object subexprs = ['function'] def analyse_types(self, env): self.function = self.function.analyse_types(env) self.type = py_object_type self.is_temp = 1 return self gil_message = "Constructing a bound method" def generate_result_code(self, code): code.putln( "%s = PyMethod_New(%s, %s, (PyObject*)%s->ob_type); %s" % ( self.result(), self.function.py_result(), self.self_object.py_result(), self.self_object.py_result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class UnboundMethodNode(ExprNode): # Helper class used in the implementation of Python # class definitions. Constructs an unbound method # object from a class and a function. # # function ExprNode Function object type = py_object_type is_temp = 1 subexprs = ['function'] def analyse_types(self, env): self.function = self.function.analyse_types(env) return self def may_be_none(self): return False gil_message = "Constructing an unbound method" def generate_result_code(self, code): class_cname = code.pyclass_stack[-1].classobj.result() code.putln( "%s = PyMethod_New(%s, 0, %s); %s" % ( self.result(), self.function.py_result(), class_cname, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class PyCFunctionNode(ExprNode, ModuleNameMixin): # Helper class used in the implementation of Python # functions. Constructs a PyCFunction object # from a PyMethodDef struct. # # pymethdef_cname string PyMethodDef structure # self_object ExprNode or None # binding bool # def_node DefNode the Python function node # module_name EncodedString Name of defining module # code_object CodeObjectNode the PyCodeObject creator node subexprs = ['code_object', 'defaults_tuple', 'defaults_kwdict', 'annotations_dict'] self_object = None code_object = None binding = False def_node = None defaults = None defaults_struct = None defaults_pyobjects = 0 defaults_tuple = None defaults_kwdict = None annotations_dict = None type = py_object_type is_temp = 1 specialized_cpdefs = None is_specialization = False @classmethod def from_defnode(cls, node, binding): return cls(node.pos, def_node=node, pymethdef_cname=node.entry.pymethdef_cname, binding=binding or node.specialized_cpdefs, specialized_cpdefs=node.specialized_cpdefs, code_object=CodeObjectNode(node)) def analyse_types(self, env): if self.binding: self.analyse_default_args(env) return self def analyse_default_args(self, env): """ Handle non-literal function's default arguments. """ nonliteral_objects = [] nonliteral_other = [] default_args = [] default_kwargs = [] annotations = [] for arg in self.def_node.args: if arg.default: if not arg.default.is_literal: arg.is_dynamic = True if arg.type.is_pyobject: nonliteral_objects.append(arg) else: nonliteral_other.append(arg) else: arg.default = DefaultLiteralArgNode(arg.pos, arg.default) if arg.kw_only: default_kwargs.append(arg) else: default_args.append(arg) if arg.annotation: arg.annotation = arg.annotation.analyse_types(env) if not arg.annotation.type.is_pyobject: arg.annotation = arg.annotation.coerce_to_pyobject(env) annotations.append((arg.pos, arg.name, arg.annotation)) if self.def_node.return_type_annotation: annotations.append((self.def_node.return_type_annotation.pos, StringEncoding.EncodedString("return"), self.def_node.return_type_annotation)) if nonliteral_objects or nonliteral_other: module_scope = env.global_scope() cname = module_scope.next_id(Naming.defaults_struct_prefix) scope = Symtab.StructOrUnionScope(cname) self.defaults = [] for arg in nonliteral_objects: entry = scope.declare_var(arg.name, arg.type, None, Naming.arg_prefix + arg.name, allow_pyobject=True) self.defaults.append((arg, entry)) for arg in nonliteral_other: entry = scope.declare_var(arg.name, arg.type, None, Naming.arg_prefix + arg.name, allow_pyobject=False) self.defaults.append((arg, entry)) entry = module_scope.declare_struct_or_union( None, 'struct', scope, 1, None, cname=cname) self.defaults_struct = scope self.defaults_pyobjects = len(nonliteral_objects) for arg, entry in self.defaults: arg.default_value = '%s->%s' % ( Naming.dynamic_args_cname, entry.cname) self.def_node.defaults_struct = self.defaults_struct.name if default_args or default_kwargs: if self.defaults_struct is None: if default_args: defaults_tuple = TupleNode(self.pos, args=[ arg.default for arg in default_args]) self.defaults_tuple = defaults_tuple.analyse_types(env) if default_kwargs: defaults_kwdict = DictNode(self.pos, key_value_pairs=[ DictItemNode( arg.pos, key=IdentifierStringNode(arg.pos, value=arg.name), value=arg.default) for arg in default_kwargs]) self.defaults_kwdict = defaults_kwdict.analyse_types(env) else: if default_args: defaults_tuple = DefaultsTupleNode( self.pos, default_args, self.defaults_struct) else: defaults_tuple = NoneNode(self.pos) if default_kwargs: defaults_kwdict = DefaultsKwDictNode( self.pos, default_kwargs, self.defaults_struct) else: defaults_kwdict = NoneNode(self.pos) defaults_getter = Nodes.DefNode( self.pos, args=[], star_arg=None, starstar_arg=None, body=Nodes.ReturnStatNode( self.pos, return_type=py_object_type, value=TupleNode( self.pos, args=[defaults_tuple, defaults_kwdict])), decorators=None, name=StringEncoding.EncodedString("__defaults__")) defaults_getter.analyse_declarations(env) defaults_getter = defaults_getter.analyse_expressions(env) defaults_getter.body = defaults_getter.body.analyse_expressions( defaults_getter.local_scope) defaults_getter.py_wrapper_required = False defaults_getter.pymethdef_required = False self.def_node.defaults_getter = defaults_getter if annotations: annotations_dict = DictNode(self.pos, key_value_pairs=[ DictItemNode( pos, key=IdentifierStringNode(pos, value=name), value=value) for pos, name, value in annotations]) self.annotations_dict = annotations_dict.analyse_types(env) def may_be_none(self): return False gil_message = "Constructing Python function" def self_result_code(self): if self.self_object is None: self_result = "NULL" else: self_result = self.self_object.py_result() return self_result def generate_result_code(self, code): if self.binding: self.generate_cyfunction_code(code) else: self.generate_pycfunction_code(code) def generate_pycfunction_code(self, code): py_mod_name = self.get_py_mod_name(code) code.putln( '%s = PyCFunction_NewEx(&%s, %s, %s); %s' % ( self.result(), self.pymethdef_cname, self.self_result_code(), py_mod_name, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) def generate_cyfunction_code(self, code): if self.specialized_cpdefs: def_node = self.specialized_cpdefs[0] else: def_node = self.def_node if self.specialized_cpdefs or self.is_specialization: code.globalstate.use_utility_code( UtilityCode.load_cached("FusedFunction", "CythonFunction.c")) constructor = "__pyx_FusedFunction_NewEx" else: code.globalstate.use_utility_code( UtilityCode.load_cached("CythonFunction", "CythonFunction.c")) constructor = "__Pyx_CyFunction_NewEx" if self.code_object: code_object_result = self.code_object.py_result() else: code_object_result = 'NULL' flags = [] if def_node.is_staticmethod: flags.append('__Pyx_CYFUNCTION_STATICMETHOD') elif def_node.is_classmethod: flags.append('__Pyx_CYFUNCTION_CLASSMETHOD') if def_node.local_scope.parent_scope.is_c_class_scope: flags.append('__Pyx_CYFUNCTION_CCLASS') if flags: flags = ' | '.join(flags) else: flags = '0' code.putln( '%s = %s(&%s, %s, %s, %s, %s, %s, %s); %s' % ( self.result(), constructor, self.pymethdef_cname, flags, self.get_py_qualified_name(code), self.self_result_code(), self.get_py_mod_name(code), "PyModule_GetDict(%s)" % Naming.module_cname, code_object_result, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) if def_node.requires_classobj: assert code.pyclass_stack, "pyclass_stack is empty" class_node = code.pyclass_stack[-1] code.put_incref(self.py_result(), py_object_type) code.putln( 'PyList_Append(%s, %s);' % ( class_node.class_cell.result(), self.result())) code.put_giveref(self.py_result()) if self.defaults: code.putln( 'if (!__Pyx_CyFunction_InitDefaults(%s, sizeof(%s), %d)) %s' % ( self.result(), self.defaults_struct.name, self.defaults_pyobjects, code.error_goto(self.pos))) defaults = '__Pyx_CyFunction_Defaults(%s, %s)' % ( self.defaults_struct.name, self.result()) for arg, entry in self.defaults: arg.generate_assignment_code(code, target='%s->%s' % ( defaults, entry.cname)) if self.defaults_tuple: code.putln('__Pyx_CyFunction_SetDefaultsTuple(%s, %s);' % ( self.result(), self.defaults_tuple.py_result())) if self.defaults_kwdict: code.putln('__Pyx_CyFunction_SetDefaultsKwDict(%s, %s);' % ( self.result(), self.defaults_kwdict.py_result())) if def_node.defaults_getter: code.putln('__Pyx_CyFunction_SetDefaultsGetter(%s, %s);' % ( self.result(), def_node.defaults_getter.entry.pyfunc_cname)) if self.annotations_dict: code.putln('__Pyx_CyFunction_SetAnnotationsDict(%s, %s);' % ( self.result(), self.annotations_dict.py_result())) class InnerFunctionNode(PyCFunctionNode): # Special PyCFunctionNode that depends on a closure class # binding = True needs_self_code = True def self_result_code(self): if self.needs_self_code: return "((PyObject*)%s)" % Naming.cur_scope_cname return "NULL" class CodeObjectNode(ExprNode): # Create a PyCodeObject for a CyFunction instance. # # def_node DefNode the Python function node # varnames TupleNode a tuple with all local variable names subexprs = ['varnames'] is_temp = False def __init__(self, def_node): ExprNode.__init__(self, def_node.pos, def_node=def_node) args = list(def_node.args) # if we have args/kwargs, then the first two in var_entries are those local_vars = [arg for arg in def_node.local_scope.var_entries if arg.name] self.varnames = TupleNode( def_node.pos, args=[IdentifierStringNode(arg.pos, value=arg.name) for arg in args + local_vars], is_temp=0, is_literal=1) def may_be_none(self): return False def calculate_result_code(self): return self.result_code def generate_result_code(self, code): self.result_code = code.get_py_const(py_object_type, 'codeobj', cleanup_level=2) code = code.get_cached_constants_writer() code.mark_pos(self.pos) func = self.def_node func_name = code.get_py_string_const( func.name, identifier=True, is_str=False, unicode_value=func.name) # FIXME: better way to get the module file path at module init time? Encoding to use? file_path = StringEncoding.BytesLiteral(func.pos[0].get_filenametable_entry().encode('utf8')) file_path_const = code.get_py_string_const(file_path, identifier=False, is_str=True) flags = [] if self.def_node.star_arg: flags.append('CO_VARARGS') if self.def_node.starstar_arg: flags.append('CO_VARKEYWORDS') code.putln("%s = (PyObject*)__Pyx_PyCode_New(%d, %d, %d, 0, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s); %s" % ( self.result_code, len(func.args) - func.num_kwonly_args, # argcount func.num_kwonly_args, # kwonlyargcount (Py3 only) len(self.varnames.args), # nlocals '|'.join(flags) or '0', # flags Naming.empty_bytes, # code Naming.empty_tuple, # consts Naming.empty_tuple, # names (FIXME) self.varnames.result(), # varnames Naming.empty_tuple, # freevars (FIXME) Naming.empty_tuple, # cellvars (FIXME) file_path_const, # filename func_name, # name self.pos[1], # firstlineno Naming.empty_bytes, # lnotab code.error_goto_if_null(self.result_code, self.pos), )) class DefaultLiteralArgNode(ExprNode): # CyFunction's literal argument default value # # Evaluate literal only once. subexprs = [] is_literal = True is_temp = False def __init__(self, pos, arg): super(DefaultLiteralArgNode, self).__init__(pos) self.arg = arg self.type = self.arg.type self.evaluated = False def analyse_types(self, env): return self def generate_result_code(self, code): pass def generate_evaluation_code(self, code): if not self.evaluated: self.arg.generate_evaluation_code(code) self.evaluated = True def result(self): return self.type.cast_code(self.arg.result()) class DefaultNonLiteralArgNode(ExprNode): # CyFunction's non-literal argument default value subexprs = [] def __init__(self, pos, arg, defaults_struct): super(DefaultNonLiteralArgNode, self).__init__(pos) self.arg = arg self.defaults_struct = defaults_struct def analyse_types(self, env): self.type = self.arg.type self.is_temp = False return self def generate_result_code(self, code): pass def result(self): return '__Pyx_CyFunction_Defaults(%s, %s)->%s' % ( self.defaults_struct.name, Naming.self_cname, self.defaults_struct.lookup(self.arg.name).cname) class DefaultsTupleNode(TupleNode): # CyFunction's __defaults__ tuple def __init__(self, pos, defaults, defaults_struct): args = [] for arg in defaults: if not arg.default.is_literal: arg = DefaultNonLiteralArgNode(pos, arg, defaults_struct) else: arg = arg.default args.append(arg) super(DefaultsTupleNode, self).__init__(pos, args=args) class DefaultsKwDictNode(DictNode): # CyFunction's __kwdefaults__ dict def __init__(self, pos, defaults, defaults_struct): items = [] for arg in defaults: name = IdentifierStringNode(arg.pos, value=arg.name) if not arg.default.is_literal: arg = DefaultNonLiteralArgNode(pos, arg, defaults_struct) else: arg = arg.default items.append(DictItemNode(arg.pos, key=name, value=arg)) super(DefaultsKwDictNode, self).__init__(pos, key_value_pairs=items) class LambdaNode(InnerFunctionNode): # Lambda expression node (only used as a function reference) # # args [CArgDeclNode] formal arguments # star_arg PyArgDeclNode or None * argument # starstar_arg PyArgDeclNode or None ** argument # lambda_name string a module-globally unique lambda name # result_expr ExprNode # def_node DefNode the underlying function 'def' node child_attrs = ['def_node'] name = StringEncoding.EncodedString('') def analyse_declarations(self, env): self.def_node.no_assignment_synthesis = True self.def_node.pymethdef_required = True self.def_node.analyse_declarations(env) self.def_node.is_cyfunction = True self.pymethdef_cname = self.def_node.entry.pymethdef_cname env.add_lambda_def(self.def_node) def analyse_types(self, env): self.def_node = self.def_node.analyse_expressions(env) return super(LambdaNode, self).analyse_types(env) def generate_result_code(self, code): self.def_node.generate_execution_code(code) super(LambdaNode, self).generate_result_code(code) class GeneratorExpressionNode(LambdaNode): # A generator expression, e.g. (i for i in range(10)) # # Result is a generator. # # loop ForStatNode the for-loop, containing a YieldExprNode # def_node DefNode the underlying generator 'def' node name = StringEncoding.EncodedString('genexpr') binding = False def analyse_declarations(self, env): super(GeneratorExpressionNode, self).analyse_declarations(env) # No pymethdef required self.def_node.pymethdef_required = False self.def_node.py_wrapper_required = False self.def_node.is_cyfunction = False # Force genexpr signature self.def_node.entry.signature = TypeSlots.pyfunction_noargs def generate_result_code(self, code): code.putln( '%s = %s(%s); %s' % ( self.result(), self.def_node.entry.pyfunc_cname, self.self_result_code(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class YieldExprNode(ExprNode): # Yield expression node # # arg ExprNode the value to return from the generator # label_num integer yield label number # is_yield_from boolean is a YieldFromExprNode to delegate to another generator subexprs = ['arg'] type = py_object_type label_num = 0 is_yield_from = False def analyse_types(self, env): if not self.label_num: error(self.pos, "'yield' not supported here") self.is_temp = 1 if self.arg is not None: self.arg = self.arg.analyse_types(env) if not self.arg.type.is_pyobject: self.coerce_yield_argument(env) return self def coerce_yield_argument(self, env): self.arg = self.arg.coerce_to_pyobject(env) def generate_evaluation_code(self, code): if self.arg: self.arg.generate_evaluation_code(code) self.arg.make_owned_reference(code) code.putln( "%s = %s;" % ( Naming.retval_cname, self.arg.result_as(py_object_type))) self.arg.generate_post_assignment_code(code) self.arg.free_temps(code) else: code.put_init_to_py_none(Naming.retval_cname, py_object_type) self.generate_yield_code(code) def generate_yield_code(self, code): """ Generate the code to return the argument in 'Naming.retval_cname' and to continue at the yield label. """ label_num, label_name = code.new_yield_label() code.use_label(label_name) saved = [] code.funcstate.closure_temps.reset() for cname, type, manage_ref in code.funcstate.temps_in_use(): save_cname = code.funcstate.closure_temps.allocate_temp(type) saved.append((cname, save_cname, type)) if type.is_pyobject: code.put_xgiveref(cname) code.putln('%s->%s = %s;' % (Naming.cur_scope_cname, save_cname, cname)) code.put_xgiveref(Naming.retval_cname) code.put_finish_refcount_context() code.putln("/* return from generator, yielding value */") code.putln("%s->resume_label = %d;" % ( Naming.generator_cname, label_num)) code.putln("return %s;" % Naming.retval_cname) code.put_label(label_name) for cname, save_cname, type in saved: code.putln('%s = %s->%s;' % (cname, Naming.cur_scope_cname, save_cname)) if type.is_pyobject: code.putln('%s->%s = 0;' % (Naming.cur_scope_cname, save_cname)) code.put_xgotref(cname) code.putln(code.error_goto_if_null(Naming.sent_value_cname, self.pos)) if self.result_is_used: self.allocate_temp_result(code) code.put('%s = %s; ' % (self.result(), Naming.sent_value_cname)) code.put_incref(self.result(), py_object_type) class YieldFromExprNode(YieldExprNode): # "yield from GEN" expression is_yield_from = True def coerce_yield_argument(self, env): if not self.arg.type.is_string: # FIXME: support C arrays and C++ iterators? error(self.pos, "yielding from non-Python object not supported") self.arg = self.arg.coerce_to_pyobject(env) def generate_evaluation_code(self, code): code.globalstate.use_utility_code(UtilityCode.load_cached("YieldFrom", "Generator.c")) self.arg.generate_evaluation_code(code) code.putln("%s = __Pyx_Generator_Yield_From(%s, %s);" % ( Naming.retval_cname, Naming.generator_cname, self.arg.result_as(py_object_type))) self.arg.generate_disposal_code(code) self.arg.free_temps(code) code.put_xgotref(Naming.retval_cname) code.putln("if (likely(%s)) {" % Naming.retval_cname) self.generate_yield_code(code) code.putln("} else {") # either error or sub-generator has normally terminated: return value => node result if self.result_is_used: # YieldExprNode has allocated the result temp for us code.putln("%s = NULL;" % self.result()) code.putln("if (unlikely(__Pyx_PyGen_FetchStopIterationValue(&%s) < 0)) %s" % ( self.result(), code.error_goto(self.pos))) code.put_gotref(self.result()) else: code.putln("PyObject* exc_type = PyErr_Occurred();") code.putln("if (exc_type) {") code.putln("if (likely(exc_type == PyExc_StopIteration ||" " PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();") code.putln("else %s" % code.error_goto(self.pos)) code.putln("}") code.putln("}") class GlobalsExprNode(AtomicExprNode): type = dict_type is_temp = 1 def analyse_types(self, env): env.use_utility_code(Builtin.globals_utility_code) return self gil_message = "Constructing globals dict" def may_be_none(self): return False def generate_result_code(self, code): code.putln('%s = __Pyx_Globals(); %s' % ( self.result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.result()) class LocalsDictItemNode(DictItemNode): def analyse_types(self, env): self.key = self.key.analyse_types(env) self.value = self.value.analyse_types(env) self.key = self.key.coerce_to_pyobject(env) if self.value.type.can_coerce_to_pyobject(env): self.value = self.value.coerce_to_pyobject(env) else: self.value = None return self class FuncLocalsExprNode(DictNode): def __init__(self, pos, env): local_vars = sorted([ entry.name for entry in env.entries.values() if entry.name]) items = [LocalsDictItemNode( pos, key=IdentifierStringNode(pos, value=var), value=NameNode(pos, name=var, allow_null=True)) for var in local_vars] DictNode.__init__(self, pos, key_value_pairs=items, exclude_null_values=True) def analyse_types(self, env): node = super(FuncLocalsExprNode, self).analyse_types(env) node.key_value_pairs = [ i for i in node.key_value_pairs if i.value is not None ] return node class PyClassLocalsExprNode(AtomicExprNode): def __init__(self, pos, pyclass_dict): AtomicExprNode.__init__(self, pos) self.pyclass_dict = pyclass_dict def analyse_types(self, env): self.type = self.pyclass_dict.type self.is_temp = False return self def may_be_none(self): return False def result(self): return self.pyclass_dict.result() def generate_result_code(self, code): pass def LocalsExprNode(pos, scope_node, env): if env.is_module_scope: return GlobalsExprNode(pos) if env.is_py_class_scope: return PyClassLocalsExprNode(pos, scope_node.dict) return FuncLocalsExprNode(pos, env) #------------------------------------------------------------------- # # Unary operator nodes # #------------------------------------------------------------------- compile_time_unary_operators = { 'not': operator.not_, '~': operator.inv, '-': operator.neg, '+': operator.pos, } class UnopNode(ExprNode): # operator string # operand ExprNode # # Processing during analyse_expressions phase: # # analyse_c_operation # Called when the operand is not a pyobject. # - Check operand type and coerce if needed. # - Determine result type and result code fragment. # - Allocate temporary for result if needed. subexprs = ['operand'] infix = True def calculate_constant_result(self): func = compile_time_unary_operators[self.operator] self.constant_result = func(self.operand.constant_result) def compile_time_value(self, denv): func = compile_time_unary_operators.get(self.operator) if not func: error(self.pos, "Unary '%s' not supported in compile-time expression" % self.operator) operand = self.operand.compile_time_value(denv) try: return func(operand) except Exception, e: self.compile_time_value_error(e) def infer_type(self, env): operand_type = self.operand.infer_type(env) if operand_type.is_cpp_class or operand_type.is_ptr: cpp_type = operand_type.find_cpp_operation_type(self.operator) if cpp_type is not None: return cpp_type return self.infer_unop_type(env, operand_type) def infer_unop_type(self, env, operand_type): if operand_type.is_pyobject: return py_object_type else: return operand_type def may_be_none(self): if self.operand.type and self.operand.type.is_builtin_type: if self.operand.type is not type_type: return False return ExprNode.may_be_none(self) def analyse_types(self, env): self.operand = self.operand.analyse_types(env) if self.is_py_operation(): self.coerce_operand_to_pyobject(env) self.type = py_object_type self.is_temp = 1 elif self.is_cpp_operation(): self.analyse_cpp_operation(env) else: self.analyse_c_operation(env) return self def check_const(self): return self.operand.check_const() def is_py_operation(self): return self.operand.type.is_pyobject def nogil_check(self, env): if self.is_py_operation(): self.gil_error() def is_cpp_operation(self): type = self.operand.type return type.is_cpp_class def coerce_operand_to_pyobject(self, env): self.operand = self.operand.coerce_to_pyobject(env) def generate_result_code(self, code): if self.operand.type.is_pyobject: self.generate_py_operation_code(code) def generate_py_operation_code(self, code): function = self.py_operation_function() code.putln( "%s = %s(%s); %s" % ( self.result(), function, self.operand.py_result(), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) def type_error(self): if not self.operand.type.is_error: error(self.pos, "Invalid operand type for '%s' (%s)" % (self.operator, self.operand.type)) self.type = PyrexTypes.error_type def analyse_cpp_operation(self, env): cpp_type = self.operand.type.find_cpp_operation_type(self.operator) if cpp_type is None: error(self.pos, "'%s' operator not defined for %s" % ( self.operator, type)) self.type_error() return self.type = cpp_type class NotNode(UnopNode): # 'not' operator # # operand ExprNode operator = '!' type = PyrexTypes.c_bint_type def calculate_constant_result(self): self.constant_result = not self.operand.constant_result def compile_time_value(self, denv): operand = self.operand.compile_time_value(denv) try: return not operand except Exception, e: self.compile_time_value_error(e) def infer_unop_type(self, env, operand_type): return PyrexTypes.c_bint_type def analyse_types(self, env): self.operand = self.operand.analyse_types(env) operand_type = self.operand.type if operand_type.is_cpp_class: cpp_type = operand_type.find_cpp_operation_type(self.operator) if not cpp_type: error(self.pos, "'!' operator not defined for %s" % operand_type) self.type = PyrexTypes.error_type return self.type = cpp_type else: self.operand = self.operand.coerce_to_boolean(env) return self def calculate_result_code(self): return "(!%s)" % self.operand.result() def generate_result_code(self, code): pass class UnaryPlusNode(UnopNode): # unary '+' operator operator = '+' def analyse_c_operation(self, env): self.type = PyrexTypes.widest_numeric_type( self.operand.type, PyrexTypes.c_int_type) def py_operation_function(self): return "PyNumber_Positive" def calculate_result_code(self): if self.is_cpp_operation(): return "(+%s)" % self.operand.result() else: return self.operand.result() class UnaryMinusNode(UnopNode): # unary '-' operator operator = '-' def analyse_c_operation(self, env): if self.operand.type.is_numeric: self.type = PyrexTypes.widest_numeric_type( self.operand.type, PyrexTypes.c_int_type) elif self.operand.type.is_enum: self.type = PyrexTypes.c_int_type else: self.type_error() if self.type.is_complex: self.infix = False def py_operation_function(self): return "PyNumber_Negative" def calculate_result_code(self): if self.infix: return "(-%s)" % self.operand.result() else: return "%s(%s)" % (self.operand.type.unary_op('-'), self.operand.result()) def get_constant_c_result_code(self): value = self.operand.get_constant_c_result_code() if value: return "(-%s)" % value class TildeNode(UnopNode): # unary '~' operator def analyse_c_operation(self, env): if self.operand.type.is_int: self.type = PyrexTypes.widest_numeric_type( self.operand.type, PyrexTypes.c_int_type) elif self.operand.type.is_enum: self.type = PyrexTypes.c_int_type else: self.type_error() def py_operation_function(self): return "PyNumber_Invert" def calculate_result_code(self): return "(~%s)" % self.operand.result() class CUnopNode(UnopNode): def is_py_operation(self): return False class DereferenceNode(CUnopNode): # unary * operator operator = '*' def infer_unop_type(self, env, operand_type): if operand_type.is_ptr: return operand_type.base_type else: return PyrexTypes.error_type def analyse_c_operation(self, env): if self.operand.type.is_ptr: self.type = self.operand.type.base_type else: self.type_error() def calculate_result_code(self): return "(*%s)" % self.operand.result() class DecrementIncrementNode(CUnopNode): # unary ++/-- operator def analyse_c_operation(self, env): if self.operand.type.is_numeric: self.type = PyrexTypes.widest_numeric_type( self.operand.type, PyrexTypes.c_int_type) elif self.operand.type.is_ptr: self.type = self.operand.type else: self.type_error() def calculate_result_code(self): if self.is_prefix: return "(%s%s)" % (self.operator, self.operand.result()) else: return "(%s%s)" % (self.operand.result(), self.operator) def inc_dec_constructor(is_prefix, operator): return lambda pos, **kwds: DecrementIncrementNode(pos, is_prefix=is_prefix, operator=operator, **kwds) class AmpersandNode(CUnopNode): # The C address-of operator. # # operand ExprNode operator = '&' def infer_unop_type(self, env, operand_type): return PyrexTypes.c_ptr_type(operand_type) def analyse_types(self, env): self.operand = self.operand.analyse_types(env) argtype = self.operand.type if argtype.is_cpp_class: cpp_type = argtype.find_cpp_operation_type(self.operator) if cpp_type is not None: self.type = cpp_type return self if not (argtype.is_cfunction or argtype.is_reference or self.operand.is_addressable()): if argtype.is_memoryviewslice: self.error("Cannot take address of memoryview slice") else: self.error("Taking address of non-lvalue") return self if argtype.is_pyobject: self.error("Cannot take address of Python variable") return self self.type = PyrexTypes.c_ptr_type(argtype) return self def check_const(self): return self.operand.check_const_addr() def error(self, mess): error(self.pos, mess) self.type = PyrexTypes.error_type self.result_code = "" def calculate_result_code(self): return "(&%s)" % self.operand.result() def generate_result_code(self, code): pass unop_node_classes = { "+": UnaryPlusNode, "-": UnaryMinusNode, "~": TildeNode, } def unop_node(pos, operator, operand): # Construct unnop node of appropriate class for # given operator. if isinstance(operand, IntNode) and operator == '-': return IntNode(pos = operand.pos, value = str(-Utils.str_to_number(operand.value)), longness=operand.longness, unsigned=operand.unsigned) elif isinstance(operand, UnopNode) and operand.operator == operator in '+-': warning(pos, "Python has no increment/decrement operator: %s%sx == %s(%sx) == x" % ((operator,)*4), 5) return unop_node_classes[operator](pos, operator = operator, operand = operand) class TypecastNode(ExprNode): # C type cast # # operand ExprNode # base_type CBaseTypeNode # declarator CDeclaratorNode # typecheck boolean # # If used from a transform, one can if wanted specify the attribute # "type" directly and leave base_type and declarator to None subexprs = ['operand'] base_type = declarator = type = None def type_dependencies(self, env): return () def infer_type(self, env): if self.type is None: base_type = self.base_type.analyse(env) _, self.type = self.declarator.analyse(base_type, env) return self.type def analyse_types(self, env): if self.type is None: base_type = self.base_type.analyse(env) _, self.type = self.declarator.analyse(base_type, env) if self.operand.has_constant_result(): # Must be done after self.type is resolved. self.calculate_constant_result() if self.type.is_cfunction: error(self.pos, "Cannot cast to a function type") self.type = PyrexTypes.error_type self.operand = self.operand.analyse_types(env) if self.type is PyrexTypes.c_bint_type: # short circuit this to a coercion return self.operand.coerce_to_boolean(env) to_py = self.type.is_pyobject from_py = self.operand.type.is_pyobject if from_py and not to_py and self.operand.is_ephemeral(): if not self.type.is_numeric and not self.type.is_cpp_class: error(self.pos, "Casting temporary Python object to non-numeric non-Python type") if to_py and not from_py: if self.type is bytes_type and self.operand.type.is_int: return CoerceIntToBytesNode(self.operand, env) elif self.operand.type.can_coerce_to_pyobject(env): self.result_ctype = py_object_type base_type = self.base_type.analyse(env) self.operand = self.operand.coerce_to(base_type, env) else: if self.operand.type.is_ptr: if not (self.operand.type.base_type.is_void or self.operand.type.base_type.is_struct): error(self.pos, "Python objects cannot be cast from pointers of primitive types") else: # Should this be an error? warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type)) self.operand = self.operand.coerce_to_simple(env) elif from_py and not to_py: if self.type.create_from_py_utility_code(env): self.operand = self.operand.coerce_to(self.type, env) elif self.type.is_ptr: if not (self.type.base_type.is_void or self.type.base_type.is_struct): error(self.pos, "Python objects cannot be cast to pointers of primitive types") else: warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.type, self.operand.type)) elif from_py and to_py: if self.typecheck: self.operand = PyTypeTestNode(self.operand, self.type, env, notnone=True) elif isinstance(self.operand, SliceIndexNode): # This cast can influence the created type of string slices. self.operand = self.operand.coerce_to(self.type, env) elif self.type.is_complex and self.operand.type.is_complex: self.operand = self.operand.coerce_to_simple(env) elif self.operand.type.is_fused: self.operand = self.operand.coerce_to(self.type, env) #self.type = self.operand.type return self def is_simple(self): # either temp or a C cast => no side effects other than the operand's return self.operand.is_simple() def nonlocally_immutable(self): return self.is_temp or self.operand.nonlocally_immutable() def nogil_check(self, env): if self.type and self.type.is_pyobject and self.is_temp: self.gil_error() def check_const(self): return self.operand.check_const() def calculate_constant_result(self): self.constant_result = self.calculate_result_code(self.operand.constant_result) def calculate_result_code(self, operand_result = None): if operand_result is None: operand_result = self.operand.result() if self.type.is_complex: operand_result = self.operand.result() if self.operand.type.is_complex: real_part = self.type.real_type.cast_code("__Pyx_CREAL(%s)" % operand_result) imag_part = self.type.real_type.cast_code("__Pyx_CIMAG(%s)" % operand_result) else: real_part = self.type.real_type.cast_code(operand_result) imag_part = "0" return "%s(%s, %s)" % ( self.type.from_parts, real_part, imag_part) else: return self.type.cast_code(operand_result) def get_constant_c_result_code(self): operand_result = self.operand.get_constant_c_result_code() if operand_result: return self.type.cast_code(operand_result) def result_as(self, type): if self.type.is_pyobject and not self.is_temp: # Optimise away some unnecessary casting return self.operand.result_as(type) else: return ExprNode.result_as(self, type) def generate_result_code(self, code): if self.is_temp: code.putln( "%s = (PyObject *)%s;" % ( self.result(), self.operand.result())) code.put_incref(self.result(), self.ctype()) ERR_START = "Start may not be given" ERR_NOT_STOP = "Stop must be provided to indicate shape" ERR_STEPS = ("Strides may only be given to indicate contiguity. " "Consider slicing it after conversion") ERR_NOT_POINTER = "Can only create cython.array from pointer or array" ERR_BASE_TYPE = "Pointer base type does not match cython.array base type" class CythonArrayNode(ExprNode): """ Used when a pointer of base_type is cast to a memoryviewslice with that base type. i.e. p creates a fortran-contiguous cython.array. We leave the type set to object so coercions to object are more efficient and less work. Acquiring a memoryviewslice from this will be just as efficient. ExprNode.coerce_to() will do the additional typecheck on self.compile_time_type This also handles my_c_array operand ExprNode the thing we're casting base_type_node MemoryViewSliceTypeNode the cast expression node """ subexprs = ['operand', 'shapes'] shapes = None is_temp = True mode = "c" array_dtype = None shape_type = PyrexTypes.c_py_ssize_t_type def analyse_types(self, env): import MemoryView self.operand = self.operand.analyse_types(env) if self.array_dtype: array_dtype = self.array_dtype else: array_dtype = self.base_type_node.base_type_node.analyse(env) axes = self.base_type_node.axes MemoryView.validate_memslice_dtype(self.pos, array_dtype) self.type = error_type self.shapes = [] ndim = len(axes) # Base type of the pointer or C array we are converting base_type = self.operand.type if not self.operand.type.is_ptr and not self.operand.type.is_array: error(self.operand.pos, ERR_NOT_POINTER) return self # Dimension sizes of C array array_dimension_sizes = [] if base_type.is_array: while base_type.is_array: array_dimension_sizes.append(base_type.size) base_type = base_type.base_type elif base_type.is_ptr: base_type = base_type.base_type else: error(self.pos, "unexpected base type %s found" % base_type) return self if not (base_type.same_as(array_dtype) or base_type.is_void): error(self.operand.pos, ERR_BASE_TYPE) return self elif self.operand.type.is_array and len(array_dimension_sizes) != ndim: error(self.operand.pos, "Expected %d dimensions, array has %d dimensions" % (ndim, len(array_dimension_sizes))) return self # Verify the start, stop and step values # In case of a C array, use the size of C array in each dimension to # get an automatic cast for axis_no, axis in enumerate(axes): if not axis.start.is_none: error(axis.start.pos, ERR_START) return self if axis.stop.is_none: if array_dimension_sizes: dimsize = array_dimension_sizes[axis_no] axis.stop = IntNode(self.pos, value=str(dimsize), constant_result=dimsize, type=PyrexTypes.c_int_type) else: error(axis.pos, ERR_NOT_STOP) return self axis.stop = axis.stop.analyse_types(env) shape = axis.stop.coerce_to(self.shape_type, env) if not shape.is_literal: shape.coerce_to_temp(env) self.shapes.append(shape) first_or_last = axis_no in (0, ndim - 1) if not axis.step.is_none and first_or_last: # '1' in the first or last dimension denotes F or C contiguity axis.step = axis.step.analyse_types(env) if (not axis.step.type.is_int and axis.step.is_literal and not axis.step.type.is_error): error(axis.step.pos, "Expected an integer literal") return self if axis.step.compile_time_value(env) != 1: error(axis.step.pos, ERR_STEPS) return self if axis_no == 0: self.mode = "fortran" elif not axis.step.is_none and not first_or_last: # step provided in some other dimension error(axis.step.pos, ERR_STEPS) return self if not self.operand.is_name: self.operand = self.operand.coerce_to_temp(env) axes = [('direct', 'follow')] * len(axes) if self.mode == "fortran": axes[0] = ('direct', 'contig') else: axes[-1] = ('direct', 'contig') self.coercion_type = PyrexTypes.MemoryViewSliceType(array_dtype, axes) self.type = self.get_cython_array_type(env) MemoryView.use_cython_array_utility_code(env) env.use_utility_code(MemoryView.typeinfo_to_format_code) return self def allocate_temp_result(self, code): if self.temp_code: raise RuntimeError("temp allocated mulitple times") self.temp_code = code.funcstate.allocate_temp(self.type, True) def infer_type(self, env): return self.get_cython_array_type(env) def get_cython_array_type(self, env): return env.global_scope().context.cython_scope.viewscope.lookup("array").type def generate_result_code(self, code): import Buffer shapes = [self.shape_type.cast_code(shape.result()) for shape in self.shapes] dtype = self.coercion_type.dtype shapes_temp = code.funcstate.allocate_temp(py_object_type, True) format_temp = code.funcstate.allocate_temp(py_object_type, True) itemsize = "sizeof(%s)" % dtype.declaration_code("") type_info = Buffer.get_type_information_cname(code, dtype) if self.operand.type.is_ptr: code.putln("if (!%s) {" % self.operand.result()) code.putln( 'PyErr_SetString(PyExc_ValueError,' '"Cannot create cython.array from NULL pointer");') code.putln(code.error_goto(self.operand.pos)) code.putln("}") code.putln("%s = __pyx_format_from_typeinfo(&%s);" % (format_temp, type_info)) buildvalue_fmt = " __PYX_BUILD_PY_SSIZE_T " * len(shapes) code.putln('%s = Py_BuildValue((char*) "(" %s ")", %s);' % ( shapes_temp, buildvalue_fmt, ", ".join(shapes))) err = "!%s || !%s || !PyBytes_AsString(%s)" % (format_temp, shapes_temp, format_temp) code.putln(code.error_goto_if(err, self.pos)) code.put_gotref(format_temp) code.put_gotref(shapes_temp) tup = (self.result(), shapes_temp, itemsize, format_temp, self.mode, self.operand.result()) code.putln('%s = __pyx_array_new(' '%s, %s, PyBytes_AS_STRING(%s), ' '(char *) "%s", (char *) %s);' % tup) code.putln(code.error_goto_if_null(self.result(), self.pos)) code.put_gotref(self.result()) def dispose(temp): code.put_decref_clear(temp, py_object_type) code.funcstate.release_temp(temp) dispose(shapes_temp) dispose(format_temp) @classmethod def from_carray(cls, src_node, env): """ Given a C array type, return a CythonArrayNode """ pos = src_node.pos base_type = src_node.type none_node = NoneNode(pos) axes = [] while base_type.is_array: axes.append(SliceNode(pos, start=none_node, stop=none_node, step=none_node)) base_type = base_type.base_type axes[-1].step = IntNode(pos, value="1", is_c_literal=True) memslicenode = Nodes.MemoryViewSliceTypeNode(pos, axes=axes, base_type_node=base_type) result = CythonArrayNode(pos, base_type_node=memslicenode, operand=src_node, array_dtype=base_type) result = result.analyse_types(env) return result class SizeofNode(ExprNode): # Abstract base class for sizeof(x) expression nodes. type = PyrexTypes.c_size_t_type def check_const(self): return True def generate_result_code(self, code): pass class SizeofTypeNode(SizeofNode): # C sizeof function applied to a type # # base_type CBaseTypeNode # declarator CDeclaratorNode subexprs = [] arg_type = None def analyse_types(self, env): # we may have incorrectly interpreted a dotted name as a type rather than an attribute # this could be better handled by more uniformly treating types as runtime-available objects if 0 and self.base_type.module_path: path = self.base_type.module_path obj = env.lookup(path[0]) if obj.as_module is None: operand = NameNode(pos=self.pos, name=path[0]) for attr in path[1:]: operand = AttributeNode(pos=self.pos, obj=operand, attribute=attr) operand = AttributeNode(pos=self.pos, obj=operand, attribute=self.base_type.name) self.operand = operand self.__class__ = SizeofVarNode node = self.analyse_types(env) return node if self.arg_type is None: base_type = self.base_type.analyse(env) _, arg_type = self.declarator.analyse(base_type, env) self.arg_type = arg_type self.check_type() return self def check_type(self): arg_type = self.arg_type if arg_type.is_pyobject and not arg_type.is_extension_type: error(self.pos, "Cannot take sizeof Python object") elif arg_type.is_void: error(self.pos, "Cannot take sizeof void") elif not arg_type.is_complete(): error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type) def calculate_result_code(self): if self.arg_type.is_extension_type: # the size of the pointer is boring # we want the size of the actual struct arg_code = self.arg_type.declaration_code("", deref=1) else: arg_code = self.arg_type.declaration_code("") return "(sizeof(%s))" % arg_code class SizeofVarNode(SizeofNode): # C sizeof function applied to a variable # # operand ExprNode subexprs = ['operand'] def analyse_types(self, env): # We may actually be looking at a type rather than a variable... # If we are, traditional analysis would fail... operand_as_type = self.operand.analyse_as_type(env) if operand_as_type: self.arg_type = operand_as_type if self.arg_type.is_fused: self.arg_type = self.arg_type.specialize(env.fused_to_specific) self.__class__ = SizeofTypeNode self.check_type() else: self.operand = self.operand.analyse_types(env) return self def calculate_result_code(self): return "(sizeof(%s))" % self.operand.result() def generate_result_code(self, code): pass class TypeofNode(ExprNode): # Compile-time type of an expression, as a string. # # operand ExprNode # literal StringNode # internal literal = None type = py_object_type subexprs = ['literal'] # 'operand' will be ignored after type analysis! def analyse_types(self, env): self.operand = self.operand.analyse_types(env) value = StringEncoding.EncodedString(str(self.operand.type)) #self.operand.type.typeof_name()) literal = StringNode(self.pos, value=value) literal = literal.analyse_types(env) self.literal = literal.coerce_to_pyobject(env) return self def may_be_none(self): return False def generate_evaluation_code(self, code): self.literal.generate_evaluation_code(code) def calculate_result_code(self): return self.literal.calculate_result_code() #------------------------------------------------------------------- # # Binary operator nodes # #------------------------------------------------------------------- compile_time_binary_operators = { '<': operator.lt, '<=': operator.le, '==': operator.eq, '!=': operator.ne, '>=': operator.ge, '>': operator.gt, 'is': operator.is_, 'is_not': operator.is_not, '+': operator.add, '&': operator.and_, '/': operator.truediv, '//': operator.floordiv, '<<': operator.lshift, '%': operator.mod, '*': operator.mul, '|': operator.or_, '**': operator.pow, '>>': operator.rshift, '-': operator.sub, '^': operator.xor, 'in': lambda x, seq: x in seq, 'not_in': lambda x, seq: x not in seq, } def get_compile_time_binop(node): func = compile_time_binary_operators.get(node.operator) if not func: error(node.pos, "Binary '%s' not supported in compile-time expression" % node.operator) return func class BinopNode(ExprNode): # operator string # operand1 ExprNode # operand2 ExprNode # # Processing during analyse_expressions phase: # # analyse_c_operation # Called when neither operand is a pyobject. # - Check operand types and coerce if needed. # - Determine result type and result code fragment. # - Allocate temporary for result if needed. subexprs = ['operand1', 'operand2'] inplace = False def calculate_constant_result(self): func = compile_time_binary_operators[self.operator] self.constant_result = func( self.operand1.constant_result, self.operand2.constant_result) def compile_time_value(self, denv): func = get_compile_time_binop(self) operand1 = self.operand1.compile_time_value(denv) operand2 = self.operand2.compile_time_value(denv) try: return func(operand1, operand2) except Exception, e: self.compile_time_value_error(e) def infer_type(self, env): return self.result_type(self.operand1.infer_type(env), self.operand2.infer_type(env)) def analyse_types(self, env): self.operand1 = self.operand1.analyse_types(env) self.operand2 = self.operand2.analyse_types(env) self.analyse_operation(env) return self def analyse_operation(self, env): if self.is_py_operation(): self.coerce_operands_to_pyobjects(env) self.type = self.result_type(self.operand1.type, self.operand2.type) assert self.type.is_pyobject self.is_temp = 1 elif self.is_cpp_operation(): self.analyse_cpp_operation(env) else: self.analyse_c_operation(env) def is_py_operation(self): return self.is_py_operation_types(self.operand1.type, self.operand2.type) def is_py_operation_types(self, type1, type2): return type1.is_pyobject or type2.is_pyobject def is_cpp_operation(self): return (self.operand1.type.is_cpp_class or self.operand2.type.is_cpp_class) def analyse_cpp_operation(self, env): entry = env.lookup_operator(self.operator, [self.operand1, self.operand2]) if not entry: self.type_error() return func_type = entry.type if func_type.is_ptr: func_type = func_type.base_type if len(func_type.args) == 1: self.operand2 = self.operand2.coerce_to(func_type.args[0].type, env) else: self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env) self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env) self.type = func_type.return_type def result_type(self, type1, type2): if self.is_py_operation_types(type1, type2): if type2.is_string: type2 = Builtin.bytes_type elif type2.is_pyunicode_ptr: type2 = Builtin.unicode_type if type1.is_string: type1 = Builtin.bytes_type elif type1.is_pyunicode_ptr: type1 = Builtin.unicode_type if type1.is_builtin_type or type2.is_builtin_type: if type1 is type2 and self.operator in '**%+|&^': # FIXME: at least these operators should be safe - others? return type1 result_type = self.infer_builtin_types_operation(type1, type2) if result_type is not None: return result_type return py_object_type else: return self.compute_c_result_type(type1, type2) def infer_builtin_types_operation(self, type1, type2): return None def nogil_check(self, env): if self.is_py_operation(): self.gil_error() def coerce_operands_to_pyobjects(self, env): self.operand1 = self.operand1.coerce_to_pyobject(env) self.operand2 = self.operand2.coerce_to_pyobject(env) def check_const(self): return self.operand1.check_const() and self.operand2.check_const() def generate_result_code(self, code): #print "BinopNode.generate_result_code:", self.operand1, self.operand2 ### if self.operand1.type.is_pyobject: function = self.py_operation_function() if self.operator == '**': extra_args = ", Py_None" else: extra_args = "" code.putln( "%s = %s(%s, %s%s); %s" % ( self.result(), function, self.operand1.py_result(), self.operand2.py_result(), extra_args, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) elif self.is_temp: code.putln("%s = %s;" % (self.result(), self.calculate_result_code())) def type_error(self): if not (self.operand1.type.is_error or self.operand2.type.is_error): error(self.pos, "Invalid operand types for '%s' (%s; %s)" % (self.operator, self.operand1.type, self.operand2.type)) self.type = PyrexTypes.error_type class CBinopNode(BinopNode): def analyse_types(self, env): node = BinopNode.analyse_types(self, env) if node.is_py_operation(): node.type = PyrexTypes.error_type return node def py_operation_function(self): return "" def calculate_result_code(self): return "(%s %s %s)" % ( self.operand1.result(), self.operator, self.operand2.result()) def compute_c_result_type(self, type1, type2): cpp_type = None if type1.is_cpp_class or type1.is_ptr: cpp_type = type1.find_cpp_operation_type(self.operator, type2) # FIXME: handle the reversed case? #if cpp_type is None and (type2.is_cpp_class or type2.is_ptr): # cpp_type = type2.find_cpp_operation_type(self.operator, type1) # FIXME: do we need to handle other cases here? return cpp_type def c_binop_constructor(operator): def make_binop_node(pos, **operands): return CBinopNode(pos, operator=operator, **operands) return make_binop_node class NumBinopNode(BinopNode): # Binary operation taking numeric arguments. infix = True overflow_check = False overflow_bit_node = None def analyse_c_operation(self, env): type1 = self.operand1.type type2 = self.operand2.type self.type = self.compute_c_result_type(type1, type2) if not self.type: self.type_error() return if self.type.is_complex: self.infix = False if (self.type.is_int and env.directives['overflowcheck'] and self.operator in self.overflow_op_names): if (self.operator in ('+', '*') and self.operand1.has_constant_result() and not self.operand2.has_constant_result()): self.operand1, self.operand2 = self.operand2, self.operand1 self.overflow_check = True self.overflow_fold = env.directives['overflowcheck.fold'] self.func = self.type.overflow_check_binop( self.overflow_op_names[self.operator], env, const_rhs = self.operand2.has_constant_result()) self.is_temp = True if not self.infix or (type1.is_numeric and type2.is_numeric): self.operand1 = self.operand1.coerce_to(self.type, env) self.operand2 = self.operand2.coerce_to(self.type, env) def compute_c_result_type(self, type1, type2): if self.c_types_okay(type1, type2): widest_type = PyrexTypes.widest_numeric_type(type1, type2) if widest_type is PyrexTypes.c_bint_type: if self.operator not in '|^&': # False + False == 0 # not False! widest_type = PyrexTypes.c_int_type else: widest_type = PyrexTypes.widest_numeric_type( widest_type, PyrexTypes.c_int_type) return widest_type else: return None def may_be_none(self): if self.type and self.type.is_builtin_type: # if we know the result type, we know the operation, so it can't be None return False type1 = self.operand1.type type2 = self.operand2.type if type1 and type1.is_builtin_type and type2 and type2.is_builtin_type: # XXX: I can't think of any case where a binary operation # on builtin types evaluates to None - add a special case # here if there is one. return False return super(NumBinopNode, self).may_be_none() def get_constant_c_result_code(self): value1 = self.operand1.get_constant_c_result_code() value2 = self.operand2.get_constant_c_result_code() if value1 and value2: return "(%s %s %s)" % (value1, self.operator, value2) else: return None def c_types_okay(self, type1, type2): #print "NumBinopNode.c_types_okay:", type1, type2 ### return (type1.is_numeric or type1.is_enum) \ and (type2.is_numeric or type2.is_enum) def generate_evaluation_code(self, code): if self.overflow_check: self.overflow_bit_node = self self.overflow_bit = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) code.putln("%s = 0;" % self.overflow_bit) super(NumBinopNode, self).generate_evaluation_code(code) if self.overflow_check: code.putln("if (unlikely(%s)) {" % self.overflow_bit) code.putln('PyErr_SetString(PyExc_OverflowError, "value too large");') code.putln(code.error_goto(self.pos)) code.putln("}") code.funcstate.release_temp(self.overflow_bit) def calculate_result_code(self): if self.overflow_bit_node is not None: return "%s(%s, %s, &%s)" % ( self.func, self.operand1.result(), self.operand2.result(), self.overflow_bit_node.overflow_bit) elif self.infix: return "(%s %s %s)" % ( self.operand1.result(), self.operator, self.operand2.result()) else: func = self.type.binary_op(self.operator) if func is None: error(self.pos, "binary operator %s not supported for %s" % (self.operator, self.type)) return "%s(%s, %s)" % ( func, self.operand1.result(), self.operand2.result()) def is_py_operation_types(self, type1, type2): return (type1.is_unicode_char or type2.is_unicode_char or BinopNode.is_py_operation_types(self, type1, type2)) def py_operation_function(self): function_name = self.py_functions[self.operator] if self.inplace: function_name = function_name.replace('PyNumber_', 'PyNumber_InPlace') return function_name py_functions = { "|": "PyNumber_Or", "^": "PyNumber_Xor", "&": "PyNumber_And", "<<": "PyNumber_Lshift", ">>": "PyNumber_Rshift", "+": "PyNumber_Add", "-": "PyNumber_Subtract", "*": "PyNumber_Multiply", "/": "__Pyx_PyNumber_Divide", "//": "PyNumber_FloorDivide", "%": "PyNumber_Remainder", "**": "PyNumber_Power" } overflow_op_names = { "+": "add", "-": "sub", "*": "mul", "<<": "lshift", } class IntBinopNode(NumBinopNode): # Binary operation taking integer arguments. def c_types_okay(self, type1, type2): #print "IntBinopNode.c_types_okay:", type1, type2 ### return (type1.is_int or type1.is_enum) \ and (type2.is_int or type2.is_enum) class AddNode(NumBinopNode): # '+' operator. def is_py_operation_types(self, type1, type2): if type1.is_string and type2.is_string or type1.is_pyunicode_ptr and type2.is_pyunicode_ptr: return 1 else: return NumBinopNode.is_py_operation_types(self, type1, type2) def infer_builtin_types_operation(self, type1, type2): # b'abc' + 'abc' raises an exception in Py3, # so we can safely infer the Py2 type for bytes here string_types = [bytes_type, str_type, basestring_type, unicode_type] # Py2.4 lacks tuple.index() if type1 in string_types and type2 in string_types: return string_types[max(string_types.index(type1), string_types.index(type2))] return None def compute_c_result_type(self, type1, type2): #print "AddNode.compute_c_result_type:", type1, self.operator, type2 ### if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum): return type1 elif (type2.is_ptr or type2.is_array) and (type1.is_int or type1.is_enum): return type2 else: return NumBinopNode.compute_c_result_type( self, type1, type2) def py_operation_function(self): type1, type2 = self.operand1.type, self.operand2.type if type1 is unicode_type or type2 is unicode_type: if type1.is_builtin_type and type2.is_builtin_type: if self.operand1.may_be_none() or self.operand2.may_be_none(): return '__Pyx_PyUnicode_ConcatSafe' else: return '__Pyx_PyUnicode_Concat' return super(AddNode, self).py_operation_function() class SubNode(NumBinopNode): # '-' operator. def compute_c_result_type(self, type1, type2): if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum): return type1 elif (type1.is_ptr or type1.is_array) and (type2.is_ptr or type2.is_array): return PyrexTypes.c_ptrdiff_t_type else: return NumBinopNode.compute_c_result_type( self, type1, type2) class MulNode(NumBinopNode): # '*' operator. def is_py_operation_types(self, type1, type2): if ((type1.is_string and type2.is_int) or (type2.is_string and type1.is_int)): return 1 else: return NumBinopNode.is_py_operation_types(self, type1, type2) def infer_builtin_types_operation(self, type1, type2): # let's assume that whatever builtin type you multiply a string with # will either return a string of the same type or fail with an exception string_types = (bytes_type, str_type, basestring_type, unicode_type) if type1 in string_types and type2.is_builtin_type: return type1 if type2 in string_types and type1.is_builtin_type: return type2 # multiplication of containers/numbers with an integer value # always (?) returns the same type if type1.is_int: return type2 if type2.is_int: return type1 return None class DivNode(NumBinopNode): # '/' or '//' operator. cdivision = None truedivision = None # == "unknown" if operator == '/' ctruedivision = False cdivision_warnings = False zerodivision_check = None def find_compile_time_binary_operator(self, op1, op2): func = compile_time_binary_operators[self.operator] if self.operator == '/' and self.truedivision is None: # => true div for floats, floor div for integers if isinstance(op1, (int,long)) and isinstance(op2, (int,long)): func = compile_time_binary_operators['//'] return func def calculate_constant_result(self): op1 = self.operand1.constant_result op2 = self.operand2.constant_result func = self.find_compile_time_binary_operator(op1, op2) self.constant_result = func( self.operand1.constant_result, self.operand2.constant_result) def compile_time_value(self, denv): operand1 = self.operand1.compile_time_value(denv) operand2 = self.operand2.compile_time_value(denv) try: func = self.find_compile_time_binary_operator( operand1, operand2) return func(operand1, operand2) except Exception, e: self.compile_time_value_error(e) def analyse_operation(self, env): if self.cdivision or env.directives['cdivision']: self.ctruedivision = False else: self.ctruedivision = self.truedivision NumBinopNode.analyse_operation(self, env) if self.is_cpp_operation(): self.cdivision = True if not self.type.is_pyobject: self.zerodivision_check = ( self.cdivision is None and not env.directives['cdivision'] and (not self.operand2.has_constant_result() or self.operand2.constant_result == 0)) if self.zerodivision_check or env.directives['cdivision_warnings']: # Need to check ahead of time to warn or raise zero division error self.operand1 = self.operand1.coerce_to_simple(env) self.operand2 = self.operand2.coerce_to_simple(env) def compute_c_result_type(self, type1, type2): if self.operator == '/' and self.ctruedivision: if not type1.is_float and not type2.is_float: widest_type = PyrexTypes.widest_numeric_type(type1, PyrexTypes.c_double_type) widest_type = PyrexTypes.widest_numeric_type(type2, widest_type) return widest_type return NumBinopNode.compute_c_result_type(self, type1, type2) def zero_division_message(self): if self.type.is_int: return "integer division or modulo by zero" else: return "float division" def generate_evaluation_code(self, code): if not self.type.is_pyobject and not self.type.is_complex: if self.cdivision is None: self.cdivision = (code.globalstate.directives['cdivision'] or not self.type.signed or self.type.is_float) if not self.cdivision: code.globalstate.use_utility_code(div_int_utility_code.specialize(self.type)) NumBinopNode.generate_evaluation_code(self, code) self.generate_div_warning_code(code) def generate_div_warning_code(self, code): if not self.type.is_pyobject: if self.zerodivision_check: if not self.infix: zero_test = "%s(%s)" % (self.type.unary_op('zero'), self.operand2.result()) else: zero_test = "%s == 0" % self.operand2.result() code.putln("if (unlikely(%s)) {" % zero_test) code.put_ensure_gil() code.putln('PyErr_SetString(PyExc_ZeroDivisionError, "%s");' % self.zero_division_message()) code.put_release_ensured_gil() code.putln(code.error_goto(self.pos)) code.putln("}") if self.type.is_int and self.type.signed and self.operator != '%': code.globalstate.use_utility_code(division_overflow_test_code) if self.operand2.type.signed == 2: # explicitly signed, no runtime check needed minus1_check = 'unlikely(%s == -1)' % self.operand2.result() else: type_of_op2 = self.operand2.type.declaration_code('') minus1_check = '(!(((%s)-1) > 0)) && unlikely(%s == (%s)-1)' % ( type_of_op2, self.operand2.result(), type_of_op2) code.putln("else if (sizeof(%s) == sizeof(long) && %s " " && unlikely(UNARY_NEG_WOULD_OVERFLOW(%s))) {" % ( self.type.declaration_code(''), minus1_check, self.operand1.result())) code.put_ensure_gil() code.putln('PyErr_SetString(PyExc_OverflowError, "value too large to perform division");') code.put_release_ensured_gil() code.putln(code.error_goto(self.pos)) code.putln("}") if code.globalstate.directives['cdivision_warnings'] and self.operator != '/': code.globalstate.use_utility_code(cdivision_warning_utility_code) code.putln("if (unlikely((%s < 0) ^ (%s < 0))) {" % ( self.operand1.result(), self.operand2.result())) code.put_ensure_gil() code.putln(code.set_error_info(self.pos, used=True)) code.putln("if (__Pyx_cdivision_warning(%(FILENAME)s, " "%(LINENO)s)) {" % { 'FILENAME': Naming.filename_cname, 'LINENO': Naming.lineno_cname, }) code.put_release_ensured_gil() code.put_goto(code.error_label) code.putln("}") code.put_release_ensured_gil() code.putln("}") def calculate_result_code(self): if self.type.is_complex: return NumBinopNode.calculate_result_code(self) elif self.type.is_float and self.operator == '//': return "floor(%s / %s)" % ( self.operand1.result(), self.operand2.result()) elif self.truedivision or self.cdivision: op1 = self.operand1.result() op2 = self.operand2.result() if self.truedivision: if self.type != self.operand1.type: op1 = self.type.cast_code(op1) if self.type != self.operand2.type: op2 = self.type.cast_code(op2) return "(%s / %s)" % (op1, op2) else: return "__Pyx_div_%s(%s, %s)" % ( self.type.specialization_name(), self.operand1.result(), self.operand2.result()) class ModNode(DivNode): # '%' operator. def is_py_operation_types(self, type1, type2): return (type1.is_string or type2.is_string or NumBinopNode.is_py_operation_types(self, type1, type2)) def infer_builtin_types_operation(self, type1, type2): # b'%s' % xyz raises an exception in Py3, so it's safe to infer the type for Py2 if type1 is unicode_type: # None + xyz may be implemented by RHS if type2.is_builtin_type or not self.operand1.may_be_none(): return type1 elif type1 in (bytes_type, str_type, basestring_type): if type2 is unicode_type: return type2 elif type2.is_numeric: return type1 elif type1 is bytes_type and not type2.is_builtin_type: return None # RHS might implement '% operator differently in Py3 else: return basestring_type # either str or unicode, can't tell return None def zero_division_message(self): if self.type.is_int: return "integer division or modulo by zero" else: return "float divmod()" def analyse_operation(self, env): DivNode.analyse_operation(self, env) if not self.type.is_pyobject: if self.cdivision is None: self.cdivision = env.directives['cdivision'] or not self.type.signed if not self.cdivision and not self.type.is_int and not self.type.is_float: error(self.pos, "mod operator not supported for type '%s'" % self.type) def generate_evaluation_code(self, code): if not self.type.is_pyobject and not self.cdivision: if self.type.is_int: code.globalstate.use_utility_code( mod_int_utility_code.specialize(self.type)) else: # float code.globalstate.use_utility_code( mod_float_utility_code.specialize( self.type, math_h_modifier=self.type.math_h_modifier)) # note: skipping over DivNode here NumBinopNode.generate_evaluation_code(self, code) self.generate_div_warning_code(code) def calculate_result_code(self): if self.cdivision: if self.type.is_float: return "fmod%s(%s, %s)" % ( self.type.math_h_modifier, self.operand1.result(), self.operand2.result()) else: return "(%s %% %s)" % ( self.operand1.result(), self.operand2.result()) else: return "__Pyx_mod_%s(%s, %s)" % ( self.type.specialization_name(), self.operand1.result(), self.operand2.result()) def py_operation_function(self): if self.operand1.type is unicode_type: if self.operand1.may_be_none(): return '__Pyx_PyUnicode_FormatSafe' else: return 'PyUnicode_Format' elif self.operand1.type is str_type: if self.operand1.may_be_none(): return '__Pyx_PyString_FormatSafe' else: return '__Pyx_PyString_Format' return super(ModNode, self).py_operation_function() class PowNode(NumBinopNode): # '**' operator. def analyse_c_operation(self, env): NumBinopNode.analyse_c_operation(self, env) if self.type.is_complex: if self.type.real_type.is_float: self.operand1 = self.operand1.coerce_to(self.type, env) self.operand2 = self.operand2.coerce_to(self.type, env) self.pow_func = "__Pyx_c_pow" + self.type.real_type.math_h_modifier else: error(self.pos, "complex int powers not supported") self.pow_func = "" elif self.type.is_float: self.pow_func = "pow" + self.type.math_h_modifier elif self.type.is_int: self.pow_func = "__Pyx_pow_%s" % self.type.declaration_code('').replace(' ', '_') env.use_utility_code( int_pow_utility_code.specialize( func_name=self.pow_func, type=self.type.declaration_code(''), signed=self.type.signed and 1 or 0)) elif not self.type.is_error: error(self.pos, "got unexpected types for C power operator: %s, %s" % (self.operand1.type, self.operand2.type)) def calculate_result_code(self): # Work around MSVC overloading ambiguity. def typecast(operand): if self.type == operand.type: return operand.result() else: return self.type.cast_code(operand.result()) return "%s(%s, %s)" % ( self.pow_func, typecast(self.operand1), typecast(self.operand2)) # Note: This class is temporarily "shut down" into an ineffective temp # allocation mode. # # More sophisticated temp reuse was going on before, one could have a # look at adding this again after /all/ classes are converted to the # new temp scheme. (The temp juggling cannot work otherwise). class BoolBinopNode(ExprNode): # Short-circuiting boolean operation. # # operator string # operand1 ExprNode # operand2 ExprNode subexprs = ['operand1', 'operand2'] def infer_type(self, env): type1 = self.operand1.infer_type(env) type2 = self.operand2.infer_type(env) return PyrexTypes.independent_spanning_type(type1, type2) def may_be_none(self): if self.operator == 'or': return self.operand2.may_be_none() else: return self.operand1.may_be_none() or self.operand2.may_be_none() def calculate_constant_result(self): if self.operator == 'and': self.constant_result = \ self.operand1.constant_result and \ self.operand2.constant_result else: self.constant_result = \ self.operand1.constant_result or \ self.operand2.constant_result def compile_time_value(self, denv): if self.operator == 'and': return self.operand1.compile_time_value(denv) \ and self.operand2.compile_time_value(denv) else: return self.operand1.compile_time_value(denv) \ or self.operand2.compile_time_value(denv) def coerce_to_boolean(self, env): return BoolBinopNode( self.pos, operator = self.operator, operand1 = self.operand1.coerce_to_boolean(env), operand2 = self.operand2.coerce_to_boolean(env), type = PyrexTypes.c_bint_type, is_temp = self.is_temp) def analyse_types(self, env): self.operand1 = self.operand1.analyse_types(env) self.operand2 = self.operand2.analyse_types(env) self.type = PyrexTypes.independent_spanning_type(self.operand1.type, self.operand2.type) self.operand1 = self.operand1.coerce_to(self.type, env) self.operand2 = self.operand2.coerce_to(self.type, env) # For what we're about to do, it's vital that # both operands be temp nodes. self.operand1 = self.operand1.coerce_to_simple(env) self.operand2 = self.operand2.coerce_to_simple(env) self.is_temp = 1 return self gil_message = "Truth-testing Python object" def check_const(self): return self.operand1.check_const() and self.operand2.check_const() def generate_evaluation_code(self, code): code.mark_pos(self.pos) self.operand1.generate_evaluation_code(code) test_result, uses_temp = self.generate_operand1_test(code) if self.operator == 'and': sense = "" else: sense = "!" code.putln( "if (%s%s) {" % ( sense, test_result)) if uses_temp: code.funcstate.release_temp(test_result) self.operand1.generate_disposal_code(code) self.operand2.generate_evaluation_code(code) self.allocate_temp_result(code) self.operand2.make_owned_reference(code) code.putln("%s = %s;" % (self.result(), self.operand2.result())) self.operand2.generate_post_assignment_code(code) self.operand2.free_temps(code) code.putln("} else {") self.operand1.make_owned_reference(code) code.putln("%s = %s;" % (self.result(), self.operand1.result())) self.operand1.generate_post_assignment_code(code) self.operand1.free_temps(code) code.putln("}") def generate_operand1_test(self, code): # Generate code to test the truth of the first operand. if self.type.is_pyobject: test_result = code.funcstate.allocate_temp(PyrexTypes.c_bint_type, manage_ref=False) code.putln( "%s = __Pyx_PyObject_IsTrue(%s); %s" % ( test_result, self.operand1.py_result(), code.error_goto_if_neg(test_result, self.pos))) else: test_result = self.operand1.result() return (test_result, self.type.is_pyobject) class CondExprNode(ExprNode): # Short-circuiting conditional expression. # # test ExprNode # true_val ExprNode # false_val ExprNode true_val = None false_val = None subexprs = ['test', 'true_val', 'false_val'] def type_dependencies(self, env): return self.true_val.type_dependencies(env) + self.false_val.type_dependencies(env) def infer_type(self, env): return PyrexTypes.independent_spanning_type( self.true_val.infer_type(env), self.false_val.infer_type(env)) def calculate_constant_result(self): if self.test.constant_result: self.constant_result = self.true_val.constant_result else: self.constant_result = self.false_val.constant_result def analyse_types(self, env): self.test = self.test.analyse_types(env).coerce_to_boolean(env) self.true_val = self.true_val.analyse_types(env) self.false_val = self.false_val.analyse_types(env) self.is_temp = 1 return self.analyse_result_type(env) def analyse_result_type(self, env): self.type = PyrexTypes.independent_spanning_type( self.true_val.type, self.false_val.type) if self.type.is_pyobject: self.result_ctype = py_object_type if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject: self.true_val = self.true_val.coerce_to(self.type, env) self.false_val = self.false_val.coerce_to(self.type, env) if self.type == PyrexTypes.error_type: self.type_error() return self def coerce_to(self, dst_type, env): self.true_val = self.true_val.coerce_to(dst_type, env) self.false_val = self.false_val.coerce_to(dst_type, env) self.result_ctype = None return self.analyse_result_type(env) def type_error(self): if not (self.true_val.type.is_error or self.false_val.type.is_error): error(self.pos, "Incompatible types in conditional expression (%s; %s)" % (self.true_val.type, self.false_val.type)) self.type = PyrexTypes.error_type def check_const(self): return (self.test.check_const() and self.true_val.check_const() and self.false_val.check_const()) def generate_evaluation_code(self, code): # Because subexprs may not be evaluated we can use a more optimal # subexpr allocation strategy than the default, so override evaluation_code. code.mark_pos(self.pos) self.allocate_temp_result(code) self.test.generate_evaluation_code(code) code.putln("if (%s) {" % self.test.result() ) self.eval_and_get(code, self.true_val) code.putln("} else {") self.eval_and_get(code, self.false_val) code.putln("}") self.test.generate_disposal_code(code) self.test.free_temps(code) def eval_and_get(self, code, expr): expr.generate_evaluation_code(code) expr.make_owned_reference(code) code.putln('%s = %s;' % (self.result(), expr.result_as(self.ctype()))) expr.generate_post_assignment_code(code) expr.free_temps(code) richcmp_constants = { "<" : "Py_LT", "<=": "Py_LE", "==": "Py_EQ", "!=": "Py_NE", "<>": "Py_NE", ">" : "Py_GT", ">=": "Py_GE", # the following are faked by special compare functions "in" : "Py_EQ", "not_in": "Py_NE", } class CmpNode(object): # Mixin class containing code common to PrimaryCmpNodes # and CascadedCmpNodes. special_bool_cmp_function = None special_bool_cmp_utility_code = None def infer_type(self, env): # TODO: Actually implement this (after merging with -unstable). return py_object_type def calculate_cascaded_constant_result(self, operand1_result): func = compile_time_binary_operators[self.operator] operand2_result = self.operand2.constant_result if (isinstance(operand1_result, (bytes, unicode)) and isinstance(operand2_result, (bytes, unicode)) and type(operand1_result) != type(operand2_result)): # string comparison of different types isn't portable return if self.operator in ('in', 'not_in'): if isinstance(self.operand2, (ListNode, TupleNode, SetNode)): if not self.operand2.args: self.constant_result = self.operator == 'not_in' return elif isinstance(self.operand2, ListNode) and not self.cascade: # tuples are more efficient to store than lists self.operand2 = self.operand2.as_tuple() elif isinstance(self.operand2, DictNode): if not self.operand2.key_value_pairs: self.constant_result = self.operator == 'not_in' return self.constant_result = func(operand1_result, operand2_result) def cascaded_compile_time_value(self, operand1, denv): func = get_compile_time_binop(self) operand2 = self.operand2.compile_time_value(denv) try: result = func(operand1, operand2) except Exception, e: self.compile_time_value_error(e) result = None if result: cascade = self.cascade if cascade: result = result and cascade.cascaded_compile_time_value(operand2, denv) return result def is_cpp_comparison(self): return self.operand1.type.is_cpp_class or self.operand2.type.is_cpp_class def find_common_int_type(self, env, op, operand1, operand2): # type1 != type2 and at least one of the types is not a C int type1 = operand1.type type2 = operand2.type type1_can_be_int = False type2_can_be_int = False if operand1.is_string_literal and operand1.can_coerce_to_char_literal(): type1_can_be_int = True if operand2.is_string_literal and operand2.can_coerce_to_char_literal(): type2_can_be_int = True if type1.is_int: if type2_can_be_int: return type1 elif type2.is_int: if type1_can_be_int: return type2 elif type1_can_be_int: if type2_can_be_int: if Builtin.unicode_type in (type1, type2): return PyrexTypes.c_py_ucs4_type else: return PyrexTypes.c_uchar_type return None def find_common_type(self, env, op, operand1, common_type=None): operand2 = self.operand2 type1 = operand1.type type2 = operand2.type new_common_type = None # catch general errors if type1 == str_type and (type2.is_string or type2 in (bytes_type, unicode_type)) or \ type2 == str_type and (type1.is_string or type1 in (bytes_type, unicode_type)): error(self.pos, "Comparisons between bytes/unicode and str are not portable to Python 3") new_common_type = error_type # try to use numeric comparisons where possible elif type1.is_complex or type2.is_complex: if op not in ('==', '!=') \ and (type1.is_complex or type1.is_numeric) \ and (type2.is_complex or type2.is_numeric): error(self.pos, "complex types are unordered") new_common_type = error_type elif type1.is_pyobject: new_common_type = type1 elif type2.is_pyobject: new_common_type = type2 else: new_common_type = PyrexTypes.widest_numeric_type(type1, type2) elif type1.is_numeric and type2.is_numeric: new_common_type = PyrexTypes.widest_numeric_type(type1, type2) elif common_type is None or not common_type.is_pyobject: new_common_type = self.find_common_int_type(env, op, operand1, operand2) if new_common_type is None: # fall back to generic type compatibility tests if type1 == type2: new_common_type = type1 elif type1.is_pyobject or type2.is_pyobject: if type2.is_numeric or type2.is_string: if operand2.check_for_coercion_error(type1, env): new_common_type = error_type else: new_common_type = py_object_type elif type1.is_numeric or type1.is_string: if operand1.check_for_coercion_error(type2, env): new_common_type = error_type else: new_common_type = py_object_type elif py_object_type.assignable_from(type1) and py_object_type.assignable_from(type2): new_common_type = py_object_type else: # one Python type and one non-Python type, not assignable self.invalid_types_error(operand1, op, operand2) new_common_type = error_type elif type1.assignable_from(type2): new_common_type = type1 elif type2.assignable_from(type1): new_common_type = type2 else: # C types that we couldn't handle up to here are an error self.invalid_types_error(operand1, op, operand2) new_common_type = error_type if new_common_type.is_string and (isinstance(operand1, BytesNode) or isinstance(operand2, BytesNode)): # special case when comparing char* to bytes literal: must # compare string values! new_common_type = bytes_type # recursively merge types if common_type is None or new_common_type.is_error: common_type = new_common_type else: # we could do a lot better by splitting the comparison # into a non-Python part and a Python part, but this is # safer for now common_type = PyrexTypes.spanning_type(common_type, new_common_type) if self.cascade: common_type = self.cascade.find_common_type(env, self.operator, operand2, common_type) return common_type def invalid_types_error(self, operand1, op, operand2): error(self.pos, "Invalid types for '%s' (%s, %s)" % (op, operand1.type, operand2.type)) def is_python_comparison(self): return (not self.is_ptr_contains() and not self.is_c_string_contains() and (self.has_python_operands() or (self.cascade and self.cascade.is_python_comparison()) or self.operator in ('in', 'not_in'))) def coerce_operands_to(self, dst_type, env): operand2 = self.operand2 if operand2.type != dst_type: self.operand2 = operand2.coerce_to(dst_type, env) if self.cascade: self.cascade.coerce_operands_to(dst_type, env) def is_python_result(self): return ((self.has_python_operands() and self.special_bool_cmp_function is None and self.operator not in ('is', 'is_not', 'in', 'not_in') and not self.is_c_string_contains() and not self.is_ptr_contains()) or (self.cascade and self.cascade.is_python_result())) def is_c_string_contains(self): return self.operator in ('in', 'not_in') and \ ((self.operand1.type.is_int and (self.operand2.type.is_string or self.operand2.type is bytes_type)) or (self.operand1.type.is_unicode_char and self.operand2.type is unicode_type)) def is_ptr_contains(self): if self.operator in ('in', 'not_in'): container_type = self.operand2.type return (container_type.is_ptr or container_type.is_array) \ and not container_type.is_string def find_special_bool_compare_function(self, env, operand1, result_is_bool=False): # note: currently operand1 must get coerced to a Python object if we succeed here! if self.operator in ('==', '!='): type1, type2 = operand1.type, self.operand2.type if result_is_bool or (type1.is_builtin_type and type2.is_builtin_type): if type1 is Builtin.unicode_type or type2 is Builtin.unicode_type: self.special_bool_cmp_utility_code = UtilityCode.load_cached("UnicodeEquals", "StringTools.c") self.special_bool_cmp_function = "__Pyx_PyUnicode_Equals" return True elif type1 is Builtin.bytes_type or type2 is Builtin.bytes_type: self.special_bool_cmp_utility_code = UtilityCode.load_cached("BytesEquals", "StringTools.c") self.special_bool_cmp_function = "__Pyx_PyBytes_Equals" return True elif type1 is Builtin.basestring_type or type2 is Builtin.basestring_type: self.special_bool_cmp_utility_code = UtilityCode.load_cached("UnicodeEquals", "StringTools.c") self.special_bool_cmp_function = "__Pyx_PyUnicode_Equals" return True elif type1 is Builtin.str_type or type2 is Builtin.str_type: self.special_bool_cmp_utility_code = UtilityCode.load_cached("StrEquals", "StringTools.c") self.special_bool_cmp_function = "__Pyx_PyString_Equals" return True elif self.operator in ('in', 'not_in'): if self.operand2.type is Builtin.dict_type: self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable") self.special_bool_cmp_utility_code = UtilityCode.load_cached("PyDictContains", "ObjectHandling.c") self.special_bool_cmp_function = "__Pyx_PyDict_Contains" return True elif self.operand2.type is Builtin.unicode_type: self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable") self.special_bool_cmp_utility_code = UtilityCode.load_cached("PyUnicodeContains", "StringTools.c") self.special_bool_cmp_function = "__Pyx_PyUnicode_Contains" return True else: if not self.operand2.type.is_pyobject: self.operand2 = self.operand2.coerce_to_pyobject(env) self.special_bool_cmp_utility_code = UtilityCode.load_cached("PySequenceContains", "ObjectHandling.c") self.special_bool_cmp_function = "__Pyx_PySequence_Contains" return True return False def generate_operation_code(self, code, result_code, operand1, op , operand2): if self.type.is_pyobject: error_clause = code.error_goto_if_null got_ref = "__Pyx_XGOTREF(%s); " % result_code if self.special_bool_cmp_function: code.globalstate.use_utility_code( UtilityCode.load_cached("PyBoolOrNullFromLong", "ObjectHandling.c")) coerce_result = "__Pyx_PyBoolOrNull_FromLong" else: coerce_result = "__Pyx_PyBool_FromLong" else: error_clause = code.error_goto_if_neg got_ref = "" coerce_result = "" if self.special_bool_cmp_function: if operand1.type.is_pyobject: result1 = operand1.py_result() else: result1 = operand1.result() if operand2.type.is_pyobject: result2 = operand2.py_result() else: result2 = operand2.result() if self.special_bool_cmp_utility_code: code.globalstate.use_utility_code(self.special_bool_cmp_utility_code) code.putln( "%s = %s(%s(%s, %s, %s)); %s%s" % ( result_code, coerce_result, self.special_bool_cmp_function, result1, result2, richcmp_constants[op], got_ref, error_clause(result_code, self.pos))) elif operand1.type.is_pyobject and op not in ('is', 'is_not'): assert op not in ('in', 'not_in'), op code.putln("%s = PyObject_RichCompare(%s, %s, %s); %s%s" % ( result_code, operand1.py_result(), operand2.py_result(), richcmp_constants[op], got_ref, error_clause(result_code, self.pos))) elif operand1.type.is_complex: code.putln("%s = %s(%s%s(%s, %s));" % ( result_code, coerce_result, op == "!=" and "!" or "", operand1.type.unary_op('eq'), operand1.result(), operand2.result())) else: type1 = operand1.type type2 = operand2.type if (type1.is_extension_type or type2.is_extension_type) \ and not type1.same_as(type2): common_type = py_object_type elif type1.is_numeric: common_type = PyrexTypes.widest_numeric_type(type1, type2) else: common_type = type1 code1 = operand1.result_as(common_type) code2 = operand2.result_as(common_type) code.putln("%s = %s(%s %s %s);" % ( result_code, coerce_result, code1, self.c_operator(op), code2)) def c_operator(self, op): if op == 'is': return "==" elif op == 'is_not': return "!=" else: return op class PrimaryCmpNode(ExprNode, CmpNode): # Non-cascaded comparison or first comparison of # a cascaded sequence. # # operator string # operand1 ExprNode # operand2 ExprNode # cascade CascadedCmpNode # We don't use the subexprs mechanism, because # things here are too complicated for it to handle. # Instead, we override all the framework methods # which use it. child_attrs = ['operand1', 'operand2', 'coerced_operand2', 'cascade'] cascade = None coerced_operand2 = None is_memslice_nonecheck = False def infer_type(self, env): # TODO: Actually implement this (after merging with -unstable). return py_object_type def type_dependencies(self, env): return () def calculate_constant_result(self): assert not self.cascade self.calculate_cascaded_constant_result(self.operand1.constant_result) def compile_time_value(self, denv): operand1 = self.operand1.compile_time_value(denv) return self.cascaded_compile_time_value(operand1, denv) def analyse_types(self, env): self.operand1 = self.operand1.analyse_types(env) self.operand2 = self.operand2.analyse_types(env) if self.is_cpp_comparison(): self.analyse_cpp_comparison(env) if self.cascade: error(self.pos, "Cascading comparison not yet supported for cpp types.") return self if self.analyse_memoryviewslice_comparison(env): return self if self.cascade: self.cascade = self.cascade.analyse_types(env) if self.operator in ('in', 'not_in'): if self.is_c_string_contains(): self.is_pycmp = False common_type = None if self.cascade: error(self.pos, "Cascading comparison not yet supported for 'int_val in string'.") return self if self.operand2.type is unicode_type: env.use_utility_code(UtilityCode.load_cached("PyUCS4InUnicode", "StringTools.c")) else: if self.operand1.type is PyrexTypes.c_uchar_type: self.operand1 = self.operand1.coerce_to(PyrexTypes.c_char_type, env) if self.operand2.type is not bytes_type: self.operand2 = self.operand2.coerce_to(bytes_type, env) env.use_utility_code(UtilityCode.load_cached("BytesContains", "StringTools.c")) self.operand2 = self.operand2.as_none_safe_node( "argument of type 'NoneType' is not iterable") elif self.is_ptr_contains(): if self.cascade: error(self.pos, "Cascading comparison not supported for 'val in sliced pointer'.") self.type = PyrexTypes.c_bint_type # Will be transformed by IterationTransform return self elif self.find_special_bool_compare_function(env, self.operand1): if not self.operand1.type.is_pyobject: self.operand1 = self.operand1.coerce_to_pyobject(env) common_type = None # if coercion needed, the method call above has already done it self.is_pycmp = False # result is bint else: common_type = py_object_type self.is_pycmp = True elif self.find_special_bool_compare_function(env, self.operand1): if not self.operand1.type.is_pyobject: self.operand1 = self.operand1.coerce_to_pyobject(env) common_type = None # if coercion needed, the method call above has already done it self.is_pycmp = False # result is bint else: common_type = self.find_common_type(env, self.operator, self.operand1) self.is_pycmp = common_type.is_pyobject if common_type is not None and not common_type.is_error: if self.operand1.type != common_type: self.operand1 = self.operand1.coerce_to(common_type, env) self.coerce_operands_to(common_type, env) if self.cascade: self.operand2 = self.operand2.coerce_to_simple(env) self.cascade.coerce_cascaded_operands_to_temp(env) operand2 = self.cascade.optimise_comparison(self.operand2, env) if operand2 is not self.operand2: self.coerced_operand2 = operand2 if self.is_python_result(): self.type = PyrexTypes.py_object_type else: self.type = PyrexTypes.c_bint_type cdr = self.cascade while cdr: cdr.type = self.type cdr = cdr.cascade if self.is_pycmp or self.cascade or self.special_bool_cmp_function: # 1) owned reference, 2) reused value, 3) potential function error return value self.is_temp = 1 return self def analyse_cpp_comparison(self, env): type1 = self.operand1.type type2 = self.operand2.type entry = env.lookup_operator(self.operator, [self.operand1, self.operand2]) if entry is None: error(self.pos, "Invalid types for '%s' (%s, %s)" % (self.operator, type1, type2)) self.type = PyrexTypes.error_type self.result_code = "" return func_type = entry.type if func_type.is_ptr: func_type = func_type.base_type if len(func_type.args) == 1: self.operand2 = self.operand2.coerce_to(func_type.args[0].type, env) else: self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env) self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env) self.is_pycmp = False self.type = func_type.return_type def analyse_memoryviewslice_comparison(self, env): have_none = self.operand1.is_none or self.operand2.is_none have_slice = (self.operand1.type.is_memoryviewslice or self.operand2.type.is_memoryviewslice) ops = ('==', '!=', 'is', 'is_not') if have_slice and have_none and self.operator in ops: self.is_pycmp = False self.type = PyrexTypes.c_bint_type self.is_memslice_nonecheck = True return True return False def coerce_to_boolean(self, env): if self.is_pycmp: # coercing to bool => may allow for more efficient comparison code if self.find_special_bool_compare_function( env, self.operand1, result_is_bool=True): self.is_pycmp = False self.type = PyrexTypes.c_bint_type self.is_temp = 1 if self.cascade: operand2 = self.cascade.optimise_comparison( self.operand2, env, result_is_bool=True) if operand2 is not self.operand2: self.coerced_operand2 = operand2 return self # TODO: check if we can optimise parts of the cascade here return ExprNode.coerce_to_boolean(self, env) def has_python_operands(self): return (self.operand1.type.is_pyobject or self.operand2.type.is_pyobject) def check_const(self): if self.cascade: self.not_const() return False else: return self.operand1.check_const() and self.operand2.check_const() def calculate_result_code(self): if self.operand1.type.is_complex: if self.operator == "!=": negation = "!" else: negation = "" return "(%s%s(%s, %s))" % ( negation, self.operand1.type.binary_op('=='), self.operand1.result(), self.operand2.result()) elif self.is_c_string_contains(): if self.operand2.type is unicode_type: method = "__Pyx_UnicodeContainsUCS4" else: method = "__Pyx_BytesContains" if self.operator == "not_in": negation = "!" else: negation = "" return "(%s%s(%s, %s))" % ( negation, method, self.operand2.result(), self.operand1.result()) else: result1 = self.operand1.result() result2 = self.operand2.result() if self.is_memslice_nonecheck: if self.operand1.type.is_memoryviewslice: result1 = "((PyObject *) %s.memview)" % result1 else: result2 = "((PyObject *) %s.memview)" % result2 return "(%s %s %s)" % ( result1, self.c_operator(self.operator), result2) def generate_evaluation_code(self, code): self.operand1.generate_evaluation_code(code) self.operand2.generate_evaluation_code(code) if self.is_temp: self.allocate_temp_result(code) self.generate_operation_code(code, self.result(), self.operand1, self.operator, self.operand2) if self.cascade: self.cascade.generate_evaluation_code( code, self.result(), self.coerced_operand2 or self.operand2, needs_evaluation=self.coerced_operand2 is not None) self.operand1.generate_disposal_code(code) self.operand1.free_temps(code) self.operand2.generate_disposal_code(code) self.operand2.free_temps(code) def generate_subexpr_disposal_code(self, code): # If this is called, it is a non-cascaded cmp, # so only need to dispose of the two main operands. self.operand1.generate_disposal_code(code) self.operand2.generate_disposal_code(code) def free_subexpr_temps(self, code): # If this is called, it is a non-cascaded cmp, # so only need to dispose of the two main operands. self.operand1.free_temps(code) self.operand2.free_temps(code) def annotate(self, code): self.operand1.annotate(code) self.operand2.annotate(code) if self.cascade: self.cascade.annotate(code) class CascadedCmpNode(Node, CmpNode): # A CascadedCmpNode is not a complete expression node. It # hangs off the side of another comparison node, shares # its left operand with that node, and shares its result # with the PrimaryCmpNode at the head of the chain. # # operator string # operand2 ExprNode # cascade CascadedCmpNode child_attrs = ['operand2', 'coerced_operand2', 'cascade'] cascade = None coerced_operand2 = None constant_result = constant_value_not_set # FIXME: where to calculate this? def infer_type(self, env): # TODO: Actually implement this (after merging with -unstable). return py_object_type def type_dependencies(self, env): return () def has_constant_result(self): return self.constant_result is not constant_value_not_set and \ self.constant_result is not not_a_constant def analyse_types(self, env): self.operand2 = self.operand2.analyse_types(env) if self.cascade: self.cascade = self.cascade.analyse_types(env) return self def has_python_operands(self): return self.operand2.type.is_pyobject def optimise_comparison(self, operand1, env, result_is_bool=False): if self.find_special_bool_compare_function(env, operand1, result_is_bool): self.is_pycmp = False self.type = PyrexTypes.c_bint_type if not operand1.type.is_pyobject: operand1 = operand1.coerce_to_pyobject(env) if self.cascade: operand2 = self.cascade.optimise_comparison(self.operand2, env, result_is_bool) if operand2 is not self.operand2: self.coerced_operand2 = operand2 return operand1 def coerce_operands_to_pyobjects(self, env): self.operand2 = self.operand2.coerce_to_pyobject(env) if self.operand2.type is dict_type and self.operator in ('in', 'not_in'): self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable") if self.cascade: self.cascade.coerce_operands_to_pyobjects(env) def coerce_cascaded_operands_to_temp(self, env): if self.cascade: #self.operand2 = self.operand2.coerce_to_temp(env) #CTT self.operand2 = self.operand2.coerce_to_simple(env) self.cascade.coerce_cascaded_operands_to_temp(env) def generate_evaluation_code(self, code, result, operand1, needs_evaluation=False): if self.type.is_pyobject: code.putln("if (__Pyx_PyObject_IsTrue(%s)) {" % result) code.put_decref(result, self.type) else: code.putln("if (%s) {" % result) if needs_evaluation: operand1.generate_evaluation_code(code) self.operand2.generate_evaluation_code(code) self.generate_operation_code(code, result, operand1, self.operator, self.operand2) if self.cascade: self.cascade.generate_evaluation_code( code, result, self.coerced_operand2 or self.operand2, needs_evaluation=self.coerced_operand2 is not None) if needs_evaluation: operand1.generate_disposal_code(code) operand1.free_temps(code) # Cascaded cmp result is always temp self.operand2.generate_disposal_code(code) self.operand2.free_temps(code) code.putln("}") def annotate(self, code): self.operand2.annotate(code) if self.cascade: self.cascade.annotate(code) binop_node_classes = { "or": BoolBinopNode, "and": BoolBinopNode, "|": IntBinopNode, "^": IntBinopNode, "&": IntBinopNode, "<<": IntBinopNode, ">>": IntBinopNode, "+": AddNode, "-": SubNode, "*": MulNode, "/": DivNode, "//": DivNode, "%": ModNode, "**": PowNode } def binop_node(pos, operator, operand1, operand2, inplace=False): # Construct binop node of appropriate class for # given operator. return binop_node_classes[operator](pos, operator = operator, operand1 = operand1, operand2 = operand2, inplace = inplace) #------------------------------------------------------------------- # # Coercion nodes # # Coercion nodes are special in that they are created during # the analyse_types phase of parse tree processing. # Their __init__ methods consequently incorporate some aspects # of that phase. # #------------------------------------------------------------------- class CoercionNode(ExprNode): # Abstract base class for coercion nodes. # # arg ExprNode node being coerced subexprs = ['arg'] constant_result = not_a_constant def __init__(self, arg): super(CoercionNode, self).__init__(arg.pos) self.arg = arg if debug_coercion: print("%s Coercing %s" % (self, self.arg)) def calculate_constant_result(self): # constant folding can break type coercion, so this is disabled pass def annotate(self, code): self.arg.annotate(code) if self.arg.type != self.type: file, line, col = self.pos code.annotate((file, line, col-1), AnnotationItem( style='coerce', tag='coerce', text='[%s] to [%s]' % (self.arg.type, self.type))) class CoerceToMemViewSliceNode(CoercionNode): """ Coerce an object to a memoryview slice. This holds a new reference in a managed temp. """ def __init__(self, arg, dst_type, env): assert dst_type.is_memoryviewslice assert not arg.type.is_memoryviewslice CoercionNode.__init__(self, arg) self.type = dst_type self.is_temp = 1 self.env = env self.use_managed_ref = True self.arg = arg def generate_result_code(self, code): self.type.create_from_py_utility_code(self.env) code.putln("%s = %s(%s);" % (self.result(), self.type.from_py_function, self.arg.py_result())) error_cond = self.type.error_condition(self.result()) code.putln(code.error_goto_if(error_cond, self.pos)) class CastNode(CoercionNode): # Wrap a node in a C type cast. def __init__(self, arg, new_type): CoercionNode.__init__(self, arg) self.type = new_type def may_be_none(self): return self.arg.may_be_none() def calculate_result_code(self): return self.arg.result_as(self.type) def generate_result_code(self, code): self.arg.generate_result_code(code) class PyTypeTestNode(CoercionNode): # This node is used to check that a generic Python # object is an instance of a particular extension type. # This node borrows the result of its argument node. exact_builtin_type = True def __init__(self, arg, dst_type, env, notnone=False): # The arg is know to be a Python object, and # the dst_type is known to be an extension type. assert dst_type.is_extension_type or dst_type.is_builtin_type, "PyTypeTest on non extension type" CoercionNode.__init__(self, arg) self.type = dst_type self.result_ctype = arg.ctype() self.notnone = notnone nogil_check = Node.gil_error gil_message = "Python type test" def analyse_types(self, env): return self def may_be_none(self): if self.notnone: return False return self.arg.may_be_none() def is_simple(self): return self.arg.is_simple() def result_in_temp(self): return self.arg.result_in_temp() def is_ephemeral(self): return self.arg.is_ephemeral() def nonlocally_immutable(self): return self.arg.nonlocally_immutable() def calculate_constant_result(self): # FIXME pass def calculate_result_code(self): return self.arg.result() def generate_result_code(self, code): if self.type.typeobj_is_available(): if self.type.is_builtin_type: type_test = self.type.type_test_code( self.arg.py_result(), self.notnone, exact=self.exact_builtin_type) else: type_test = self.type.type_test_code( self.arg.py_result(), self.notnone) code.globalstate.use_utility_code( UtilityCode.load_cached("ExtTypeTest", "ObjectHandling.c")) code.putln("if (!(%s)) %s" % ( type_test, code.error_goto(self.pos))) else: error(self.pos, "Cannot test type of extern C class " "without type object name specification") def generate_post_assignment_code(self, code): self.arg.generate_post_assignment_code(code) def free_temps(self, code): self.arg.free_temps(code) class NoneCheckNode(CoercionNode): # This node is used to check that a Python object is not None and # raises an appropriate exception (as specified by the creating # transform). is_nonecheck = True def __init__(self, arg, exception_type_cname, exception_message, exception_format_args): CoercionNode.__init__(self, arg) self.type = arg.type self.result_ctype = arg.ctype() self.exception_type_cname = exception_type_cname self.exception_message = exception_message self.exception_format_args = tuple(exception_format_args or ()) nogil_check = None # this node only guards an operation that would fail already def analyse_types(self, env): return self def may_be_none(self): return False def is_simple(self): return self.arg.is_simple() def result_in_temp(self): return self.arg.result_in_temp() def nonlocally_immutable(self): return self.arg.nonlocally_immutable() def calculate_result_code(self): return self.arg.result() def condition(self): if self.type.is_pyobject: return self.arg.py_result() elif self.type.is_memoryviewslice: return "((PyObject *) %s.memview)" % self.arg.result() else: raise Exception("unsupported type") def put_nonecheck(self, code): code.putln( "if (unlikely(%s == Py_None)) {" % self.condition()) if self.in_nogil_context: code.put_ensure_gil() escape = StringEncoding.escape_byte_string if self.exception_format_args: code.putln('PyErr_Format(%s, "%s", %s);' % ( self.exception_type_cname, StringEncoding.escape_byte_string( self.exception_message.encode('UTF-8')), ', '.join([ '"%s"' % escape(str(arg).encode('UTF-8')) for arg in self.exception_format_args ]))) else: code.putln('PyErr_SetString(%s, "%s");' % ( self.exception_type_cname, escape(self.exception_message.encode('UTF-8')))) if self.in_nogil_context: code.put_release_ensured_gil() code.putln(code.error_goto(self.pos)) code.putln("}") def generate_result_code(self, code): self.put_nonecheck(code) def generate_post_assignment_code(self, code): self.arg.generate_post_assignment_code(code) def free_temps(self, code): self.arg.free_temps(code) class CoerceToPyTypeNode(CoercionNode): # This node is used to convert a C data type # to a Python object. type = py_object_type is_temp = 1 def __init__(self, arg, env, type=py_object_type): if not arg.type.create_to_py_utility_code(env): error(arg.pos, "Cannot convert '%s' to Python object" % arg.type) elif arg.type.is_complex: # special case: complex coercion is so complex that it # uses a macro ("__pyx_PyComplex_FromComplex()"), for # which the argument must be simple arg = arg.coerce_to_simple(env) CoercionNode.__init__(self, arg) if type is py_object_type: # be specific about some known types if arg.type.is_string or arg.type.is_cpp_string: self.type = default_str_type(env) elif arg.type.is_pyunicode_ptr or arg.type.is_unicode_char: self.type = unicode_type elif arg.type.is_complex: self.type = Builtin.complex_type elif arg.type.is_string or arg.type.is_cpp_string: if (type not in (bytes_type, bytearray_type) and not env.directives['c_string_encoding']): error(arg.pos, "default encoding required for conversion from '%s' to '%s'" % (arg.type, type)) self.type = type else: # FIXME: check that the target type and the resulting type are compatible pass if arg.type.is_memoryviewslice: # Register utility codes at this point arg.type.get_to_py_function(env, arg) self.env = env gil_message = "Converting to Python object" def may_be_none(self): # FIXME: is this always safe? return False def coerce_to_boolean(self, env): arg_type = self.arg.type if (arg_type == PyrexTypes.c_bint_type or (arg_type.is_pyobject and arg_type.name == 'bool')): return self.arg.coerce_to_temp(env) else: return CoerceToBooleanNode(self, env) def coerce_to_integer(self, env): # If not already some C integer type, coerce to longint. if self.arg.type.is_int: return self.arg else: return self.arg.coerce_to(PyrexTypes.c_long_type, env) def analyse_types(self, env): # The arg is always already analysed return self def generate_result_code(self, code): arg_type = self.arg.type if arg_type.is_memoryviewslice: funccall = arg_type.get_to_py_function(self.env, self.arg) else: func = arg_type.to_py_function if arg_type.is_string or arg_type.is_cpp_string: if self.type in (bytes_type, str_type, unicode_type): func = func.replace("Object", self.type.name.title()) elif self.type is bytearray_type: func = func.replace("Object", "ByteArray") funccall = "%s(%s)" % (func, self.arg.result()) code.putln('%s = %s; %s' % ( self.result(), funccall, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) class CoerceIntToBytesNode(CoerceToPyTypeNode): # This node is used to convert a C int type to a Python bytes # object. is_temp = 1 def __init__(self, arg, env): arg = arg.coerce_to_simple(env) CoercionNode.__init__(self, arg) self.type = Builtin.bytes_type def generate_result_code(self, code): arg = self.arg arg_result = arg.result() if arg.type not in (PyrexTypes.c_char_type, PyrexTypes.c_uchar_type, PyrexTypes.c_schar_type): if arg.type.signed: code.putln("if ((%s < 0) || (%s > 255)) {" % ( arg_result, arg_result)) else: code.putln("if (%s > 255) {" % arg_result) code.putln('PyErr_SetString(PyExc_OverflowError, ' '"value too large to pack into a byte"); %s' % ( code.error_goto(self.pos))) code.putln('}') temp = None if arg.type is not PyrexTypes.c_char_type: temp = code.funcstate.allocate_temp(PyrexTypes.c_char_type, manage_ref=False) code.putln("%s = (char)%s;" % (temp, arg_result)) arg_result = temp code.putln('%s = PyBytes_FromStringAndSize(&%s, 1); %s' % ( self.result(), arg_result, code.error_goto_if_null(self.result(), self.pos))) if temp is not None: code.funcstate.release_temp(temp) code.put_gotref(self.py_result()) class CoerceFromPyTypeNode(CoercionNode): # This node is used to convert a Python object # to a C data type. def __init__(self, result_type, arg, env): CoercionNode.__init__(self, arg) self.type = result_type self.is_temp = 1 if not result_type.create_from_py_utility_code(env): error(arg.pos, "Cannot convert Python object to '%s'" % result_type) if self.type.is_string or self.type.is_pyunicode_ptr: if self.arg.is_ephemeral(): error(arg.pos, "Obtaining '%s' from temporary Python value" % result_type) elif self.arg.is_name and self.arg.entry and self.arg.entry.is_pyglobal: warning(arg.pos, "Obtaining '%s' from externally modifiable global Python value" % result_type, level=1) def analyse_types(self, env): # The arg is always already analysed return self def generate_result_code(self, code): function = self.type.from_py_function operand = self.arg.py_result() rhs = "%s(%s)" % (function, operand) if self.type.is_enum: rhs = typecast(self.type, c_long_type, rhs) code.putln('%s = %s; %s' % ( self.result(), rhs, code.error_goto_if(self.type.error_condition(self.result()), self.pos))) if self.type.is_pyobject: code.put_gotref(self.py_result()) def nogil_check(self, env): error(self.pos, "Coercion from Python not allowed without the GIL") class CoerceToBooleanNode(CoercionNode): # This node is used when a result needs to be used # in a boolean context. type = PyrexTypes.c_bint_type _special_builtins = { Builtin.list_type : 'PyList_GET_SIZE', Builtin.tuple_type : 'PyTuple_GET_SIZE', Builtin.bytes_type : 'PyBytes_GET_SIZE', Builtin.unicode_type : 'PyUnicode_GET_SIZE', } def __init__(self, arg, env): CoercionNode.__init__(self, arg) if arg.type.is_pyobject: self.is_temp = 1 def nogil_check(self, env): if self.arg.type.is_pyobject and self._special_builtins.get(self.arg.type) is None: self.gil_error() gil_message = "Truth-testing Python object" def check_const(self): if self.is_temp: self.not_const() return False return self.arg.check_const() def calculate_result_code(self): return "(%s != 0)" % self.arg.result() def generate_result_code(self, code): if not self.is_temp: return test_func = self._special_builtins.get(self.arg.type) if test_func is not None: code.putln("%s = (%s != Py_None) && (%s(%s) != 0);" % ( self.result(), self.arg.py_result(), test_func, self.arg.py_result())) else: code.putln( "%s = __Pyx_PyObject_IsTrue(%s); %s" % ( self.result(), self.arg.py_result(), code.error_goto_if_neg(self.result(), self.pos))) class CoerceToComplexNode(CoercionNode): def __init__(self, arg, dst_type, env): if arg.type.is_complex: arg = arg.coerce_to_simple(env) self.type = dst_type CoercionNode.__init__(self, arg) dst_type.create_declaration_utility_code(env) def calculate_result_code(self): if self.arg.type.is_complex: real_part = "__Pyx_CREAL(%s)" % self.arg.result() imag_part = "__Pyx_CIMAG(%s)" % self.arg.result() else: real_part = self.arg.result() imag_part = "0" return "%s(%s, %s)" % ( self.type.from_parts, real_part, imag_part) def generate_result_code(self, code): pass class CoerceToTempNode(CoercionNode): # This node is used to force the result of another node # to be stored in a temporary. It is only used if the # argument node's result is not already in a temporary. def __init__(self, arg, env): CoercionNode.__init__(self, arg) self.type = self.arg.type.as_argument_type() self.constant_result = self.arg.constant_result self.is_temp = 1 if self.type.is_pyobject: self.result_ctype = py_object_type gil_message = "Creating temporary Python reference" def analyse_types(self, env): # The arg is always already analysed return self def coerce_to_boolean(self, env): self.arg = self.arg.coerce_to_boolean(env) if self.arg.is_simple(): return self.arg self.type = self.arg.type self.result_ctype = self.type return self def generate_result_code(self, code): #self.arg.generate_evaluation_code(code) # Already done # by generic generate_subexpr_evaluation_code! code.putln("%s = %s;" % ( self.result(), self.arg.result_as(self.ctype()))) if self.use_managed_ref: if self.type.is_pyobject: code.put_incref(self.result(), self.ctype()) elif self.type.is_memoryviewslice: code.put_incref_memoryviewslice(self.result(), not self.in_nogil_context) class ProxyNode(CoercionNode): """ A node that should not be replaced by transforms or other means, and hence can be useful to wrap the argument to a clone node MyNode -> ProxyNode -> ArgNode CloneNode -^ """ nogil_check = None def __init__(self, arg): super(ProxyNode, self).__init__(arg) self.constant_result = arg.constant_result self._proxy_type() def analyse_expressions(self, env): self.arg = self.arg.analyse_expressions(env) self._proxy_type() return self def _proxy_type(self): if hasattr(self.arg, 'type'): self.type = self.arg.type self.result_ctype = self.arg.result_ctype if hasattr(self.arg, 'entry'): self.entry = self.arg.entry def generate_result_code(self, code): self.arg.generate_result_code(code) def result(self): return self.arg.result() def is_simple(self): return self.arg.is_simple() def may_be_none(self): return self.arg.may_be_none() def generate_evaluation_code(self, code): self.arg.generate_evaluation_code(code) def generate_result_code(self, code): self.arg.generate_result_code(code) def generate_disposal_code(self, code): self.arg.generate_disposal_code(code) def free_temps(self, code): self.arg.free_temps(code) class CloneNode(CoercionNode): # This node is employed when the result of another node needs # to be used multiple times. The argument node's result must # be in a temporary. This node "borrows" the result from the # argument node, and does not generate any evaluation or # disposal code for it. The original owner of the argument # node is responsible for doing those things. subexprs = [] # Arg is not considered a subexpr nogil_check = None def __init__(self, arg): CoercionNode.__init__(self, arg) self.constant_result = arg.constant_result if hasattr(arg, 'type'): self.type = arg.type self.result_ctype = arg.result_ctype if hasattr(arg, 'entry'): self.entry = arg.entry def result(self): return self.arg.result() def may_be_none(self): return self.arg.may_be_none() def type_dependencies(self, env): return self.arg.type_dependencies(env) def infer_type(self, env): return self.arg.infer_type(env) def analyse_types(self, env): self.type = self.arg.type self.result_ctype = self.arg.result_ctype self.is_temp = 1 if hasattr(self.arg, 'entry'): self.entry = self.arg.entry return self def is_simple(self): return True # result is always in a temp (or a name) def generate_evaluation_code(self, code): pass def generate_result_code(self, code): pass def generate_disposal_code(self, code): pass def free_temps(self, code): pass class CMethodSelfCloneNode(CloneNode): # Special CloneNode for the self argument of builtin C methods # that accepts subtypes of the builtin type. This is safe only # for 'final' subtypes, as subtypes of the declared type may # override the C method. def coerce_to(self, dst_type, env): if dst_type.is_builtin_type and self.type.subtype_of(dst_type): return self return CloneNode.coerce_to(self, dst_type, env) class ModuleRefNode(ExprNode): # Simple returns the module object type = py_object_type is_temp = False subexprs = [] def analyse_types(self, env): return self def may_be_none(self): return False def calculate_result_code(self): return Naming.module_cname def generate_result_code(self, code): pass class DocstringRefNode(ExprNode): # Extracts the docstring of the body element subexprs = ['body'] type = py_object_type is_temp = True def __init__(self, pos, body): ExprNode.__init__(self, pos) assert body.type.is_pyobject self.body = body def analyse_types(self, env): return self def generate_result_code(self, code): code.putln('%s = __Pyx_GetAttr(%s, %s); %s' % ( self.result(), self.body.result(), code.intern_identifier(StringEncoding.EncodedString("__doc__")), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.result()) #------------------------------------------------------------------------------------ # # Runtime support code # #------------------------------------------------------------------------------------ pyerr_occurred_withgil_utility_code= UtilityCode( proto = """ static CYTHON_INLINE int __Pyx_ErrOccurredWithGIL(void); /* proto */ """, impl = """ static CYTHON_INLINE int __Pyx_ErrOccurredWithGIL(void) { int err; #ifdef WITH_THREAD PyGILState_STATE _save = PyGILState_Ensure(); #endif err = !!PyErr_Occurred(); #ifdef WITH_THREAD PyGILState_Release(_save); #endif return err; } """ ) #------------------------------------------------------------------------------------ raise_unbound_local_error_utility_code = UtilityCode( proto = """ static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); """, impl = """ static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) { PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname); } """) raise_closure_name_error_utility_code = UtilityCode( proto = """ static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname); """, impl = """ static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname) { PyErr_Format(PyExc_NameError, "free variable '%s' referenced before assignment in enclosing scope", varname); } """) # Don't inline the function, it should really never be called in production raise_unbound_memoryview_utility_code_nogil = UtilityCode( proto = """ static void __Pyx_RaiseUnboundMemoryviewSliceNogil(const char *varname); """, impl = """ static void __Pyx_RaiseUnboundMemoryviewSliceNogil(const char *varname) { #ifdef WITH_THREAD PyGILState_STATE gilstate = PyGILState_Ensure(); #endif __Pyx_RaiseUnboundLocalError(varname); #ifdef WITH_THREAD PyGILState_Release(gilstate); #endif } """, requires = [raise_unbound_local_error_utility_code]) #------------------------------------------------------------------------------------ raise_too_many_values_to_unpack = UtilityCode.load_cached("RaiseTooManyValuesToUnpack", "ObjectHandling.c") raise_need_more_values_to_unpack = UtilityCode.load_cached("RaiseNeedMoreValuesToUnpack", "ObjectHandling.c") tuple_unpacking_error_code = UtilityCode.load_cached("UnpackTupleError", "ObjectHandling.c") #------------------------------------------------------------------------------------ int_pow_utility_code = UtilityCode( proto=""" static CYTHON_INLINE %(type)s %(func_name)s(%(type)s, %(type)s); /* proto */ """, impl=""" static CYTHON_INLINE %(type)s %(func_name)s(%(type)s b, %(type)s e) { %(type)s t = b; switch (e) { case 3: t *= b; case 2: t *= b; case 1: return t; case 0: return 1; } #if %(signed)s if (unlikely(e<0)) return 0; #endif t = 1; while (likely(e)) { t *= (b * (e&1)) | ((~e)&1); /* 1 or b */ b *= b; e >>= 1; } return t; } """) # ------------------------------ Division ------------------------------------ div_int_utility_code = UtilityCode( proto=""" static CYTHON_INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s, %(type)s); /* proto */ """, impl=""" static CYTHON_INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) { %(type)s q = a / b; %(type)s r = a - q*b; q -= ((r != 0) & ((r ^ b) < 0)); return q; } """) mod_int_utility_code = UtilityCode( proto=""" static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */ """, impl=""" static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) { %(type)s r = a %% b; r += ((r != 0) & ((r ^ b) < 0)) * b; return r; } """) mod_float_utility_code = UtilityCode( proto=""" static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */ """, impl=""" static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) { %(type)s r = fmod%(math_h_modifier)s(a, b); r += ((r != 0) & ((r < 0) ^ (b < 0))) * b; return r; } """) cdivision_warning_utility_code = UtilityCode( proto=""" static int __Pyx_cdivision_warning(const char *, int); /* proto */ """, impl=""" static int __Pyx_cdivision_warning(const char *filename, int lineno) { #if CYTHON_COMPILING_IN_PYPY filename++; // avoid compiler warnings lineno++; return PyErr_Warn(PyExc_RuntimeWarning, "division with oppositely signed operands, C and Python semantics differ"); #else return PyErr_WarnExplicit(PyExc_RuntimeWarning, "division with oppositely signed operands, C and Python semantics differ", filename, lineno, __Pyx_MODULE_NAME, NULL); #endif } """) # from intobject.c division_overflow_test_code = UtilityCode( proto=""" #define UNARY_NEG_WOULD_OVERFLOW(x) \ (((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x))) """) cython-0.20.1+git90-g0e6e38e/Cython/Compiler/FlowControl.pxd000066400000000000000000000054621231323242300232570ustar00rootroot00000000000000cimport cython from Cython.Compiler.Visitor cimport CythonTransform, TreeVisitor cdef class ControlBlock: cdef public set children cdef public set parents cdef public set positions cdef public list stats cdef public dict gen cdef public set bounded cdef public dict input cdef public dict output # Big integer it bitsets cdef public object i_input cdef public object i_output cdef public object i_gen cdef public object i_kill cdef public object i_state cpdef bint empty(self) cpdef detach(self) cpdef add_child(self, block) cdef class ExitBlock(ControlBlock): cpdef bint empty(self) cdef class NameAssignment: cdef public bint is_arg cdef public bint is_deletion cdef public object lhs cdef public object rhs cdef public object entry cdef public object pos cdef public set refs cdef public object bit cdef public object inferred_type cdef class AssignmentList: cdef public object bit cdef public object mask cdef public list stats cdef class AssignmentCollector(TreeVisitor): cdef list assignments @cython.final cdef class ControlFlow: cdef public set blocks cdef public set entries cdef public list loops cdef public list exceptions cdef public ControlBlock entry_point cdef public ExitBlock exit_point cdef public ControlBlock block cdef public dict assmts cpdef newblock(self, ControlBlock parent=*) cpdef nextblock(self, ControlBlock parent=*) cpdef bint is_tracked(self, entry) cpdef bint is_statically_assigned(self, entry) cpdef mark_position(self, node) cpdef mark_assignment(self, lhs, rhs, entry) cpdef mark_argument(self, lhs, rhs, entry) cpdef mark_deletion(self, node, entry) cpdef mark_reference(self, node, entry) @cython.locals(block=ControlBlock, parent=ControlBlock, unreachable=set) cpdef normalize(self) @cython.locals(bit=object, assmts=AssignmentList, block=ControlBlock) cpdef initialize(self) @cython.locals(assmts=AssignmentList, assmt=NameAssignment) cpdef set map_one(self, istate, entry) @cython.locals(block=ControlBlock, parent=ControlBlock) cdef reaching_definitions(self) cdef class Uninitialized: pass cdef class Unknown: pass @cython.locals(dirty=bint, block=ControlBlock, parent=ControlBlock, assmt=NameAssignment) cdef check_definitions(ControlFlow flow, dict compiler_directives) @cython.final cdef class ControlFlowAnalysis(CythonTransform): cdef object gv_ctx cdef set reductions cdef list env_stack cdef list stack cdef object env cdef ControlFlow flow cdef bint in_inplace_assignment cpdef mark_assignment(self, lhs, rhs=*) cpdef mark_position(self, node) cython-0.20.1+git90-g0e6e38e/Cython/Compiler/FlowControl.py000066400000000000000000001275051231323242300231170ustar00rootroot00000000000000import cython cython.declare(PyrexTypes=object, ExprNodes=object, Nodes=object, Builtin=object, InternalError=object, error=object, warning=object, py_object_type=object, unspecified_type=object, object_expr=object, object_expr_not_none=object, fake_rhs_expr=object, TypedExprNode=object) import Builtin import ExprNodes import Nodes import Options from PyrexTypes import py_object_type, unspecified_type import PyrexTypes from Visitor import TreeVisitor, CythonTransform from Errors import error, warning, InternalError class TypedExprNode(ExprNodes.ExprNode): # Used for declaring assignments of a specified type without a known entry. def __init__(self, type, may_be_none=None, pos=None): super(TypedExprNode, self).__init__(pos) self.type = type self._may_be_none = may_be_none def may_be_none(self): return self._may_be_none != False object_expr = TypedExprNode(py_object_type, may_be_none=True) object_expr_not_none = TypedExprNode(py_object_type, may_be_none=False) # Fake rhs to silence "unused variable" warning fake_rhs_expr = TypedExprNode(unspecified_type) class ControlBlock(object): """Control flow graph node. Sequence of assignments and name references. children set of children nodes parents set of parent nodes positions set of position markers stats list of block statements gen dict of assignments generated by this block bounded set of entries that are definitely bounded in this block Example: a = 1 b = a + c # 'c' is already bounded or exception here stats = [Assignment(a), NameReference(a), NameReference(c), Assignment(b)] gen = {Entry(a): Assignment(a), Entry(b): Assignment(b)} bounded = set([Entry(a), Entry(c)]) """ def __init__(self): self.children = set() self.parents = set() self.positions = set() self.stats = [] self.gen = {} self.bounded = set() self.i_input = 0 self.i_output = 0 self.i_gen = 0 self.i_kill = 0 self.i_state = 0 def empty(self): return (not self.stats and not self.positions) def detach(self): """Detach block from parents and children.""" for child in self.children: child.parents.remove(self) for parent in self.parents: parent.children.remove(self) self.parents.clear() self.children.clear() def add_child(self, block): self.children.add(block) block.parents.add(self) class ExitBlock(ControlBlock): """Non-empty exit point block.""" def empty(self): return False class AssignmentList(object): def __init__(self): self.stats = [] class ControlFlow(object): """Control-flow graph. entry_point ControlBlock entry point for this graph exit_point ControlBlock normal exit point block ControlBlock current block blocks set children nodes entries set tracked entries loops list stack for loop descriptors exceptions list stack for exception descriptors """ def __init__(self): self.blocks = set() self.entries = set() self.loops = [] self.exceptions = [] self.entry_point = ControlBlock() self.exit_point = ExitBlock() self.blocks.add(self.exit_point) self.block = self.entry_point def newblock(self, parent=None): """Create floating block linked to `parent` if given. NOTE: Block is NOT added to self.blocks """ block = ControlBlock() self.blocks.add(block) if parent: parent.add_child(block) return block def nextblock(self, parent=None): """Create block children block linked to current or `parent` if given. NOTE: Block is added to self.blocks """ block = ControlBlock() self.blocks.add(block) if parent: parent.add_child(block) elif self.block: self.block.add_child(block) self.block = block return self.block def is_tracked(self, entry): if entry.is_anonymous: return False return (entry.is_local or entry.is_pyclass_attr or entry.is_arg or entry.from_closure or entry.in_closure or entry.error_on_uninitialized) def is_statically_assigned(self, entry): if (entry.is_local and entry.is_variable and (entry.type.is_struct_or_union or entry.type.is_complex or entry.type.is_array or entry.type.is_cpp_class)): # stack allocated structured variable => never uninitialised return True return False def mark_position(self, node): """Mark position, will be used to draw graph nodes.""" if self.block: self.block.positions.add(node.pos[:2]) def mark_assignment(self, lhs, rhs, entry): if self.block and self.is_tracked(entry): assignment = NameAssignment(lhs, rhs, entry) self.block.stats.append(assignment) self.block.gen[entry] = assignment self.entries.add(entry) def mark_argument(self, lhs, rhs, entry): if self.block and self.is_tracked(entry): assignment = Argument(lhs, rhs, entry) self.block.stats.append(assignment) self.block.gen[entry] = assignment self.entries.add(entry) def mark_deletion(self, node, entry): if self.block and self.is_tracked(entry): assignment = NameDeletion(node, entry) self.block.stats.append(assignment) self.block.gen[entry] = Uninitialized self.entries.add(entry) def mark_reference(self, node, entry): if self.block and self.is_tracked(entry): self.block.stats.append(NameReference(node, entry)) ## XXX: We don't track expression evaluation order so we can't use ## XXX: successful reference as initialization sign. ## # Local variable is definitely bound after this reference ## if not node.allow_null: ## self.block.bounded.add(entry) self.entries.add(entry) def normalize(self): """Delete unreachable and orphan blocks.""" queue = set([self.entry_point]) visited = set() while queue: root = queue.pop() visited.add(root) for child in root.children: if child not in visited: queue.add(child) unreachable = self.blocks - visited for block in unreachable: block.detach() visited.remove(self.entry_point) for block in visited: if block.empty(): for parent in block.parents: # Re-parent for child in block.children: parent.add_child(child) block.detach() unreachable.add(block) self.blocks -= unreachable def initialize(self): """Set initial state, map assignments to bits.""" self.assmts = {} bit = 1 for entry in self.entries: assmts = AssignmentList() assmts.mask = assmts.bit = bit self.assmts[entry] = assmts bit <<= 1 for block in self.blocks: for stat in block.stats: if isinstance(stat, NameAssignment): stat.bit = bit assmts = self.assmts[stat.entry] assmts.stats.append(stat) assmts.mask |= bit bit <<= 1 for block in self.blocks: for entry, stat in block.gen.items(): assmts = self.assmts[entry] if stat is Uninitialized: block.i_gen |= assmts.bit else: block.i_gen |= stat.bit block.i_kill |= assmts.mask block.i_output = block.i_gen for entry in block.bounded: block.i_kill |= self.assmts[entry].bit for assmts in self.assmts.itervalues(): self.entry_point.i_gen |= assmts.bit self.entry_point.i_output = self.entry_point.i_gen def map_one(self, istate, entry): ret = set() assmts = self.assmts[entry] if istate & assmts.bit: if self.is_statically_assigned(entry): ret.add(StaticAssignment(entry)) elif entry.from_closure: ret.add(Unknown) else: ret.add(Uninitialized) for assmt in assmts.stats: if istate & assmt.bit: ret.add(assmt) return ret def reaching_definitions(self): """Per-block reaching definitions analysis.""" dirty = True while dirty: dirty = False for block in self.blocks: i_input = 0 for parent in block.parents: i_input |= parent.i_output i_output = (i_input & ~block.i_kill) | block.i_gen if i_output != block.i_output: dirty = True block.i_input = i_input block.i_output = i_output class LoopDescr(object): def __init__(self, next_block, loop_block): self.next_block = next_block self.loop_block = loop_block self.exceptions = [] class ExceptionDescr(object): """Exception handling helper. entry_point ControlBlock Exception handling entry point finally_enter ControlBlock Normal finally clause entry point finally_exit ControlBlock Normal finally clause exit point """ def __init__(self, entry_point, finally_enter=None, finally_exit=None): self.entry_point = entry_point self.finally_enter = finally_enter self.finally_exit = finally_exit class NameAssignment(object): def __init__(self, lhs, rhs, entry): if lhs.cf_state is None: lhs.cf_state = set() self.lhs = lhs self.rhs = rhs self.entry = entry self.pos = lhs.pos self.refs = set() self.is_arg = False self.is_deletion = False self.inferred_type = None def __repr__(self): return '%s(entry=%r)' % (self.__class__.__name__, self.entry) def infer_type(self): self.inferred_type = self.rhs.infer_type(self.entry.scope) return self.inferred_type def type_dependencies(self): return self.rhs.type_dependencies(self.entry.scope) @property def type(self): if not self.entry.type.is_unspecified: return self.entry.type return self.inferred_type class StaticAssignment(NameAssignment): """Initialised at declaration time, e.g. stack allocation.""" def __init__(self, entry): if not entry.type.is_pyobject: may_be_none = False else: may_be_none = None # unknown lhs = TypedExprNode( entry.type, may_be_none=may_be_none, pos=entry.pos) super(StaticAssignment, self).__init__(lhs, lhs, entry) def infer_type(self): return self.entry.type def type_dependencies(self): return () class Argument(NameAssignment): def __init__(self, lhs, rhs, entry): NameAssignment.__init__(self, lhs, rhs, entry) self.is_arg = True class NameDeletion(NameAssignment): def __init__(self, lhs, entry): NameAssignment.__init__(self, lhs, lhs, entry) self.is_deletion = True def infer_type(self): inferred_type = self.rhs.infer_type(self.entry.scope) if (not inferred_type.is_pyobject and inferred_type.can_coerce_to_pyobject(self.entry.scope)): return py_object_type self.inferred_type = inferred_type return inferred_type class Uninitialized(object): """Definitely not initialised yet.""" class Unknown(object): """Coming from outer closure, might be initialised or not.""" class NameReference(object): def __init__(self, node, entry): if node.cf_state is None: node.cf_state = set() self.node = node self.entry = entry self.pos = node.pos def __repr__(self): return '%s(entry=%r)' % (self.__class__.__name__, self.entry) class ControlFlowState(list): # Keeps track of Node's entry assignments # # cf_is_null [boolean] It is uninitialized # cf_maybe_null [boolean] May be uninitialized # is_single [boolean] Has only one assignment at this point cf_maybe_null = False cf_is_null = False is_single = False def __init__(self, state): if Uninitialized in state: state.discard(Uninitialized) self.cf_maybe_null = True if not state: self.cf_is_null = True elif Unknown in state: state.discard(Unknown) self.cf_maybe_null = True else: if len(state) == 1: self.is_single = True # XXX: Remove fake_rhs_expr super(ControlFlowState, self).__init__( [i for i in state if i.rhs is not fake_rhs_expr]) def one(self): return self[0] class GVContext(object): """Graphviz subgraph object.""" def __init__(self): self.blockids = {} self.nextid = 0 self.children = [] self.sources = {} def add(self, child): self.children.append(child) def nodeid(self, block): if block not in self.blockids: self.blockids[block] = 'block%d' % self.nextid self.nextid += 1 return self.blockids[block] def extract_sources(self, block): if not block.positions: return '' start = min(block.positions) stop = max(block.positions) srcdescr = start[0] if not srcdescr in self.sources: self.sources[srcdescr] = list(srcdescr.get_lines()) lines = self.sources[srcdescr] return '\\n'.join([l.strip() for l in lines[start[1] - 1:stop[1]]]) def render(self, fp, name, annotate_defs=False): """Render graphviz dot graph""" fp.write('digraph %s {\n' % name) fp.write(' node [shape=box];\n') for child in self.children: child.render(fp, self, annotate_defs) fp.write('}\n') def escape(self, text): return text.replace('"', '\\"').replace('\n', '\\n') class GV(object): """Graphviz DOT renderer.""" def __init__(self, name, flow): self.name = name self.flow = flow def render(self, fp, ctx, annotate_defs=False): fp.write(' subgraph %s {\n' % self.name) for block in self.flow.blocks: label = ctx.extract_sources(block) if annotate_defs: for stat in block.stats: if isinstance(stat, NameAssignment): label += '\n %s [definition]' % stat.entry.name elif isinstance(stat, NameReference): if stat.entry: label += '\n %s [reference]' % stat.entry.name if not label: label = 'empty' pid = ctx.nodeid(block) fp.write(' %s [label="%s"];\n' % (pid, ctx.escape(label))) for block in self.flow.blocks: pid = ctx.nodeid(block) for child in block.children: fp.write(' %s -> %s;\n' % (pid, ctx.nodeid(child))) fp.write(' }\n') class MessageCollection(object): """Collect error/warnings messages first then sort""" def __init__(self): self.messages = [] def error(self, pos, message): self.messages.append((pos, True, message)) def warning(self, pos, message): self.messages.append((pos, False, message)) def report(self): self.messages.sort() for pos, is_error, message in self.messages: if is_error: error(pos, message) else: warning(pos, message, 2) def check_definitions(flow, compiler_directives): flow.initialize() flow.reaching_definitions() # Track down state assignments = set() # Node to entry map references = {} assmt_nodes = set() for block in flow.blocks: i_state = block.i_input for stat in block.stats: i_assmts = flow.assmts[stat.entry] state = flow.map_one(i_state, stat.entry) if isinstance(stat, NameAssignment): stat.lhs.cf_state.update(state) assmt_nodes.add(stat.lhs) i_state = i_state & ~i_assmts.mask if stat.is_deletion: i_state |= i_assmts.bit else: i_state |= stat.bit assignments.add(stat) if stat.rhs is not fake_rhs_expr: stat.entry.cf_assignments.append(stat) elif isinstance(stat, NameReference): references[stat.node] = stat.entry stat.entry.cf_references.append(stat) stat.node.cf_state.update(state) ## if not stat.node.allow_null: ## i_state &= ~i_assmts.bit ## # after successful read, the state is known to be initialised state.discard(Uninitialized) state.discard(Unknown) for assmt in state: assmt.refs.add(stat) # Check variable usage warn_maybe_uninitialized = compiler_directives['warn.maybe_uninitialized'] warn_unused_result = compiler_directives['warn.unused_result'] warn_unused = compiler_directives['warn.unused'] warn_unused_arg = compiler_directives['warn.unused_arg'] messages = MessageCollection() # assignment hints for node in assmt_nodes: if Uninitialized in node.cf_state: node.cf_maybe_null = True if len(node.cf_state) == 1: node.cf_is_null = True else: node.cf_is_null = False elif Unknown in node.cf_state: node.cf_maybe_null = True else: node.cf_is_null = False node.cf_maybe_null = False # Find uninitialized references and cf-hints for node, entry in references.iteritems(): if Uninitialized in node.cf_state: node.cf_maybe_null = True if not entry.from_closure and len(node.cf_state) == 1: node.cf_is_null = True if (node.allow_null or entry.from_closure or entry.is_pyclass_attr or entry.type.is_error): pass # Can be uninitialized here elif node.cf_is_null: if entry.error_on_uninitialized or ( Options.error_on_uninitialized and ( entry.type.is_pyobject or entry.type.is_unspecified)): messages.error( node.pos, "local variable '%s' referenced before assignment" % entry.name) else: messages.warning( node.pos, "local variable '%s' referenced before assignment" % entry.name) elif warn_maybe_uninitialized: messages.warning( node.pos, "local variable '%s' might be referenced before assignment" % entry.name) elif Unknown in node.cf_state: # TODO: better cross-closure analysis to know when inner functions # are being called before a variable is being set, and when # a variable is known to be set before even defining the # inner function, etc. node.cf_maybe_null = True else: node.cf_is_null = False node.cf_maybe_null = False # Unused result for assmt in assignments: if (not assmt.refs and not assmt.entry.is_pyclass_attr and not assmt.entry.in_closure): if assmt.entry.cf_references and warn_unused_result: if assmt.is_arg: messages.warning(assmt.pos, "Unused argument value '%s'" % assmt.entry.name) else: messages.warning(assmt.pos, "Unused result in '%s'" % assmt.entry.name) assmt.lhs.cf_used = False # Unused entries for entry in flow.entries: if (not entry.cf_references and not entry.is_pyclass_attr): if entry.name != '_': # '_' is often used for unused variables, e.g. in loops if entry.is_arg: if warn_unused_arg: messages.warning(entry.pos, "Unused argument '%s'" % entry.name) else: if warn_unused: messages.warning(entry.pos, "Unused entry '%s'" % entry.name) entry.cf_used = False messages.report() for node in assmt_nodes: node.cf_state = ControlFlowState(node.cf_state) for node in references: node.cf_state = ControlFlowState(node.cf_state) class AssignmentCollector(TreeVisitor): def __init__(self): super(AssignmentCollector, self).__init__() self.assignments = [] def visit_Node(self): self._visitchildren(self, None) def visit_SingleAssignmentNode(self, node): self.assignments.append((node.lhs, node.rhs)) def visit_CascadedAssignmentNode(self, node): for lhs in node.lhs_list: self.assignments.append((lhs, node.rhs)) class ControlFlowAnalysis(CythonTransform): def visit_ModuleNode(self, node): self.gv_ctx = GVContext() # Set of NameNode reductions self.reductions = set() self.in_inplace_assignment = False self.env_stack = [] self.env = node.scope self.stack = [] self.flow = ControlFlow() self.visitchildren(node) check_definitions(self.flow, self.current_directives) dot_output = self.current_directives['control_flow.dot_output'] if dot_output: annotate_defs = self.current_directives['control_flow.dot_annotate_defs'] fp = open(dot_output, 'wt') try: self.gv_ctx.render(fp, 'module', annotate_defs=annotate_defs) finally: fp.close() return node def visit_FuncDefNode(self, node): for arg in node.args: if arg.default: self.visitchildren(arg) self.visitchildren(node, ('decorators',)) self.env_stack.append(self.env) self.env = node.local_scope self.stack.append(self.flow) self.flow = ControlFlow() # Collect all entries for entry in node.local_scope.entries.values(): if self.flow.is_tracked(entry): self.flow.entries.add(entry) self.mark_position(node) # Function body block self.flow.nextblock() for arg in node.args: self._visit(arg) if node.star_arg: self.flow.mark_argument(node.star_arg, TypedExprNode(Builtin.tuple_type, may_be_none=False), node.star_arg.entry) if node.starstar_arg: self.flow.mark_argument(node.starstar_arg, TypedExprNode(Builtin.dict_type, may_be_none=False), node.starstar_arg.entry) self._visit(node.body) # Workaround for generators if node.is_generator: self._visit(node.gbody.body) # Exit point if self.flow.block: self.flow.block.add_child(self.flow.exit_point) # Cleanup graph self.flow.normalize() check_definitions(self.flow, self.current_directives) self.flow.blocks.add(self.flow.entry_point) self.gv_ctx.add(GV(node.local_scope.name, self.flow)) self.flow = self.stack.pop() self.env = self.env_stack.pop() return node def visit_DefNode(self, node): node.used = True return self.visit_FuncDefNode(node) def visit_GeneratorBodyDefNode(self, node): return node def visit_CTypeDefNode(self, node): return node def mark_assignment(self, lhs, rhs=None): if not self.flow.block: return if self.flow.exceptions: exc_descr = self.flow.exceptions[-1] self.flow.block.add_child(exc_descr.entry_point) self.flow.nextblock() if not rhs: rhs = object_expr if lhs.is_name: if lhs.entry is not None: entry = lhs.entry else: entry = self.env.lookup(lhs.name) if entry is None: # TODO: This shouldn't happen... return self.flow.mark_assignment(lhs, rhs, entry) elif isinstance(lhs, ExprNodes.SequenceNode): for arg in lhs.args: self.mark_assignment(arg) else: self._visit(lhs) if self.flow.exceptions: exc_descr = self.flow.exceptions[-1] self.flow.block.add_child(exc_descr.entry_point) self.flow.nextblock() def mark_position(self, node): """Mark position if DOT output is enabled.""" if self.current_directives['control_flow.dot_output']: self.flow.mark_position(node) def visit_FromImportStatNode(self, node): for name, target in node.items: if name != "*": self.mark_assignment(target) self.visitchildren(node) return node def visit_AssignmentNode(self, node): raise InternalError("Unhandled assignment node") def visit_SingleAssignmentNode(self, node): self._visit(node.rhs) self.mark_assignment(node.lhs, node.rhs) return node def visit_CascadedAssignmentNode(self, node): self._visit(node.rhs) for lhs in node.lhs_list: self.mark_assignment(lhs, node.rhs) return node def visit_ParallelAssignmentNode(self, node): collector = AssignmentCollector() collector.visitchildren(node) for lhs, rhs in collector.assignments: self._visit(rhs) for lhs, rhs in collector.assignments: self.mark_assignment(lhs, rhs) return node def visit_InPlaceAssignmentNode(self, node): self.in_inplace_assignment = True self.visitchildren(node) self.in_inplace_assignment = False self.mark_assignment(node.lhs, node.create_binop_node()) return node def visit_DelStatNode(self, node): for arg in node.args: if arg.is_name: entry = arg.entry or self.env.lookup(arg.name) if entry.in_closure or entry.from_closure: error(arg.pos, "can not delete variable '%s' " "referenced in nested scope" % entry.name) # Mark reference self._visit(arg) self.flow.mark_deletion(arg, entry) else: self._visit(arg) return node def visit_CArgDeclNode(self, node): entry = self.env.lookup(node.name) if entry: may_be_none = not node.not_none self.flow.mark_argument( node, TypedExprNode(entry.type, may_be_none), entry) return node def visit_NameNode(self, node): if self.flow.block: entry = node.entry or self.env.lookup(node.name) if entry: self.flow.mark_reference(node, entry) if entry in self.reductions and not self.in_inplace_assignment: error(node.pos, "Cannot read reduction variable in loop body") return node def visit_StatListNode(self, node): if self.flow.block: for stat in node.stats: self._visit(stat) if not self.flow.block: stat.is_terminator = True break return node def visit_Node(self, node): self.visitchildren(node) self.mark_position(node) return node def visit_IfStatNode(self, node): next_block = self.flow.newblock() parent = self.flow.block # If clauses for clause in node.if_clauses: parent = self.flow.nextblock(parent) self._visit(clause.condition) self.flow.nextblock() self._visit(clause.body) if self.flow.block: self.flow.block.add_child(next_block) # Else clause if node.else_clause: self.flow.nextblock(parent=parent) self._visit(node.else_clause) if self.flow.block: self.flow.block.add_child(next_block) else: parent.add_child(next_block) if next_block.parents: self.flow.block = next_block else: self.flow.block = None return node def visit_WhileStatNode(self, node): condition_block = self.flow.nextblock() next_block = self.flow.newblock() # Condition block self.flow.loops.append(LoopDescr(next_block, condition_block)) if node.condition: self._visit(node.condition) # Body block self.flow.nextblock() self._visit(node.body) self.flow.loops.pop() # Loop it if self.flow.block: self.flow.block.add_child(condition_block) self.flow.block.add_child(next_block) # Else clause if node.else_clause: self.flow.nextblock(parent=condition_block) self._visit(node.else_clause) if self.flow.block: self.flow.block.add_child(next_block) else: condition_block.add_child(next_block) if next_block.parents: self.flow.block = next_block else: self.flow.block = None return node def mark_forloop_target(self, node): # TODO: Remove redundancy with range optimization... is_special = False sequence = node.iterator.sequence target = node.target if isinstance(sequence, ExprNodes.SimpleCallNode): function = sequence.function if sequence.self is None and function.is_name: entry = self.env.lookup(function.name) if not entry or entry.is_builtin: if function.name == 'reversed' and len(sequence.args) == 1: sequence = sequence.args[0] elif function.name == 'enumerate' and len(sequence.args) == 1: if target.is_sequence_constructor and len(target.args) == 2: iterator = sequence.args[0] if iterator.is_name: iterator_type = iterator.infer_type(self.env) if iterator_type.is_builtin_type: # assume that builtin types have a length within Py_ssize_t self.mark_assignment( target.args[0], ExprNodes.IntNode(target.pos, value='PY_SSIZE_T_MAX', type=PyrexTypes.c_py_ssize_t_type)) target = target.args[1] sequence = sequence.args[0] if isinstance(sequence, ExprNodes.SimpleCallNode): function = sequence.function if sequence.self is None and function.is_name: entry = self.env.lookup(function.name) if not entry or entry.is_builtin: if function.name in ('range', 'xrange'): is_special = True for arg in sequence.args[:2]: self.mark_assignment(target, arg) if len(sequence.args) > 2: self.mark_assignment( target, ExprNodes.binop_node(node.pos, '+', sequence.args[0], sequence.args[2])) if not is_special: # A for-loop basically translates to subsequent calls to # __getitem__(), so using an IndexNode here allows us to # naturally infer the base type of pointers, C arrays, # Python strings, etc., while correctly falling back to an # object type when the base type cannot be handled. self.mark_assignment(target, node.item) def visit_ForInStatNode(self, node): condition_block = self.flow.nextblock() next_block = self.flow.newblock() # Condition with iterator self.flow.loops.append(LoopDescr(next_block, condition_block)) self._visit(node.iterator) # Target assignment self.flow.nextblock() if isinstance(node, Nodes.ForInStatNode): self.mark_forloop_target(node) else: # Parallel self.mark_assignment(node.target) # Body block if isinstance(node, Nodes.ParallelRangeNode): # In case of an invalid self._delete_privates(node, exclude=node.target.entry) self.flow.nextblock() self._visit(node.body) self.flow.loops.pop() # Loop it if self.flow.block: self.flow.block.add_child(condition_block) # Else clause if node.else_clause: self.flow.nextblock(parent=condition_block) self._visit(node.else_clause) if self.flow.block: self.flow.block.add_child(next_block) else: condition_block.add_child(next_block) if next_block.parents: self.flow.block = next_block else: self.flow.block = None return node def _delete_privates(self, node, exclude=None): for private_node in node.assigned_nodes: if not exclude or private_node.entry is not exclude: self.flow.mark_deletion(private_node, private_node.entry) def visit_ParallelRangeNode(self, node): reductions = self.reductions # if node.target is None or not a NameNode, an error will have # been previously issued if hasattr(node.target, 'entry'): self.reductions = set(reductions) for private_node in node.assigned_nodes: private_node.entry.error_on_uninitialized = True pos, reduction = node.assignments[private_node.entry] if reduction: self.reductions.add(private_node.entry) node = self.visit_ForInStatNode(node) self.reductions = reductions return node def visit_ParallelWithBlockNode(self, node): for private_node in node.assigned_nodes: private_node.entry.error_on_uninitialized = True self._delete_privates(node) self.visitchildren(node) self._delete_privates(node) return node def visit_ForFromStatNode(self, node): condition_block = self.flow.nextblock() next_block = self.flow.newblock() # Condition with iterator self.flow.loops.append(LoopDescr(next_block, condition_block)) self._visit(node.bound1) self._visit(node.bound2) if node.step is not None: self._visit(node.step) # Target assignment self.flow.nextblock() self.mark_assignment(node.target, node.bound1) if node.step is not None: self.mark_assignment(node.target, ExprNodes.binop_node(node.pos, '+', node.bound1, node.step)) # Body block self.flow.nextblock() self._visit(node.body) self.flow.loops.pop() # Loop it if self.flow.block: self.flow.block.add_child(condition_block) # Else clause if node.else_clause: self.flow.nextblock(parent=condition_block) self._visit(node.else_clause) if self.flow.block: self.flow.block.add_child(next_block) else: condition_block.add_child(next_block) if next_block.parents: self.flow.block = next_block else: self.flow.block = None return node def visit_LoopNode(self, node): raise InternalError("Generic loops are not supported") def visit_WithTargetAssignmentStatNode(self, node): self.mark_assignment(node.lhs, node.rhs) return node def visit_WithStatNode(self, node): self._visit(node.manager) self._visit(node.enter_call) self._visit(node.body) return node def visit_TryExceptStatNode(self, node): # After exception handling next_block = self.flow.newblock() # Body block self.flow.newblock() # Exception entry point entry_point = self.flow.newblock() self.flow.exceptions.append(ExceptionDescr(entry_point)) self.flow.nextblock() ## XXX: links to exception handling point should be added by ## XXX: children nodes self.flow.block.add_child(entry_point) self.flow.nextblock() self._visit(node.body) self.flow.exceptions.pop() # After exception if self.flow.block: if node.else_clause: self.flow.nextblock() self._visit(node.else_clause) if self.flow.block: self.flow.block.add_child(next_block) for clause in node.except_clauses: self.flow.block = entry_point if clause.pattern: for pattern in clause.pattern: self._visit(pattern) else: # TODO: handle * pattern pass entry_point = self.flow.newblock(parent=self.flow.block) self.flow.nextblock() if clause.target: self.mark_assignment(clause.target) self._visit(clause.body) if self.flow.block: self.flow.block.add_child(next_block) if self.flow.exceptions: entry_point.add_child(self.flow.exceptions[-1].entry_point) if next_block.parents: self.flow.block = next_block else: self.flow.block = None return node def visit_TryFinallyStatNode(self, node): body_block = self.flow.nextblock() # Exception entry point entry_point = self.flow.newblock() self.flow.block = entry_point self._visit(node.finally_clause) if self.flow.block and self.flow.exceptions: self.flow.block.add_child(self.flow.exceptions[-1].entry_point) # Normal execution finally_enter = self.flow.newblock() self.flow.block = finally_enter self._visit(node.finally_clause) finally_exit = self.flow.block descr = ExceptionDescr(entry_point, finally_enter, finally_exit) self.flow.exceptions.append(descr) if self.flow.loops: self.flow.loops[-1].exceptions.append(descr) self.flow.block = body_block ## XXX: Is it still required body_block.add_child(entry_point) self.flow.nextblock() self._visit(node.body) self.flow.exceptions.pop() if self.flow.loops: self.flow.loops[-1].exceptions.pop() if self.flow.block: self.flow.block.add_child(finally_enter) if finally_exit: self.flow.block = self.flow.nextblock(parent=finally_exit) else: self.flow.block = None return node def visit_RaiseStatNode(self, node): self.mark_position(node) self.visitchildren(node) if self.flow.exceptions: self.flow.block.add_child(self.flow.exceptions[-1].entry_point) self.flow.block = None return node def visit_ReraiseStatNode(self, node): self.mark_position(node) if self.flow.exceptions: self.flow.block.add_child(self.flow.exceptions[-1].entry_point) self.flow.block = None return node def visit_ReturnStatNode(self, node): self.mark_position(node) self.visitchildren(node) for exception in self.flow.exceptions[::-1]: if exception.finally_enter: self.flow.block.add_child(exception.finally_enter) if exception.finally_exit: exception.finally_exit.add_child(self.flow.exit_point) break else: if self.flow.block: self.flow.block.add_child(self.flow.exit_point) self.flow.block = None return node def visit_BreakStatNode(self, node): if not self.flow.loops: #error(node.pos, "break statement not inside loop") return node loop = self.flow.loops[-1] self.mark_position(node) for exception in loop.exceptions[::-1]: if exception.finally_enter: self.flow.block.add_child(exception.finally_enter) if exception.finally_exit: exception.finally_exit.add_child(loop.next_block) break else: self.flow.block.add_child(loop.next_block) self.flow.block = None return node def visit_ContinueStatNode(self, node): if not self.flow.loops: #error(node.pos, "continue statement not inside loop") return node loop = self.flow.loops[-1] self.mark_position(node) for exception in loop.exceptions[::-1]: if exception.finally_enter: self.flow.block.add_child(exception.finally_enter) if exception.finally_exit: exception.finally_exit.add_child(loop.loop_block) break else: self.flow.block.add_child(loop.loop_block) self.flow.block = None return node def visit_ComprehensionNode(self, node): if node.expr_scope: self.env_stack.append(self.env) self.env = node.expr_scope # Skip append node here self._visit(node.loop) if node.expr_scope: self.env = self.env_stack.pop() return node def visit_ScopedExprNode(self, node): if node.expr_scope: self.env_stack.append(self.env) self.env = node.expr_scope self.visitchildren(node) if node.expr_scope: self.env = self.env_stack.pop() return node def visit_PyClassDefNode(self, node): self.visitchildren(node, ('dict', 'metaclass', 'mkw', 'bases', 'class_result')) self.flow.mark_assignment(node.target, object_expr_not_none, self.env.lookup(node.name)) self.env_stack.append(self.env) self.env = node.scope self.flow.nextblock() self.visitchildren(node, ('body',)) self.flow.nextblock() self.env = self.env_stack.pop() return node def visit_AmpersandNode(self, node): if node.operand.is_name: # Fake assignment to silence warning self.mark_assignment(node.operand, fake_rhs_expr) self.visitchildren(node) return node cython-0.20.1+git90-g0e6e38e/Cython/Compiler/FusedNode.py000066400000000000000000000766261231323242300225320ustar00rootroot00000000000000import copy from Cython.Compiler import (ExprNodes, PyrexTypes, MemoryView, ParseTreeTransforms, StringEncoding, Errors) from Cython.Compiler.ExprNodes import CloneNode, ProxyNode, TupleNode from Cython.Compiler.Nodes import (FuncDefNode, CFuncDefNode, StatListNode, DefNode) class FusedCFuncDefNode(StatListNode): """ This node replaces a function with fused arguments. It deep-copies the function for every permutation of fused types, and allocates a new local scope for it. It keeps track of the original function in self.node, and the entry of the original function in the symbol table is given the 'fused_cfunction' attribute which points back to us. Then when a function lookup occurs (to e.g. call it), the call can be dispatched to the right function. node FuncDefNode the original function nodes [FuncDefNode] list of copies of node with different specific types py_func DefNode the fused python function subscriptable from Python space __signatures__ A DictNode mapping signature specialization strings to PyCFunction nodes resulting_fused_function PyCFunction for the fused DefNode that delegates to specializations fused_func_assignment Assignment of the fused function to the function name defaults_tuple TupleNode of defaults (letting PyCFunctionNode build defaults would result in many different tuples) specialized_pycfuncs List of synthesized pycfunction nodes for the specializations code_object CodeObjectNode shared by all specializations and the fused function fused_compound_types All fused (compound) types (e.g. floating[:]) """ __signatures__ = None resulting_fused_function = None fused_func_assignment = None defaults_tuple = None decorators = None child_attrs = StatListNode.child_attrs + [ '__signatures__', 'resulting_fused_function', 'fused_func_assignment'] def __init__(self, node, env): super(FusedCFuncDefNode, self).__init__(node.pos) self.nodes = [] self.node = node is_def = isinstance(self.node, DefNode) if is_def: # self.node.decorators = [] self.copy_def(env) else: self.copy_cdef(env) # Perform some sanity checks. If anything fails, it's a bug for n in self.nodes: assert not n.entry.type.is_fused assert not n.local_scope.return_type.is_fused if node.return_type.is_fused: assert not n.return_type.is_fused if not is_def and n.cfunc_declarator.optional_arg_count: assert n.type.op_arg_struct node.entry.fused_cfunction = self # Copy the nodes as AnalyseDeclarationsTransform will prepend # self.py_func to self.stats, as we only want specialized # CFuncDefNodes in self.nodes self.stats = self.nodes[:] def copy_def(self, env): """ Create a copy of the original def or lambda function for specialized versions. """ fused_compound_types = PyrexTypes.unique( [arg.type for arg in self.node.args if arg.type.is_fused]) permutations = PyrexTypes.get_all_specialized_permutations(fused_compound_types) self.fused_compound_types = fused_compound_types if self.node.entry in env.pyfunc_entries: env.pyfunc_entries.remove(self.node.entry) for cname, fused_to_specific in permutations: copied_node = copy.deepcopy(self.node) self._specialize_function_args(copied_node.args, fused_to_specific) copied_node.return_type = self.node.return_type.specialize( fused_to_specific) copied_node.analyse_declarations(env) # copied_node.is_staticmethod = self.node.is_staticmethod # copied_node.is_classmethod = self.node.is_classmethod self.create_new_local_scope(copied_node, env, fused_to_specific) self.specialize_copied_def(copied_node, cname, self.node.entry, fused_to_specific, fused_compound_types) PyrexTypes.specialize_entry(copied_node.entry, cname) copied_node.entry.used = True env.entries[copied_node.entry.name] = copied_node.entry if not self.replace_fused_typechecks(copied_node): break self.orig_py_func = self.node self.py_func = self.make_fused_cpdef(self.node, env, is_def=True) def copy_cdef(self, env): """ Create a copy of the original c(p)def function for all specialized versions. """ permutations = self.node.type.get_all_specialized_permutations() # print 'Node %s has %d specializations:' % (self.node.entry.name, # len(permutations)) # import pprint; pprint.pprint([d for cname, d in permutations]) if self.node.entry in env.cfunc_entries: env.cfunc_entries.remove(self.node.entry) # Prevent copying of the python function self.orig_py_func = orig_py_func = self.node.py_func self.node.py_func = None if orig_py_func: env.pyfunc_entries.remove(orig_py_func.entry) fused_types = self.node.type.get_fused_types() self.fused_compound_types = fused_types for cname, fused_to_specific in permutations: copied_node = copy.deepcopy(self.node) # Make the types in our CFuncType specific type = copied_node.type.specialize(fused_to_specific) entry = copied_node.entry copied_node.type = type entry.type, type.entry = type, entry entry.used = (entry.used or self.node.entry.defined_in_pxd or env.is_c_class_scope or entry.is_cmethod) if self.node.cfunc_declarator.optional_arg_count: self.node.cfunc_declarator.declare_optional_arg_struct( type, env, fused_cname=cname) copied_node.return_type = type.return_type self.create_new_local_scope(copied_node, env, fused_to_specific) # Make the argument types in the CFuncDeclarator specific self._specialize_function_args(copied_node.cfunc_declarator.args, fused_to_specific) type.specialize_entry(entry, cname) env.cfunc_entries.append(entry) # If a cpdef, declare all specialized cpdefs (this # also calls analyse_declarations) copied_node.declare_cpdef_wrapper(env) if copied_node.py_func: env.pyfunc_entries.remove(copied_node.py_func.entry) self.specialize_copied_def( copied_node.py_func, cname, self.node.entry.as_variable, fused_to_specific, fused_types) if not self.replace_fused_typechecks(copied_node): break if orig_py_func: self.py_func = self.make_fused_cpdef(orig_py_func, env, is_def=False) else: self.py_func = orig_py_func def _specialize_function_args(self, args, fused_to_specific): for arg in args: if arg.type.is_fused: arg.type = arg.type.specialize(fused_to_specific) if arg.type.is_memoryviewslice: MemoryView.validate_memslice_dtype(arg.pos, arg.type.dtype) def create_new_local_scope(self, node, env, f2s): """ Create a new local scope for the copied node and append it to self.nodes. A new local scope is needed because the arguments with the fused types are aready in the local scope, and we need the specialized entries created after analyse_declarations on each specialized version of the (CFunc)DefNode. f2s is a dict mapping each fused type to its specialized version """ node.create_local_scope(env) node.local_scope.fused_to_specific = f2s # This is copied from the original function, set it to false to # stop recursion node.has_fused_arguments = False self.nodes.append(node) def specialize_copied_def(self, node, cname, py_entry, f2s, fused_types): """Specialize the copy of a DefNode given the copied node, the specialization cname and the original DefNode entry""" type_strings = [ PyrexTypes.specialization_signature_string(fused_type, f2s) for fused_type in fused_types ] node.specialized_signature_string = '|'.join(type_strings) node.entry.pymethdef_cname = PyrexTypes.get_fused_cname( cname, node.entry.pymethdef_cname) node.entry.doc = py_entry.doc node.entry.doc_cname = py_entry.doc_cname def replace_fused_typechecks(self, copied_node): """ Branch-prune fused type checks like if fused_t is int: ... Returns whether an error was issued and whether we should stop in in order to prevent a flood of errors. """ num_errors = Errors.num_errors transform = ParseTreeTransforms.ReplaceFusedTypeChecks( copied_node.local_scope) transform(copied_node) if Errors.num_errors > num_errors: return False return True def _fused_instance_checks(self, normal_types, pyx_code, env): """ Genereate Cython code for instance checks, matching an object to specialized types. """ if_ = 'if' for specialized_type in normal_types: # all_numeric = all_numeric and specialized_type.is_numeric py_type_name = specialized_type.py_type_name() specialized_type_name = specialized_type.specialization_string pyx_code.context.update(locals()) pyx_code.put_chunk( u""" {{if_}} isinstance(arg, {{py_type_name}}): dest_sig[{{dest_sig_idx}}] = '{{specialized_type_name}}' """) if_ = 'elif' if not normal_types: # we need an 'if' to match the following 'else' pyx_code.putln("if 0: pass") def _dtype_name(self, dtype): if dtype.is_typedef: return '___pyx_%s' % dtype return str(dtype).replace(' ', '_') def _dtype_type(self, dtype): if dtype.is_typedef: return self._dtype_name(dtype) return str(dtype) def _sizeof_dtype(self, dtype): if dtype.is_pyobject: return 'sizeof(void *)' else: return "sizeof(%s)" % self._dtype_type(dtype) def _buffer_check_numpy_dtype_setup_cases(self, pyx_code): "Setup some common cases to match dtypes against specializations" if pyx_code.indenter("if dtype.kind in ('i', 'u'):"): pyx_code.putln("pass") pyx_code.named_insertion_point("dtype_int") pyx_code.dedent() if pyx_code.indenter("elif dtype.kind == 'f':"): pyx_code.putln("pass") pyx_code.named_insertion_point("dtype_float") pyx_code.dedent() if pyx_code.indenter("elif dtype.kind == 'c':"): pyx_code.putln("pass") pyx_code.named_insertion_point("dtype_complex") pyx_code.dedent() if pyx_code.indenter("elif dtype.kind == 'O':"): pyx_code.putln("pass") pyx_code.named_insertion_point("dtype_object") pyx_code.dedent() match = "dest_sig[{{dest_sig_idx}}] = '{{specialized_type_name}}'" no_match = "dest_sig[{{dest_sig_idx}}] = None" def _buffer_check_numpy_dtype(self, pyx_code, specialized_buffer_types): """ Match a numpy dtype object to the individual specializations. """ self._buffer_check_numpy_dtype_setup_cases(pyx_code) for specialized_type in specialized_buffer_types: dtype = specialized_type.dtype pyx_code.context.update( itemsize_match=self._sizeof_dtype(dtype) + " == itemsize", signed_match="not (%s_is_signed ^ dtype_signed)" % self._dtype_name(dtype), dtype=dtype, specialized_type_name=specialized_type.specialization_string) dtypes = [ (dtype.is_int, pyx_code.dtype_int), (dtype.is_float, pyx_code.dtype_float), (dtype.is_complex, pyx_code.dtype_complex) ] for dtype_category, codewriter in dtypes: if dtype_category: cond = '{{itemsize_match}} and arg.ndim == %d' % ( specialized_type.ndim,) if dtype.is_int: cond += ' and {{signed_match}}' if codewriter.indenter("if %s:" % cond): # codewriter.putln("print 'buffer match found based on numpy dtype'") codewriter.putln(self.match) codewriter.putln("break") codewriter.dedent() def _buffer_parse_format_string_check(self, pyx_code, decl_code, specialized_type, env): """ For each specialized type, try to coerce the object to a memoryview slice of that type. This means obtaining a buffer and parsing the format string. TODO: separate buffer acquisition from format parsing """ dtype = specialized_type.dtype if specialized_type.is_buffer: axes = [('direct', 'strided')] * specialized_type.ndim else: axes = specialized_type.axes memslice_type = PyrexTypes.MemoryViewSliceType(dtype, axes) memslice_type.create_from_py_utility_code(env) pyx_code.context.update( coerce_from_py_func=memslice_type.from_py_function, dtype=dtype) decl_code.putln( "{{memviewslice_cname}} {{coerce_from_py_func}}(object)") pyx_code.context.update( specialized_type_name=specialized_type.specialization_string, sizeof_dtype=self._sizeof_dtype(dtype)) pyx_code.put_chunk( u""" # try {{dtype}} if itemsize == -1 or itemsize == {{sizeof_dtype}}: memslice = {{coerce_from_py_func}}(arg) if memslice.memview: __PYX_XDEC_MEMVIEW(&memslice, 1) # print 'found a match for the buffer through format parsing' %s break else: __pyx_PyErr_Clear() """ % self.match) def _buffer_checks(self, buffer_types, pyx_code, decl_code, env): """ Generate Cython code to match objects to buffer specializations. First try to get a numpy dtype object and match it against the individual specializations. If that fails, try naively to coerce the object to each specialization, which obtains the buffer each time and tries to match the format string. """ from Cython.Compiler import ExprNodes if buffer_types: if pyx_code.indenter(u"else:"): # The first thing to find a match in this loop breaks out of the loop if pyx_code.indenter(u"while 1:"): pyx_code.put_chunk( u""" if numpy is not None: if isinstance(arg, numpy.ndarray): dtype = arg.dtype elif (__pyx_memoryview_check(arg) and isinstance(arg.base, numpy.ndarray)): dtype = arg.base.dtype else: dtype = None itemsize = -1 if dtype is not None: itemsize = dtype.itemsize kind = ord(dtype.kind) dtype_signed = kind == ord('i') """) pyx_code.indent(2) pyx_code.named_insertion_point("numpy_dtype_checks") self._buffer_check_numpy_dtype(pyx_code, buffer_types) pyx_code.dedent(2) for specialized_type in buffer_types: self._buffer_parse_format_string_check( pyx_code, decl_code, specialized_type, env) pyx_code.putln(self.no_match) pyx_code.putln("break") pyx_code.dedent() pyx_code.dedent() else: pyx_code.putln("else: %s" % self.no_match) def _buffer_declarations(self, pyx_code, decl_code, all_buffer_types): """ If we have any buffer specializations, write out some variable declarations and imports. """ decl_code.put_chunk( u""" ctypedef struct {{memviewslice_cname}}: void *memview void __PYX_XDEC_MEMVIEW({{memviewslice_cname}} *, int have_gil) bint __pyx_memoryview_check(object) """) pyx_code.local_variable_declarations.put_chunk( u""" cdef {{memviewslice_cname}} memslice cdef Py_ssize_t itemsize cdef bint dtype_signed cdef char kind itemsize = -1 """) pyx_code.imports.put_chunk( u""" try: import numpy except ImportError: numpy = None """) seen_int_dtypes = set() for buffer_type in all_buffer_types: dtype = buffer_type.dtype if dtype.is_typedef: #decl_code.putln("ctypedef %s %s" % (dtype.resolve(), # self._dtype_name(dtype))) decl_code.putln('ctypedef %s %s "%s"' % (dtype.resolve(), self._dtype_name(dtype), dtype.declaration_code(""))) if buffer_type.dtype.is_int: if str(dtype) not in seen_int_dtypes: seen_int_dtypes.add(str(dtype)) pyx_code.context.update(dtype_name=self._dtype_name(dtype), dtype_type=self._dtype_type(dtype)) pyx_code.local_variable_declarations.put_chunk( u""" cdef bint {{dtype_name}}_is_signed {{dtype_name}}_is_signed = <{{dtype_type}}> -1 < 0 """) def _split_fused_types(self, arg): """ Specialize fused types and split into normal types and buffer types. """ specialized_types = PyrexTypes.get_specialized_types(arg.type) # Prefer long over int, etc # specialized_types.sort() seen_py_type_names = set() normal_types, buffer_types = [], [] for specialized_type in specialized_types: py_type_name = specialized_type.py_type_name() if py_type_name: if py_type_name in seen_py_type_names: continue seen_py_type_names.add(py_type_name) normal_types.append(specialized_type) elif specialized_type.is_buffer or specialized_type.is_memoryviewslice: buffer_types.append(specialized_type) return normal_types, buffer_types def _unpack_argument(self, pyx_code): pyx_code.put_chunk( u""" # PROCESSING ARGUMENT {{arg_tuple_idx}} if {{arg_tuple_idx}} < len(args): arg = args[{{arg_tuple_idx}}] elif '{{arg.name}}' in kwargs: arg = kwargs['{{arg.name}}'] else: {{if arg.default:}} arg = defaults[{{default_idx}}] {{else}} raise TypeError("Expected at least %d arguments" % len(args)) {{endif}} """) def make_fused_cpdef(self, orig_py_func, env, is_def): """ This creates the function that is indexable from Python and does runtime dispatch based on the argument types. The function gets the arg tuple and kwargs dict (or None) and the defaults tuple as arguments from the Binding Fused Function's tp_call. """ from Cython.Compiler import TreeFragment, Code, MemoryView, UtilityCode # { (arg_pos, FusedType) : specialized_type } seen_fused_types = set() context = { 'memviewslice_cname': MemoryView.memviewslice_cname, 'func_args': self.node.args, 'n_fused': len([arg for arg in self.node.args]), 'name': orig_py_func.entry.name, } pyx_code = Code.PyxCodeWriter(context=context) decl_code = Code.PyxCodeWriter(context=context) decl_code.put_chunk( u""" cdef extern from *: void __pyx_PyErr_Clear "PyErr_Clear" () """) decl_code.indent() pyx_code.put_chunk( u""" def __pyx_fused_cpdef(signatures, args, kwargs, defaults): dest_sig = [{{for _ in range(n_fused)}}None,{{endfor}}] if kwargs is None: kwargs = {} cdef Py_ssize_t i # instance check body """) pyx_code.indent() # indent following code to function body pyx_code.named_insertion_point("imports") pyx_code.named_insertion_point("local_variable_declarations") fused_index = 0 default_idx = 0 all_buffer_types = set() for i, arg in enumerate(self.node.args): if arg.type.is_fused and arg.type not in seen_fused_types: seen_fused_types.add(arg.type) context.update( arg_tuple_idx=i, arg=arg, dest_sig_idx=fused_index, default_idx=default_idx, ) normal_types, buffer_types = self._split_fused_types(arg) self._unpack_argument(pyx_code) self._fused_instance_checks(normal_types, pyx_code, env) self._buffer_checks(buffer_types, pyx_code, decl_code, env) fused_index += 1 all_buffer_types.update(buffer_types) if arg.default: default_idx += 1 if all_buffer_types: self._buffer_declarations(pyx_code, decl_code, all_buffer_types) env.use_utility_code(Code.UtilityCode.load_cached("Import", "ImportExport.c")) pyx_code.put_chunk( u""" candidates = [] for sig in signatures: match_found = False for src_type, dst_type in zip(sig.strip('()').split('|'), dest_sig): if dst_type is not None: if src_type == dst_type: match_found = True else: match_found = False break if match_found: candidates.append(sig) if not candidates: raise TypeError("No matching signature found") elif len(candidates) > 1: raise TypeError("Function call with ambiguous argument types") else: return signatures[candidates[0]] """) fragment_code = pyx_code.getvalue() # print decl_code.getvalue() # print fragment_code fragment = TreeFragment.TreeFragment(fragment_code, level='module') ast = TreeFragment.SetPosTransform(self.node.pos)(fragment.root) UtilityCode.declare_declarations_in_scope(decl_code.getvalue(), env.global_scope()) ast.scope = env ast.analyse_declarations(env) py_func = ast.stats[-1] # the DefNode self.fragment_scope = ast.scope if isinstance(self.node, DefNode): py_func.specialized_cpdefs = self.nodes[:] else: py_func.specialized_cpdefs = [n.py_func for n in self.nodes] return py_func def update_fused_defnode_entry(self, env): copy_attributes = ( 'name', 'pos', 'cname', 'func_cname', 'pyfunc_cname', 'pymethdef_cname', 'doc', 'doc_cname', 'is_member', 'scope' ) entry = self.py_func.entry for attr in copy_attributes: setattr(entry, attr, getattr(self.orig_py_func.entry, attr)) self.py_func.name = self.orig_py_func.name self.py_func.doc = self.orig_py_func.doc env.entries.pop('__pyx_fused_cpdef', None) if isinstance(self.node, DefNode): env.entries[entry.name] = entry else: env.entries[entry.name].as_variable = entry env.pyfunc_entries.append(entry) self.py_func.entry.fused_cfunction = self for node in self.nodes: if isinstance(self.node, DefNode): node.fused_py_func = self.py_func else: node.py_func.fused_py_func = self.py_func node.entry.as_variable = entry self.synthesize_defnodes() self.stats.append(self.__signatures__) def analyse_expressions(self, env): """ Analyse the expressions. Take care to only evaluate default arguments once and clone the result for all specializations """ for fused_compound_type in self.fused_compound_types: for fused_type in fused_compound_type.get_fused_types(): for specialization_type in fused_type.types: if specialization_type.is_complex: specialization_type.create_declaration_utility_code(env) if self.py_func: self.__signatures__ = self.__signatures__.analyse_expressions(env) self.py_func = self.py_func.analyse_expressions(env) self.resulting_fused_function = self.resulting_fused_function.analyse_expressions(env) self.fused_func_assignment = self.fused_func_assignment.analyse_expressions(env) self.defaults = defaults = [] for arg in self.node.args: if arg.default: arg.default = arg.default.analyse_expressions(env) defaults.append(ProxyNode(arg.default)) else: defaults.append(None) for i, stat in enumerate(self.stats): stat = self.stats[i] = stat.analyse_expressions(env) if isinstance(stat, FuncDefNode): for arg, default in zip(stat.args, defaults): if default is not None: arg.default = CloneNode(default).coerce_to(arg.type, env) if self.py_func: args = [CloneNode(default) for default in defaults if default] self.defaults_tuple = TupleNode(self.pos, args=args) self.defaults_tuple = self.defaults_tuple.analyse_types(env, skip_children=True) self.defaults_tuple = ProxyNode(self.defaults_tuple) self.code_object = ProxyNode(self.specialized_pycfuncs[0].code_object) fused_func = self.resulting_fused_function.arg fused_func.defaults_tuple = CloneNode(self.defaults_tuple) fused_func.code_object = CloneNode(self.code_object) for i, pycfunc in enumerate(self.specialized_pycfuncs): pycfunc.code_object = CloneNode(self.code_object) pycfunc = self.specialized_pycfuncs[i] = pycfunc.analyse_types(env) pycfunc.defaults_tuple = CloneNode(self.defaults_tuple) return self def synthesize_defnodes(self): """ Create the __signatures__ dict of PyCFunctionNode specializations. """ if isinstance(self.nodes[0], CFuncDefNode): nodes = [node.py_func for node in self.nodes] else: nodes = self.nodes signatures = [ StringEncoding.EncodedString(node.specialized_signature_string) for node in nodes] keys = [ExprNodes.StringNode(node.pos, value=sig) for node, sig in zip(nodes, signatures)] values = [ExprNodes.PyCFunctionNode.from_defnode(node, True) for node in nodes] self.__signatures__ = ExprNodes.DictNode.from_pairs(self.pos, zip(keys, values)) self.specialized_pycfuncs = values for pycfuncnode in values: pycfuncnode.is_specialization = True def generate_function_definitions(self, env, code): if self.py_func: self.py_func.pymethdef_required = True self.fused_func_assignment.generate_function_definitions(env, code) for stat in self.stats: if isinstance(stat, FuncDefNode) and stat.entry.used: code.mark_pos(stat.pos) stat.generate_function_definitions(env, code) def generate_execution_code(self, code): # Note: all def function specialization are wrapped in PyCFunction # nodes in the self.__signatures__ dictnode. for default in self.defaults: if default is not None: default.generate_evaluation_code(code) if self.py_func: self.defaults_tuple.generate_evaluation_code(code) self.code_object.generate_evaluation_code(code) for stat in self.stats: code.mark_pos(stat.pos) if isinstance(stat, ExprNodes.ExprNode): stat.generate_evaluation_code(code) else: stat.generate_execution_code(code) if self.__signatures__: self.resulting_fused_function.generate_evaluation_code(code) code.putln( "((__pyx_FusedFunctionObject *) %s)->__signatures__ = %s;" % (self.resulting_fused_function.result(), self.__signatures__.result())) code.put_giveref(self.__signatures__.result()) self.fused_func_assignment.generate_execution_code(code) # Dispose of results self.resulting_fused_function.generate_disposal_code(code) self.defaults_tuple.generate_disposal_code(code) self.code_object.generate_disposal_code(code) for default in self.defaults: if default is not None: default.generate_disposal_code(code) def annotate(self, code): for stat in self.stats: stat.annotate(code) cython-0.20.1+git90-g0e6e38e/Cython/Compiler/Future.py000066400000000000000000000010221231323242300221020ustar00rootroot00000000000000def _get_feature(name): import __future__ # fall back to a unique fake object for earlier Python versions or Python 3 return getattr(__future__, name, object()) unicode_literals = _get_feature("unicode_literals") with_statement = _get_feature("with_statement") division = _get_feature("division") print_function = _get_feature("print_function") absolute_import = _get_feature("absolute_import") nested_scopes = _get_feature("nested_scopes") # dummy generators = _get_feature("generators") # dummy del _get_feature cython-0.20.1+git90-g0e6e38e/Cython/Compiler/Interpreter.py000066400000000000000000000040171231323242300231420ustar00rootroot00000000000000""" This module deals with interpreting the parse tree as Python would have done, in the compiler. For now this only covers parse tree to value conversion of compile-time values. """ from Nodes import * from ExprNodes import * from Errors import CompileError class EmptyScope(object): def lookup(self, name): return None empty_scope = EmptyScope() def interpret_compiletime_options(optlist, optdict, type_env=None, type_args=()): """ Tries to interpret a list of compile time option nodes. The result will be a tuple (optlist, optdict) but where all expression nodes have been interpreted. The result is in the form of tuples (value, pos). optlist is a list of nodes, while optdict is a DictNode (the result optdict is a dict) If type_env is set, all type nodes will be analysed and the resulting type set. Otherwise only interpretateable ExprNodes are allowed, other nodes raises errors. A CompileError will be raised if there are problems. """ def interpret(node, ix): if ix in type_args: if type_env: type = node.analyse_as_type(type_env) if not type: raise CompileError(node.pos, "Invalid type.") return (type, node.pos) else: raise CompileError(node.pos, "Type not allowed here.") else: if (sys.version_info[0] >=3 and isinstance(node, StringNode) and node.unicode_value is not None): return (node.unicode_value, node.pos) return (node.compile_time_value(empty_scope), node.pos) if optlist: optlist = [interpret(x, ix) for ix, x in enumerate(optlist)] if optdict: assert isinstance(optdict, DictNode) new_optdict = {} for item in optdict.key_value_pairs: new_key, dummy = interpret(item.key, None) new_optdict[new_key] = interpret(item.value, item.key.value) optdict = new_optdict return (optlist, new_optdict) cython-0.20.1+git90-g0e6e38e/Cython/Compiler/Lexicon.py000066400000000000000000000107741231323242300222470ustar00rootroot00000000000000# cython: language_level=3, py2_import=True # # Cython Scanner - Lexical Definitions # raw_prefixes = "rR" bytes_prefixes = "bB" string_prefixes = "uU" + bytes_prefixes char_prefixes = "cC" any_string_prefix = raw_prefixes + string_prefixes + char_prefixes IDENT = 'IDENT' def make_lexicon(): from Cython.Plex import \ Str, Any, AnyBut, AnyChar, Rep, Rep1, Opt, Bol, Eol, Eof, \ TEXT, IGNORE, State, Lexicon from Scanning import Method letter = Any("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_") digit = Any("0123456789") bindigit = Any("01") octdigit = Any("01234567") hexdigit = Any("0123456789ABCDEFabcdef") indentation = Bol + Rep(Any(" \t")) decimal = Rep1(digit) dot = Str(".") exponent = Any("Ee") + Opt(Any("+-")) + decimal decimal_fract = (decimal + dot + Opt(decimal)) | (dot + decimal) name = letter + Rep(letter | digit) intconst = decimal | (Str("0") + ((Any("Xx") + Rep1(hexdigit)) | (Any("Oo") + Rep1(octdigit)) | (Any("Bb") + Rep1(bindigit)) )) intsuffix = (Opt(Any("Uu")) + Opt(Any("Ll")) + Opt(Any("Ll"))) | (Opt(Any("Ll")) + Opt(Any("Ll")) + Opt(Any("Uu"))) intliteral = intconst + intsuffix fltconst = (decimal_fract + Opt(exponent)) | (decimal + exponent) imagconst = (intconst | fltconst) + Any("jJ") beginstring = Opt(Any(string_prefixes) + Opt(Any(raw_prefixes)) | Any(raw_prefixes) + Opt(Any(bytes_prefixes)) | Any(char_prefixes) ) + (Str("'") | Str('"') | Str("'''") | Str('"""')) two_oct = octdigit + octdigit three_oct = octdigit + octdigit + octdigit two_hex = hexdigit + hexdigit four_hex = two_hex + two_hex escapeseq = Str("\\") + (two_oct | three_oct | Str('N{') + Rep(AnyBut('}')) + Str('}') | Str('u') + four_hex | Str('x') + two_hex | Str('U') + four_hex + four_hex | AnyChar) deco = Str("@") bra = Any("([{") ket = Any(")]}") punct = Any(":,;+-*/|&<>=.%`~^?!") diphthong = Str("==", "<>", "!=", "<=", ">=", "<<", ">>", "**", "//", "+=", "-=", "*=", "/=", "%=", "|=", "^=", "&=", "<<=", ">>=", "**=", "//=", "->") spaces = Rep1(Any(" \t\f")) escaped_newline = Str("\\\n") lineterm = Eol + Opt(Str("\n")) comment = Str("#") + Rep(AnyBut("\n")) return Lexicon([ (name, IDENT), (intliteral, 'INT'), (fltconst, 'FLOAT'), (imagconst, 'IMAG'), (deco, 'DECORATOR'), (punct | diphthong, TEXT), (bra, Method('open_bracket_action')), (ket, Method('close_bracket_action')), (lineterm, Method('newline_action')), (beginstring, Method('begin_string_action')), (comment, IGNORE), (spaces, IGNORE), (escaped_newline, IGNORE), State('INDENT', [ (comment + lineterm, Method('commentline')), (Opt(spaces) + Opt(comment) + lineterm, IGNORE), (indentation, Method('indentation_action')), (Eof, Method('eof_action')) ]), State('SQ_STRING', [ (escapeseq, 'ESCAPE'), (Rep1(AnyBut("'\"\n\\")), 'CHARS'), (Str('"'), 'CHARS'), (Str("\n"), Method('unclosed_string_action')), (Str("'"), Method('end_string_action')), (Eof, 'EOF') ]), State('DQ_STRING', [ (escapeseq, 'ESCAPE'), (Rep1(AnyBut('"\n\\')), 'CHARS'), (Str("'"), 'CHARS'), (Str("\n"), Method('unclosed_string_action')), (Str('"'), Method('end_string_action')), (Eof, 'EOF') ]), State('TSQ_STRING', [ (escapeseq, 'ESCAPE'), (Rep1(AnyBut("'\"\n\\")), 'CHARS'), (Any("'\""), 'CHARS'), (Str("\n"), 'NEWLINE'), (Str("'''"), Method('end_string_action')), (Eof, 'EOF') ]), State('TDQ_STRING', [ (escapeseq, 'ESCAPE'), (Rep1(AnyBut('"\'\n\\')), 'CHARS'), (Any("'\""), 'CHARS'), (Str("\n"), 'NEWLINE'), (Str('"""'), Method('end_string_action')), (Eof, 'EOF') ]), (Eof, Method('eof_action')) ], # FIXME: Plex 1.9 needs different args here from Plex 1.1.4 #debug_flags = scanner_debug_flags, #debug_file = scanner_dump_file ) cython-0.20.1+git90-g0e6e38e/Cython/Compiler/Main.py000066400000000000000000000641551231323242300215340ustar00rootroot00000000000000# # Cython Top Level # import os, sys, re, codecs if sys.version_info[:2] < (2, 4): sys.stderr.write("Sorry, Cython requires Python 2.4 or later\n") sys.exit(1) import Errors # Do not import Parsing here, import it when needed, because Parsing imports # Nodes, which globally needs debug command line options initialized to set a # conditional metaclass. These options are processed by CmdLine called from # main() in this file. # import Parsing import Version from Scanning import PyrexScanner, FileSourceDescriptor from Errors import PyrexError, CompileError, error, warning from Symtab import ModuleScope from Cython import Utils import Options module_name_pattern = re.compile(r"[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$") verbose = 0 class CompilationData(object): # Bundles the information that is passed from transform to transform. # (For now, this is only) # While Context contains every pxd ever loaded, path information etc., # this only contains the data related to a single compilation pass # # pyx ModuleNode Main code tree of this compilation. # pxds {string : ModuleNode} Trees for the pxds used in the pyx. # codewriter CCodeWriter Where to output final code. # options CompilationOptions # result CompilationResult pass class Context(object): # This class encapsulates the context needed for compiling # one or more Cython implementation files along with their # associated and imported declaration files. It includes # the root of the module import namespace and the list # of directories to search for include files. # # modules {string : ModuleScope} # include_directories [string] # future_directives [object] # language_level int currently 2 or 3 for Python 2/3 cython_scope = None def __init__(self, include_directories, compiler_directives, cpp=False, language_level=2, options=None, create_testscope=True): # cython_scope is a hack, set to False by subclasses, in order to break # an infinite loop. # Better code organization would fix it. import Builtin, CythonScope self.modules = {"__builtin__" : Builtin.builtin_scope} self.cython_scope = CythonScope.create_cython_scope(self) self.modules["cython"] = self.cython_scope self.include_directories = include_directories self.future_directives = set() self.compiler_directives = compiler_directives self.cpp = cpp self.options = options self.pxds = {} # full name -> node tree standard_include_path = os.path.abspath(os.path.normpath( os.path.join(os.path.dirname(__file__), os.path.pardir, 'Includes'))) self.include_directories = include_directories + [standard_include_path] self.set_language_level(language_level) self.gdb_debug_outputwriter = None def set_language_level(self, level): self.language_level = level if level >= 3: from Future import print_function, unicode_literals, absolute_import self.future_directives.update([print_function, unicode_literals, absolute_import]) self.modules['builtins'] = self.modules['__builtin__'] # pipeline creation functions can now be found in Pipeline.py def process_pxd(self, source_desc, scope, module_name): import Pipeline if isinstance(source_desc, FileSourceDescriptor) and source_desc._file_type == 'pyx': source = CompilationSource(source_desc, module_name, os.getcwd()) result_sink = create_default_resultobj(source, self.options) pipeline = Pipeline.create_pyx_as_pxd_pipeline(self, result_sink) result = Pipeline.run_pipeline(pipeline, source) else: pipeline = Pipeline.create_pxd_pipeline(self, scope, module_name) result = Pipeline.run_pipeline(pipeline, source_desc) return result def nonfatal_error(self, exc): return Errors.report_error(exc) def find_module(self, module_name, relative_to = None, pos = None, need_pxd = 1, check_module_name = True): # Finds and returns the module scope corresponding to # the given relative or absolute module name. If this # is the first time the module has been requested, finds # the corresponding .pxd file and process it. # If relative_to is not None, it must be a module scope, # and the module will first be searched for relative to # that module, provided its name is not a dotted name. debug_find_module = 0 if debug_find_module: print("Context.find_module: module_name = %s, relative_to = %s, pos = %s, need_pxd = %s" % ( module_name, relative_to, pos, need_pxd)) scope = None pxd_pathname = None if check_module_name and not module_name_pattern.match(module_name): if pos is None: pos = (module_name, 0, 0) raise CompileError(pos, "'%s' is not a valid module name" % module_name) if "." not in module_name and relative_to: if debug_find_module: print("...trying relative import") scope = relative_to.lookup_submodule(module_name) if not scope: qualified_name = relative_to.qualify_name(module_name) pxd_pathname = self.find_pxd_file(qualified_name, pos) if pxd_pathname: scope = relative_to.find_submodule(module_name) if not scope: if debug_find_module: print("...trying absolute import") scope = self for name in module_name.split("."): scope = scope.find_submodule(name) if debug_find_module: print("...scope =", scope) if not scope.pxd_file_loaded: if debug_find_module: print("...pxd not loaded") scope.pxd_file_loaded = 1 if not pxd_pathname: if debug_find_module: print("...looking for pxd file") pxd_pathname = self.find_pxd_file(module_name, pos) if debug_find_module: print("......found ", pxd_pathname) if not pxd_pathname and need_pxd: package_pathname = self.search_include_directories(module_name, ".py", pos) if package_pathname and package_pathname.endswith('__init__.py'): pass else: error(pos, "'%s.pxd' not found" % module_name) if pxd_pathname: try: if debug_find_module: print("Context.find_module: Parsing %s" % pxd_pathname) rel_path = module_name.replace('.', os.sep) + os.path.splitext(pxd_pathname)[1] if not pxd_pathname.endswith(rel_path): rel_path = pxd_pathname # safety measure to prevent printing incorrect paths source_desc = FileSourceDescriptor(pxd_pathname, rel_path) err, result = self.process_pxd(source_desc, scope, module_name) if err: raise err (pxd_codenodes, pxd_scope) = result self.pxds[module_name] = (pxd_codenodes, pxd_scope) except CompileError: pass return scope def find_pxd_file(self, qualified_name, pos): # Search include path for the .pxd file corresponding to the # given fully-qualified module name. # Will find either a dotted filename or a file in a # package directory. If a source file position is given, # the directory containing the source file is searched first # for a dotted filename, and its containing package root # directory is searched first for a non-dotted filename. pxd = self.search_include_directories(qualified_name, ".pxd", pos, sys_path=True) if pxd is None: # XXX Keep this until Includes/Deprecated is removed if (qualified_name.startswith('python') or qualified_name in ('stdlib', 'stdio', 'stl')): standard_include_path = os.path.abspath(os.path.normpath( os.path.join(os.path.dirname(__file__), os.path.pardir, 'Includes'))) deprecated_include_path = os.path.join(standard_include_path, 'Deprecated') self.include_directories.append(deprecated_include_path) try: pxd = self.search_include_directories(qualified_name, ".pxd", pos) finally: self.include_directories.pop() if pxd: name = qualified_name if name.startswith('python'): warning(pos, "'%s' is deprecated, use 'cpython'" % name, 1) elif name in ('stdlib', 'stdio'): warning(pos, "'%s' is deprecated, use 'libc.%s'" % (name, name), 1) elif name in ('stl'): warning(pos, "'%s' is deprecated, use 'libcpp.*.*'" % name, 1) if pxd is None and Options.cimport_from_pyx: return self.find_pyx_file(qualified_name, pos) return pxd def find_pyx_file(self, qualified_name, pos): # Search include path for the .pyx file corresponding to the # given fully-qualified module name, as for find_pxd_file(). return self.search_include_directories(qualified_name, ".pyx", pos) def find_include_file(self, filename, pos): # Search list of include directories for filename. # Reports an error and returns None if not found. path = self.search_include_directories(filename, "", pos, include=True) if not path: error(pos, "'%s' not found" % filename) return path def search_include_directories(self, qualified_name, suffix, pos, include=False, sys_path=False): return Utils.search_include_directories( tuple(self.include_directories), qualified_name, suffix, pos, include, sys_path) def find_root_package_dir(self, file_path): return Utils.find_root_package_dir(file_path) def check_package_dir(self, dir, package_names): return Utils.check_package_dir(dir, tuple(package_names)) def c_file_out_of_date(self, source_path): c_path = Utils.replace_suffix(source_path, ".c") if not os.path.exists(c_path): return 1 c_time = Utils.modification_time(c_path) if Utils.file_newer_than(source_path, c_time): return 1 pos = [source_path] pxd_path = Utils.replace_suffix(source_path, ".pxd") if os.path.exists(pxd_path) and Utils.file_newer_than(pxd_path, c_time): return 1 for kind, name in self.read_dependency_file(source_path): if kind == "cimport": dep_path = self.find_pxd_file(name, pos) elif kind == "include": dep_path = self.search_include_directories(name, pos) else: continue if dep_path and Utils.file_newer_than(dep_path, c_time): return 1 return 0 def find_cimported_module_names(self, source_path): return [ name for kind, name in self.read_dependency_file(source_path) if kind == "cimport" ] def is_package_dir(self, dir_path): return Utils.is_package_dir(dir_path) def read_dependency_file(self, source_path): dep_path = Utils.replace_suffix(source_path, ".dep") if os.path.exists(dep_path): f = open(dep_path, "rU") chunks = [ line.strip().split(" ", 1) for line in f.readlines() if " " in line.strip() ] f.close() return chunks else: return () def lookup_submodule(self, name): # Look up a top-level module. Returns None if not found. return self.modules.get(name, None) def find_submodule(self, name): # Find a top-level module, creating a new one if needed. scope = self.lookup_submodule(name) if not scope: scope = ModuleScope(name, parent_module = None, context = self) self.modules[name] = scope return scope def parse(self, source_desc, scope, pxd, full_module_name): if not isinstance(source_desc, FileSourceDescriptor): raise RuntimeError("Only file sources for code supported") source_filename = source_desc.filename scope.cpp = self.cpp # Parse the given source file and return a parse tree. num_errors = Errors.num_errors try: f = Utils.open_source_file(source_filename, "rU") try: import Parsing s = PyrexScanner(f, source_desc, source_encoding = f.encoding, scope = scope, context = self) tree = Parsing.p_module(s, pxd, full_module_name) finally: f.close() except UnicodeDecodeError, e: #import traceback #traceback.print_exc() line = 1 column = 0 msg = e.args[-1] position = e.args[2] encoding = e.args[0] f = open(source_filename, "rb") try: byte_data = f.read() finally: f.close() # FIXME: make this at least a little less inefficient for idx, c in enumerate(byte_data): if c in (ord('\n'), '\n'): line += 1 column = 0 if idx == position: break column += 1 error((source_desc, line, column), "Decoding error, missing or incorrect coding= " "at top of source (cannot decode with encoding %r: %s)" % (encoding, msg)) if Errors.num_errors > num_errors: raise CompileError() return tree def extract_module_name(self, path, options): # Find fully_qualified module name from the full pathname # of a source file. dir, filename = os.path.split(path) module_name, _ = os.path.splitext(filename) if "." in module_name: return module_name names = [module_name] while self.is_package_dir(dir): parent, package_name = os.path.split(dir) if parent == dir: break names.append(package_name) dir = parent names.reverse() return ".".join(names) def setup_errors(self, options, result): Errors.reset() # clear any remaining error state if options.use_listing_file: result.listing_file = Utils.replace_suffix(source, ".lis") path = result.listing_file else: path = None Errors.open_listing_file(path=path, echo_to_stderr=options.errors_to_stderr) def teardown_errors(self, err, options, result): source_desc = result.compilation_source.source_desc if not isinstance(source_desc, FileSourceDescriptor): raise RuntimeError("Only file sources for code supported") Errors.close_listing_file() result.num_errors = Errors.num_errors if result.num_errors > 0: err = True if err and result.c_file: try: Utils.castrate_file(result.c_file, os.stat(source_desc.filename)) except EnvironmentError: pass result.c_file = None def create_default_resultobj(compilation_source, options): result = CompilationResult() result.main_source_file = compilation_source.source_desc.filename result.compilation_source = compilation_source source_desc = compilation_source.source_desc if options.output_file: result.c_file = os.path.join(compilation_source.cwd, options.output_file) else: if options.cplus: c_suffix = ".cpp" else: c_suffix = ".c" result.c_file = Utils.replace_suffix(source_desc.filename, c_suffix) return result def run_pipeline(source, options, full_module_name=None, context=None): import Pipeline source_ext = os.path.splitext(source)[1] options.configure_language_defaults(source_ext[1:]) # py/pyx if context is None: context = options.create_context() # Set up source object cwd = os.getcwd() abs_path = os.path.abspath(source) full_module_name = full_module_name or context.extract_module_name(source, options) if options.relative_path_in_code_position_comments: rel_path = full_module_name.replace('.', os.sep) + source_ext if not abs_path.endswith(rel_path): rel_path = source # safety measure to prevent printing incorrect paths else: rel_path = abs_path source_desc = FileSourceDescriptor(abs_path, rel_path) source = CompilationSource(source_desc, full_module_name, cwd) # Set up result object result = create_default_resultobj(source, options) if options.annotate is None: # By default, decide based on whether an html file already exists. html_filename = os.path.splitext(result.c_file)[0] + ".html" if os.path.exists(html_filename): line = codecs.open(html_filename, "r", encoding="UTF-8").readline() if line.startswith(u' State %d\n" % (key, state['number'])) for key in ('bol', 'eol', 'eof', 'else'): state = special_to_state.get(key, None) if state: file.write(" %s --> State %d\n" % (key, state['number'])) def chars_to_ranges(self, char_list): char_list.sort() i = 0 n = len(char_list) result = [] while i < n: c1 = ord(char_list[i]) c2 = c1 i = i + 1 while i < n and ord(char_list[i]) == c2 + 1: i = i + 1 c2 = c2 + 1 result.append((chr(c1), chr(c2))) return tuple(result) def ranges_to_string(self, range_list): return ','.join(map(self.range_to_string, range_list)) def range_to_string(self, range_tuple): (c1, c2) = range_tuple if c1 == c2: return repr(c1) else: return "%s..%s" % (repr(c1), repr(c2)) cython-0.20.1+git90-g0e6e38e/Cython/Plex/Regexps.py000066400000000000000000000375051231323242300214220ustar00rootroot00000000000000#======================================================================= # # Python Lexical Analyser # # Regular Expressions # #======================================================================= import types from sys import maxint as maxint import Errors # # Constants # BOL = 'bol' EOL = 'eol' EOF = 'eof' nl_code = ord('\n') # # Helper functions # def chars_to_ranges(s): """ Return a list of character codes consisting of pairs [code1a, code1b, code2a, code2b,...] which cover all the characters in |s|. """ char_list = list(s) char_list.sort() i = 0 n = len(char_list) result = [] while i < n: code1 = ord(char_list[i]) code2 = code1 + 1 i = i + 1 while i < n and code2 >= ord(char_list[i]): code2 = code2 + 1 i = i + 1 result.append(code1) result.append(code2) return result def uppercase_range(code1, code2): """ If the range of characters from code1 to code2-1 includes any lower case letters, return the corresponding upper case range. """ code3 = max(code1, ord('a')) code4 = min(code2, ord('z') + 1) if code3 < code4: d = ord('A') - ord('a') return (code3 + d, code4 + d) else: return None def lowercase_range(code1, code2): """ If the range of characters from code1 to code2-1 includes any upper case letters, return the corresponding lower case range. """ code3 = max(code1, ord('A')) code4 = min(code2, ord('Z') + 1) if code3 < code4: d = ord('a') - ord('A') return (code3 + d, code4 + d) else: return None def CodeRanges(code_list): """ Given a list of codes as returned by chars_to_ranges, return an RE which will match a character in any of the ranges. """ re_list = [] for i in xrange(0, len(code_list), 2): re_list.append(CodeRange(code_list[i], code_list[i + 1])) return Alt(*re_list) def CodeRange(code1, code2): """ CodeRange(code1, code2) is an RE which matches any character with a code |c| in the range |code1| <= |c| < |code2|. """ if code1 <= nl_code < code2: return Alt(RawCodeRange(code1, nl_code), RawNewline, RawCodeRange(nl_code + 1, code2)) else: return RawCodeRange(code1, code2) # # Abstract classes # class RE(object): """RE is the base class for regular expression constructors. The following operators are defined on REs: re1 + re2 is an RE which matches |re1| followed by |re2| re1 | re2 is an RE which matches either |re1| or |re2| """ nullable = 1 # True if this RE can match 0 input symbols match_nl = 1 # True if this RE can match a string ending with '\n' str = None # Set to a string to override the class's __str__ result def build_machine(self, machine, initial_state, final_state, match_bol, nocase): """ This method should add states to |machine| to implement this RE, starting at |initial_state| and ending at |final_state|. If |match_bol| is true, the RE must be able to match at the beginning of a line. If nocase is true, upper and lower case letters should be treated as equivalent. """ raise NotImplementedError("%s.build_machine not implemented" % self.__class__.__name__) def build_opt(self, m, initial_state, c): """ Given a state |s| of machine |m|, return a new state reachable from |s| on character |c| or epsilon. """ s = m.new_state() initial_state.link_to(s) initial_state.add_transition(c, s) return s def __add__(self, other): return Seq(self, other) def __or__(self, other): return Alt(self, other) def __str__(self): if self.str: return self.str else: return self.calc_str() def check_re(self, num, value): if not isinstance(value, RE): self.wrong_type(num, value, "Plex.RE instance") def check_string(self, num, value): if type(value) != type(''): self.wrong_type(num, value, "string") def check_char(self, num, value): self.check_string(num, value) if len(value) != 1: raise Errors.PlexValueError("Invalid value for argument %d of Plex.%s." "Expected a string of length 1, got: %s" % ( num, self.__class__.__name__, repr(value))) def wrong_type(self, num, value, expected): if type(value) == types.InstanceType: got = "%s.%s instance" % ( value.__class__.__module__, value.__class__.__name__) else: got = type(value).__name__ raise Errors.PlexTypeError("Invalid type for argument %d of Plex.%s " "(expected %s, got %s" % ( num, self.__class__.__name__, expected, got)) # # Primitive RE constructors # ------------------------- # # These are the basic REs from which all others are built. # ## class Char(RE): ## """ ## Char(c) is an RE which matches the character |c|. ## """ ## nullable = 0 ## def __init__(self, char): ## self.char = char ## self.match_nl = char == '\n' ## def build_machine(self, m, initial_state, final_state, match_bol, nocase): ## c = self.char ## if match_bol and c != BOL: ## s1 = self.build_opt(m, initial_state, BOL) ## else: ## s1 = initial_state ## if c == '\n' or c == EOF: ## s1 = self.build_opt(m, s1, EOL) ## if len(c) == 1: ## code = ord(self.char) ## s1.add_transition((code, code+1), final_state) ## if nocase and is_letter_code(code): ## code2 = other_case_code(code) ## s1.add_transition((code2, code2+1), final_state) ## else: ## s1.add_transition(c, final_state) ## def calc_str(self): ## return "Char(%s)" % repr(self.char) def Char(c): """ Char(c) is an RE which matches the character |c|. """ if len(c) == 1: result = CodeRange(ord(c), ord(c) + 1) else: result = SpecialSymbol(c) result.str = "Char(%s)" % repr(c) return result class RawCodeRange(RE): """ RawCodeRange(code1, code2) is a low-level RE which matches any character with a code |c| in the range |code1| <= |c| < |code2|, where the range does not include newline. For internal use only. """ nullable = 0 match_nl = 0 range = None # (code, code) uppercase_range = None # (code, code) or None lowercase_range = None # (code, code) or None def __init__(self, code1, code2): self.range = (code1, code2) self.uppercase_range = uppercase_range(code1, code2) self.lowercase_range = lowercase_range(code1, code2) def build_machine(self, m, initial_state, final_state, match_bol, nocase): if match_bol: initial_state = self.build_opt(m, initial_state, BOL) initial_state.add_transition(self.range, final_state) if nocase: if self.uppercase_range: initial_state.add_transition(self.uppercase_range, final_state) if self.lowercase_range: initial_state.add_transition(self.lowercase_range, final_state) def calc_str(self): return "CodeRange(%d,%d)" % (self.code1, self.code2) class _RawNewline(RE): """ RawNewline is a low-level RE which matches a newline character. For internal use only. """ nullable = 0 match_nl = 1 def build_machine(self, m, initial_state, final_state, match_bol, nocase): if match_bol: initial_state = self.build_opt(m, initial_state, BOL) s = self.build_opt(m, initial_state, EOL) s.add_transition((nl_code, nl_code + 1), final_state) RawNewline = _RawNewline() class SpecialSymbol(RE): """ SpecialSymbol(sym) is an RE which matches the special input symbol |sym|, which is one of BOL, EOL or EOF. """ nullable = 0 match_nl = 0 sym = None def __init__(self, sym): self.sym = sym def build_machine(self, m, initial_state, final_state, match_bol, nocase): # Sequences 'bol bol' and 'bol eof' are impossible, so only need # to allow for bol if sym is eol if match_bol and self.sym == EOL: initial_state = self.build_opt(m, initial_state, BOL) initial_state.add_transition(self.sym, final_state) class Seq(RE): """Seq(re1, re2, re3...) is an RE which matches |re1| followed by |re2| followed by |re3|...""" def __init__(self, *re_list): nullable = 1 for i in xrange(len(re_list)): re = re_list[i] self.check_re(i, re) nullable = nullable and re.nullable self.re_list = re_list self.nullable = nullable i = len(re_list) match_nl = 0 while i: i = i - 1 re = re_list[i] if re.match_nl: match_nl = 1 break if not re.nullable: break self.match_nl = match_nl def build_machine(self, m, initial_state, final_state, match_bol, nocase): re_list = self.re_list if len(re_list) == 0: initial_state.link_to(final_state) else: s1 = initial_state n = len(re_list) for i in xrange(n): if i < n - 1: s2 = m.new_state() else: s2 = final_state re = re_list[i] re.build_machine(m, s1, s2, match_bol, nocase) s1 = s2 match_bol = re.match_nl or (match_bol and re.nullable) def calc_str(self): return "Seq(%s)" % ','.join(map(str, self.re_list)) class Alt(RE): """Alt(re1, re2, re3...) is an RE which matches either |re1| or |re2| or |re3|...""" def __init__(self, *re_list): self.re_list = re_list nullable = 0 match_nl = 0 nullable_res = [] non_nullable_res = [] i = 1 for re in re_list: self.check_re(i, re) if re.nullable: nullable_res.append(re) nullable = 1 else: non_nullable_res.append(re) if re.match_nl: match_nl = 1 i = i + 1 self.nullable_res = nullable_res self.non_nullable_res = non_nullable_res self.nullable = nullable self.match_nl = match_nl def build_machine(self, m, initial_state, final_state, match_bol, nocase): for re in self.nullable_res: re.build_machine(m, initial_state, final_state, match_bol, nocase) if self.non_nullable_res: if match_bol: initial_state = self.build_opt(m, initial_state, BOL) for re in self.non_nullable_res: re.build_machine(m, initial_state, final_state, 0, nocase) def calc_str(self): return "Alt(%s)" % ','.join(map(str, self.re_list)) class Rep1(RE): """Rep1(re) is an RE which matches one or more repetitions of |re|.""" def __init__(self, re): self.check_re(1, re) self.re = re self.nullable = re.nullable self.match_nl = re.match_nl def build_machine(self, m, initial_state, final_state, match_bol, nocase): s1 = m.new_state() s2 = m.new_state() initial_state.link_to(s1) self.re.build_machine(m, s1, s2, match_bol or self.re.match_nl, nocase) s2.link_to(s1) s2.link_to(final_state) def calc_str(self): return "Rep1(%s)" % self.re class SwitchCase(RE): """ SwitchCase(re, nocase) is an RE which matches the same strings as RE, but treating upper and lower case letters according to |nocase|. If |nocase| is true, case is ignored, otherwise it is not. """ re = None nocase = None def __init__(self, re, nocase): self.re = re self.nocase = nocase self.nullable = re.nullable self.match_nl = re.match_nl def build_machine(self, m, initial_state, final_state, match_bol, nocase): self.re.build_machine(m, initial_state, final_state, match_bol, self.nocase) def calc_str(self): if self.nocase: name = "NoCase" else: name = "Case" return "%s(%s)" % (name, self.re) # # Composite RE constructors # ------------------------- # # These REs are defined in terms of the primitive REs. # Empty = Seq() Empty.__doc__ = \ """ Empty is an RE which matches the empty string. """ Empty.str = "Empty" def Str1(s): """ Str1(s) is an RE which matches the literal string |s|. """ result = Seq(*tuple(map(Char, s))) result.str = "Str(%s)" % repr(s) return result def Str(*strs): """ Str(s) is an RE which matches the literal string |s|. Str(s1, s2, s3, ...) is an RE which matches any of |s1| or |s2| or |s3|... """ if len(strs) == 1: return Str1(strs[0]) else: result = Alt(*tuple(map(Str1, strs))) result.str = "Str(%s)" % ','.join(map(repr, strs)) return result def Any(s): """ Any(s) is an RE which matches any character in the string |s|. """ #result = apply(Alt, tuple(map(Char, s))) result = CodeRanges(chars_to_ranges(s)) result.str = "Any(%s)" % repr(s) return result def AnyBut(s): """ AnyBut(s) is an RE which matches any character (including newline) which is not in the string |s|. """ ranges = chars_to_ranges(s) ranges.insert(0, -maxint) ranges.append(maxint) result = CodeRanges(ranges) result.str = "AnyBut(%s)" % repr(s) return result AnyChar = AnyBut("") AnyChar.__doc__ = \ """ AnyChar is an RE which matches any single character (including a newline). """ AnyChar.str = "AnyChar" def Range(s1, s2 = None): """ Range(c1, c2) is an RE which matches any single character in the range |c1| to |c2| inclusive. Range(s) where |s| is a string of even length is an RE which matches any single character in the ranges |s[0]| to |s[1]|, |s[2]| to |s[3]|,... """ if s2: result = CodeRange(ord(s1), ord(s2) + 1) result.str = "Range(%s,%s)" % (s1, s2) else: ranges = [] for i in range(0, len(s1), 2): ranges.append(CodeRange(ord(s1[i]), ord(s1[i+1]) + 1)) result = Alt(*ranges) result.str = "Range(%s)" % repr(s1) return result def Opt(re): """ Opt(re) is an RE which matches either |re| or the empty string. """ result = Alt(re, Empty) result.str = "Opt(%s)" % re return result def Rep(re): """ Rep(re) is an RE which matches zero or more repetitions of |re|. """ result = Opt(Rep1(re)) result.str = "Rep(%s)" % re return result def NoCase(re): """ NoCase(re) is an RE which matches the same strings as RE, but treating upper and lower case letters as equivalent. """ return SwitchCase(re, nocase = 1) def Case(re): """ Case(re) is an RE which matches the same strings as RE, but treating upper and lower case letters as distinct, i.e. it cancels the effect of any enclosing NoCase(). """ return SwitchCase(re, nocase = 0) # # RE Constants # Bol = Char(BOL) Bol.__doc__ = \ """ Bol is an RE which matches the beginning of a line. """ Bol.str = "Bol" Eol = Char(EOL) Eol.__doc__ = \ """ Eol is an RE which matches the end of a line. """ Eol.str = "Eol" Eof = Char(EOF) Eof.__doc__ = \ """ Eof is an RE which matches the end of the file. """ Eof.str = "Eof" cython-0.20.1+git90-g0e6e38e/Cython/Plex/Scanners.pxd000066400000000000000000000023621231323242300217150ustar00rootroot00000000000000import cython from Cython.Plex.Actions cimport Action cdef class Scanner: cdef public lexicon cdef public stream cdef public name cdef public unicode buffer cdef public Py_ssize_t buf_start_pos cdef public Py_ssize_t next_pos cdef public Py_ssize_t cur_pos cdef public Py_ssize_t cur_line cdef public Py_ssize_t cur_line_start cdef public Py_ssize_t start_pos cdef public Py_ssize_t start_line cdef public Py_ssize_t start_col cdef public text cdef public initial_state # int? cdef public state_name cdef public list queue cdef public bint trace cdef public cur_char cdef public int input_state cdef public level @cython.locals(input_state=long) cdef next_char(self) @cython.locals(action=Action) cdef tuple read(self) cdef tuple scan_a_token(self) cdef tuple position(self) @cython.locals(cur_pos=long, cur_line=long, cur_line_start=long, input_state=long, next_pos=long, state=dict, buf_start_pos=long, buf_len=long, buf_index=long, trace=bint, discard=long, data=unicode, buffer=unicode) cdef run_machine_inlined(self) cdef begin(self, state) cdef produce(self, value, text = *) cython-0.20.1+git90-g0e6e38e/Cython/Plex/Scanners.py000066400000000000000000000246041231323242300215550ustar00rootroot00000000000000#======================================================================= # # Python Lexical Analyser # # # Scanning an input stream # #======================================================================= import cython cython.declare(BOL=object, EOL=object, EOF=object, NOT_FOUND=object) import Errors from Regexps import BOL, EOL, EOF NOT_FOUND = object() class Scanner(object): """ A Scanner is used to read tokens from a stream of characters using the token set specified by a Plex.Lexicon. Constructor: Scanner(lexicon, stream, name = '') See the docstring of the __init__ method for details. Methods: See the docstrings of the individual methods for more information. read() --> (value, text) Reads the next lexical token from the stream. position() --> (name, line, col) Returns the position of the last token read using the read() method. begin(state_name) Causes scanner to change state. produce(value [, text]) Causes return of a token value to the caller of the Scanner. """ # lexicon = None # Lexicon # stream = None # file-like object # name = '' # buffer = '' # buf_start_pos = 0 # position in input of start of buffer # next_pos = 0 # position in input of next char to read # cur_pos = 0 # position in input of current char # cur_line = 1 # line number of current char # cur_line_start = 0 # position in input of start of current line # start_pos = 0 # position in input of start of token # start_line = 0 # line number of start of token # start_col = 0 # position in line of start of token # text = None # text of last token read # initial_state = None # Node # state_name = '' # Name of initial state # queue = None # list of tokens to be returned # trace = 0 def __init__(self, lexicon, stream, name = '', initial_pos = None): """ Scanner(lexicon, stream, name = '') |lexicon| is a Plex.Lexicon instance specifying the lexical tokens to be recognised. |stream| can be a file object or anything which implements a compatible read() method. |name| is optional, and may be the name of the file being scanned or any other identifying string. """ self.trace = 0 self.buffer = u'' self.buf_start_pos = 0 self.next_pos = 0 self.cur_pos = 0 self.cur_line = 1 self.start_pos = 0 self.start_line = 0 self.start_col = 0 self.text = None self.state_name = None self.lexicon = lexicon self.stream = stream self.name = name self.queue = [] self.initial_state = None self.begin('') self.next_pos = 0 self.cur_pos = 0 self.cur_line_start = 0 self.cur_char = BOL self.input_state = 1 if initial_pos is not None: self.cur_line, self.cur_line_start = initial_pos[1], -initial_pos[2] def read(self): """ Read the next lexical token from the stream and return a tuple (value, text), where |value| is the value associated with the token as specified by the Lexicon, and |text| is the actual string read from the stream. Returns (None, '') on end of file. """ queue = self.queue while not queue: self.text, action = self.scan_a_token() if action is None: self.produce(None) self.eof() else: value = action.perform(self, self.text) if value is not None: self.produce(value) result = queue[0] del queue[0] return result def scan_a_token(self): """ Read the next input sequence recognised by the machine and return (text, action). Returns ('', None) on end of file. """ self.start_pos = self.cur_pos self.start_line = self.cur_line self.start_col = self.cur_pos - self.cur_line_start action = self.run_machine_inlined() if action is not None: if self.trace: print("Scanner: read: Performing %s %d:%d" % ( action, self.start_pos, self.cur_pos)) text = self.buffer[self.start_pos - self.buf_start_pos : self.cur_pos - self.buf_start_pos] return (text, action) else: if self.cur_pos == self.start_pos: if self.cur_char is EOL: self.next_char() if self.cur_char is None or self.cur_char is EOF: return (u'', None) raise Errors.UnrecognizedInput(self, self.state_name) def run_machine_inlined(self): """ Inlined version of run_machine for speed. """ state = self.initial_state cur_pos = self.cur_pos cur_line = self.cur_line cur_line_start = self.cur_line_start cur_char = self.cur_char input_state = self.input_state next_pos = self.next_pos buffer = self.buffer buf_start_pos = self.buf_start_pos buf_len = len(buffer) b_action, b_cur_pos, b_cur_line, b_cur_line_start, b_cur_char, b_input_state, b_next_pos = \ None, 0, 0, 0, u'', 0, 0 trace = self.trace while 1: if trace: #TRACE# print("State %d, %d/%d:%s -->" % ( #TRACE# state['number'], input_state, cur_pos, repr(cur_char))) #TRACE# # Begin inlined self.save_for_backup() #action = state.action #@slow action = state['action'] #@fast if action is not None: b_action, b_cur_pos, b_cur_line, b_cur_line_start, b_cur_char, b_input_state, b_next_pos = \ action, cur_pos, cur_line, cur_line_start, cur_char, input_state, next_pos # End inlined self.save_for_backup() c = cur_char #new_state = state.new_state(c) #@slow new_state = state.get(c, NOT_FOUND) #@fast if new_state is NOT_FOUND: #@fast new_state = c and state.get('else') #@fast if new_state: if trace: #TRACE# print("State %d" % new_state['number']) #TRACE# state = new_state # Begin inlined: self.next_char() if input_state == 1: cur_pos = next_pos # Begin inlined: c = self.read_char() buf_index = next_pos - buf_start_pos if buf_index < buf_len: c = buffer[buf_index] next_pos = next_pos + 1 else: discard = self.start_pos - buf_start_pos data = self.stream.read(0x1000) buffer = self.buffer[discard:] + data self.buffer = buffer buf_start_pos = buf_start_pos + discard self.buf_start_pos = buf_start_pos buf_len = len(buffer) buf_index = buf_index - discard if data: c = buffer[buf_index] next_pos = next_pos + 1 else: c = u'' # End inlined: c = self.read_char() if c == u'\n': cur_char = EOL input_state = 2 elif not c: cur_char = EOL input_state = 4 else: cur_char = c elif input_state == 2: cur_char = u'\n' input_state = 3 elif input_state == 3: cur_line = cur_line + 1 cur_line_start = cur_pos = next_pos cur_char = BOL input_state = 1 elif input_state == 4: cur_char = EOF input_state = 5 else: # input_state = 5 cur_char = u'' # End inlined self.next_char() else: # not new_state if trace: #TRACE# print("blocked") #TRACE# # Begin inlined: action = self.back_up() if b_action is not None: (action, cur_pos, cur_line, cur_line_start, cur_char, input_state, next_pos) = \ (b_action, b_cur_pos, b_cur_line, b_cur_line_start, b_cur_char, b_input_state, b_next_pos) else: action = None break # while 1 # End inlined: action = self.back_up() self.cur_pos = cur_pos self.cur_line = cur_line self.cur_line_start = cur_line_start self.cur_char = cur_char self.input_state = input_state self.next_pos = next_pos if trace: #TRACE# if action is not None: #TRACE# print("Doing %s" % action) #TRACE# return action def next_char(self): input_state = self.input_state if self.trace: print("Scanner: next: %s [%d] %d" % (" "*20, input_state, self.cur_pos)) if input_state == 1: self.cur_pos = self.next_pos c = self.read_char() if c == u'\n': self.cur_char = EOL self.input_state = 2 elif not c: self.cur_char = EOL self.input_state = 4 else: self.cur_char = c elif input_state == 2: self.cur_char = u'\n' self.input_state = 3 elif input_state == 3: self.cur_line = self.cur_line + 1 self.cur_line_start = self.cur_pos = self.next_pos self.cur_char = BOL self.input_state = 1 elif input_state == 4: self.cur_char = EOF self.input_state = 5 else: # input_state = 5 self.cur_char = u'' if self.trace: print("--> [%d] %d %s" % (input_state, self.cur_pos, repr(self.cur_char))) def position(self): """ Return a tuple (name, line, col) representing the location of the last token read using the read() method. |name| is the name that was provided to the Scanner constructor; |line| is the line number in the stream (1-based); |col| is the position within the line of the first character of the token (0-based). """ return (self.name, self.start_line, self.start_col) def get_position(self): """Python accessible wrapper around position(), only for error reporting. """ return self.position() def begin(self, state_name): """Set the current state of the scanner to the named state.""" self.initial_state = ( self.lexicon.get_initial_state(state_name)) self.state_name = state_name def produce(self, value, text = None): """ Called from an action procedure, causes |value| to be returned as the token value from read(). If |text| is supplied, it is returned in place of the scanned text. produce() can be called more than once during a single call to an action procedure, in which case the tokens are queued up and returned one at a time by subsequent calls to read(), until the queue is empty, whereupon scanning resumes. """ if text is None: text = self.text self.queue.append((value, text)) def eof(self): """ Override this method if you want something to be done at end of file. """ cython-0.20.1+git90-g0e6e38e/Cython/Plex/Timing.py000066400000000000000000000006231231323242300212230ustar00rootroot00000000000000# # Get time in platform-dependent way # import os from sys import platform, exit, stderr if platform == 'mac': import MacOS def time(): return MacOS.GetTicks() / 60.0 timekind = "real" elif hasattr(os, 'times'): def time(): t = os.times() return t[0] + t[1] timekind = "cpu" else: stderr.write( "Don't know how to get time on platform %s\n" % repr(platform)) exit(1) cython-0.20.1+git90-g0e6e38e/Cython/Plex/Traditional.py000066400000000000000000000066561231323242300222620ustar00rootroot00000000000000#======================================================================= # # Python Lexical Analyser # # Traditional Regular Expression Syntax # #======================================================================= from Regexps import Alt, Seq, Rep, Rep1, Opt, Any, AnyBut, Bol, Eol, Char from Errors import PlexError class RegexpSyntaxError(PlexError): pass def re(s): """ Convert traditional string representation of regular expression |s| into Plex representation. """ return REParser(s).parse_re() class REParser(object): def __init__(self, s): self.s = s self.i = -1 self.end = 0 self.next() def parse_re(self): re = self.parse_alt() if not self.end: self.error("Unexpected %s" % repr(self.c)) return re def parse_alt(self): """Parse a set of alternative regexps.""" re = self.parse_seq() if self.c == '|': re_list = [re] while self.c == '|': self.next() re_list.append(self.parse_seq()) re = Alt(*re_list) return re def parse_seq(self): """Parse a sequence of regexps.""" re_list = [] while not self.end and not self.c in "|)": re_list.append(self.parse_mod()) return Seq(*re_list) def parse_mod(self): """Parse a primitive regexp followed by *, +, ? modifiers.""" re = self.parse_prim() while not self.end and self.c in "*+?": if self.c == '*': re = Rep(re) elif self.c == '+': re = Rep1(re) else: # self.c == '?' re = Opt(re) self.next() return re def parse_prim(self): """Parse a primitive regexp.""" c = self.get() if c == '.': re = AnyBut("\n") elif c == '^': re = Bol elif c == '$': re = Eol elif c == '(': re = self.parse_alt() self.expect(')') elif c == '[': re = self.parse_charset() self.expect(']') else: if c == '\\': c = self.get() re = Char(c) return re def parse_charset(self): """Parse a charset. Does not include the surrounding [].""" char_list = [] invert = 0 if self.c == '^': invert = 1 self.next() if self.c == ']': char_list.append(']') self.next() while not self.end and self.c != ']': c1 = self.get() if self.c == '-' and self.lookahead(1) != ']': self.next() c2 = self.get() for a in xrange(ord(c1), ord(c2) + 1): char_list.append(chr(a)) else: char_list.append(c1) chars = ''.join(char_list) if invert: return AnyBut(chars) else: return Any(chars) def next(self): """Advance to the next char.""" s = self.s i = self.i = self.i + 1 if i < len(s): self.c = s[i] else: self.c = '' self.end = 1 def get(self): if self.end: self.error("Premature end of string") c = self.c self.next() return c def lookahead(self, n): """Look ahead n chars.""" j = self.i + n if j < len(self.s): return self.s[j] else: return '' def expect(self, c): """ Expect to find character |c| at current position. Raises an exception otherwise. """ if self.c == c: self.next() else: self.error("Missing %s" % repr(c)) def error(self, mess): """Raise exception to signal syntax error in regexp.""" raise RegexpSyntaxError("Syntax error in regexp %s at position %d: %s" % ( repr(self.s), self.i, mess)) cython-0.20.1+git90-g0e6e38e/Cython/Plex/Transitions.py000066400000000000000000000140211231323242300223060ustar00rootroot00000000000000# # Plex - Transition Maps # # This version represents state sets direcly as dicts # for speed. # from sys import maxint as maxint class TransitionMap(object): """ A TransitionMap maps an input event to a set of states. An input event is one of: a range of character codes, the empty string (representing an epsilon move), or one of the special symbols BOL, EOL, EOF. For characters, this implementation compactly represents the map by means of a list: [code_0, states_0, code_1, states_1, code_2, states_2, ..., code_n-1, states_n-1, code_n] where |code_i| is a character code, and |states_i| is a set of states corresponding to characters with codes |c| in the range |code_i| <= |c| <= |code_i+1|. The following invariants hold: n >= 1 code_0 == -maxint code_n == maxint code_i < code_i+1 for i in 0..n-1 states_0 == states_n-1 Mappings for the special events '', BOL, EOL, EOF are kept separately in a dictionary. """ map = None # The list of codes and states special = None # Mapping for special events def __init__(self, map = None, special = None): if not map: map = [-maxint, {}, maxint] if not special: special = {} self.map = map self.special = special #self.check() ### def add(self, event, new_state, TupleType = tuple): """ Add transition to |new_state| on |event|. """ if type(event) is TupleType: code0, code1 = event i = self.split(code0) j = self.split(code1) map = self.map while i < j: map[i + 1][new_state] = 1 i = i + 2 else: self.get_special(event)[new_state] = 1 def add_set(self, event, new_set, TupleType = tuple): """ Add transitions to the states in |new_set| on |event|. """ if type(event) is TupleType: code0, code1 = event i = self.split(code0) j = self.split(code1) map = self.map while i < j: map[i + 1].update(new_set) i = i + 2 else: self.get_special(event).update(new_set) def get_epsilon(self, none = None): """ Return the mapping for epsilon, or None. """ return self.special.get('', none) def iteritems(self, len = len): """ Return the mapping as an iterable of ((code1, code2), state_set) and (special_event, state_set) pairs. """ result = [] map = self.map else_set = map[1] i = 0 n = len(map) - 1 code0 = map[0] while i < n: set = map[i + 1] code1 = map[i + 2] if set or else_set: result.append(((code0, code1), set)) code0 = code1 i = i + 2 for event, set in self.special.iteritems(): if set: result.append((event, set)) return iter(result) items = iteritems # ------------------- Private methods -------------------- def split(self, code, len = len, maxint = maxint): """ Search the list for the position of the split point for |code|, inserting a new split point if necessary. Returns index |i| such that |code| == |map[i]|. """ # We use a funky variation on binary search. map = self.map hi = len(map) - 1 # Special case: code == map[-1] if code == maxint: return hi # General case lo = 0 # loop invariant: map[lo] <= code < map[hi] and hi - lo >= 2 while hi - lo >= 4: # Find midpoint truncated to even index mid = ((lo + hi) // 2) & ~1 if code < map[mid]: hi = mid else: lo = mid # map[lo] <= code < map[hi] and hi - lo == 2 if map[lo] == code: return lo else: map[hi:hi] = [code, map[hi - 1].copy()] #self.check() ### return hi def get_special(self, event): """ Get state set for special event, adding a new entry if necessary. """ special = self.special set = special.get(event, None) if not set: set = {} special[event] = set return set # --------------------- Conversion methods ----------------------- def __str__(self): map_strs = [] map = self.map n = len(map) i = 0 while i < n: code = map[i] if code == -maxint: code_str = "-inf" elif code == maxint: code_str = "inf" else: code_str = str(code) map_strs.append(code_str) i = i + 1 if i < n: map_strs.append(state_set_str(map[i])) i = i + 1 special_strs = {} for event, set in self.special.iteritems(): special_strs[event] = state_set_str(set) return "[%s]+%s" % ( ','.join(map_strs), special_strs ) # --------------------- Debugging methods ----------------------- def check(self): """Check data structure integrity.""" if not self.map[-3] < self.map[-1]: print(self) assert 0 def dump(self, file): map = self.map i = 0 n = len(map) - 1 while i < n: self.dump_range(map[i], map[i + 2], map[i + 1], file) i = i + 2 for event, set in self.special.iteritems(): if set: if not event: event = 'empty' self.dump_trans(event, set, file) def dump_range(self, code0, code1, set, file): if set: if code0 == -maxint: if code1 == maxint: k = "any" else: k = "< %s" % self.dump_char(code1) elif code1 == maxint: k = "> %s" % self.dump_char(code0 - 1) elif code0 == code1 - 1: k = self.dump_char(code0) else: k = "%s..%s" % (self.dump_char(code0), self.dump_char(code1 - 1)) self.dump_trans(k, set, file) def dump_char(self, code): if 0 <= code <= 255: return repr(chr(code)) else: return "chr(%d)" % code def dump_trans(self, key, set, file): file.write(" %s --> %s\n" % (key, self.dump_set(set))) def dump_set(self, set): return state_set_str(set) # # State set manipulation functions # #def merge_state_sets(set1, set2): # for state in set2.keys(): # set1[state] = 1 def state_set_str(set): return "[%s]" % ','.join(["S%d" % state.number for state in set]) cython-0.20.1+git90-g0e6e38e/Cython/Plex/__init__.py000066400000000000000000000023301231323242300215300ustar00rootroot00000000000000#======================================================================= # # Python Lexical Analyser # #======================================================================= """ The Plex module provides lexical analysers with similar capabilities to GNU Flex. The following classes and functions are exported; see the attached docstrings for more information. Scanner For scanning a character stream under the direction of a Lexicon. Lexicon For constructing a lexical definition to be used by a Scanner. Str, Any, AnyBut, AnyChar, Seq, Alt, Opt, Rep, Rep1, Bol, Eol, Eof, Empty Regular expression constructors, for building pattern definitions for a Lexicon. State For defining scanner states when creating a Lexicon. TEXT, IGNORE, Begin Actions for associating with patterns when creating a Lexicon. """ from Actions import TEXT, IGNORE, Begin from Lexicons import Lexicon, State from Regexps import RE, Seq, Alt, Rep1, Empty, Str, Any, AnyBut, AnyChar, Range from Regexps import Opt, Rep, Bol, Eol, Eof, Case, NoCase from Scanners import Scanner cython-0.20.1+git90-g0e6e38e/Cython/Runtime/000077500000000000000000000000001231323242300201345ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Cython/Runtime/__init__.py000066400000000000000000000000151231323242300222410ustar00rootroot00000000000000# empty file cython-0.20.1+git90-g0e6e38e/Cython/Runtime/refnanny.pyx000066400000000000000000000142511231323242300225210ustar00rootroot00000000000000from cpython.ref cimport PyObject, Py_INCREF, Py_DECREF, Py_XDECREF, Py_XINCREF from cpython.exc cimport PyErr_Fetch, PyErr_Restore from cpython.pystate cimport PyThreadState_Get cimport cython loglevel = 0 reflog = [] cdef log(level, action, obj, lineno): if loglevel >= level: reflog.append((lineno, action, id(obj))) LOG_NONE, LOG_ALL = range(2) @cython.final cdef class Context(object): cdef readonly object name, filename cdef readonly dict refs cdef readonly list errors cdef readonly Py_ssize_t start def __cinit__(self, name, line=0, filename=None): self.name = name self.start = line self.filename = filename self.refs = {} # id -> (count, [lineno]) self.errors = [] cdef regref(self, obj, lineno, bint is_null): log(LOG_ALL, u'regref', u"" if is_null else obj, lineno) if is_null: self.errors.append(u"NULL argument on line %d" % lineno) return id_ = id(obj) count, linenumbers = self.refs.get(id_, (0, [])) self.refs[id_] = (count + 1, linenumbers) linenumbers.append(lineno) cdef bint delref(self, obj, lineno, bint is_null) except -1: # returns whether it is ok to do the decref operation log(LOG_ALL, u'delref', u"" if is_null else obj, lineno) if is_null: self.errors.append(u"NULL argument on line %d" % lineno) return False id_ = id(obj) count, linenumbers = self.refs.get(id_, (0, [])) if count == 0: self.errors.append(u"Too many decrefs on line %d, reference acquired on lines %r" % (lineno, linenumbers)) return False elif count == 1: del self.refs[id_] return True else: self.refs[id_] = (count - 1, linenumbers) return True cdef end(self): if self.refs: msg = u"References leaked:" for count, linenos in self.refs.itervalues(): msg += u"\n (%d) acquired on lines: %s" % (count, u", ".join([u"%d" % x for x in linenos])) self.errors.append(msg) if self.errors: return u"\n".join([u'REFNANNY: '+error for error in self.errors]) else: return None cdef void report_unraisable(object e=None): try: if e is None: import sys e = sys.exc_info()[1] print u"refnanny raised an exception: %s" % e except: pass # We absolutely cannot exit with an exception # All Python operations must happen after any existing # exception has been fetched, in case we are called from # exception-handling code. cdef PyObject* SetupContext(char* funcname, int lineno, char* filename) except NULL: if Context is None: # Context may be None during finalize phase. # In that case, we don't want to be doing anything fancy # like caching and resetting exceptions. return NULL cdef (PyObject*) type = NULL, value = NULL, tb = NULL, result = NULL PyThreadState_Get() PyErr_Fetch(&type, &value, &tb) try: ctx = Context(funcname, lineno, filename) Py_INCREF(ctx) result = ctx except Exception, e: report_unraisable(e) PyErr_Restore(type, value, tb) return result cdef void GOTREF(PyObject* ctx, PyObject* p_obj, int lineno): if ctx == NULL: return cdef (PyObject*) type = NULL, value = NULL, tb = NULL PyErr_Fetch(&type, &value, &tb) try: try: if p_obj is NULL: (ctx).regref(None, lineno, True) else: (ctx).regref(p_obj, lineno, False) except: report_unraisable() except: # __Pyx_GetException may itself raise errors pass PyErr_Restore(type, value, tb) cdef int GIVEREF_and_report(PyObject* ctx, PyObject* p_obj, int lineno): if ctx == NULL: return 1 cdef (PyObject*) type = NULL, value = NULL, tb = NULL cdef bint decref_ok = False PyErr_Fetch(&type, &value, &tb) try: try: if p_obj is NULL: decref_ok = (ctx).delref(None, lineno, True) else: decref_ok = (ctx).delref(p_obj, lineno, False) except: report_unraisable() except: # __Pyx_GetException may itself raise errors pass PyErr_Restore(type, value, tb) return decref_ok cdef void GIVEREF(PyObject* ctx, PyObject* p_obj, int lineno): GIVEREF_and_report(ctx, p_obj, lineno) cdef void INCREF(PyObject* ctx, PyObject* obj, int lineno): Py_XINCREF(obj) PyThreadState_Get() GOTREF(ctx, obj, lineno) cdef void DECREF(PyObject* ctx, PyObject* obj, int lineno): if GIVEREF_and_report(ctx, obj, lineno): Py_XDECREF(obj) PyThreadState_Get() cdef void FinishContext(PyObject** ctx): if ctx == NULL or ctx[0] == NULL: return cdef (PyObject*) type = NULL, value = NULL, tb = NULL cdef object errors = None cdef Context context PyThreadState_Get() PyErr_Fetch(&type, &value, &tb) try: try: context = ctx[0] errors = context.end() if errors: print u"%s: %s()" % (context.filename.decode('latin1'), context.name.decode('latin1')) print errors context = None except: report_unraisable() except: # __Pyx_GetException may itself raise errors pass Py_XDECREF(ctx[0]) ctx[0] = NULL PyErr_Restore(type, value, tb) ctypedef struct RefNannyAPIStruct: void (*INCREF)(PyObject*, PyObject*, int) void (*DECREF)(PyObject*, PyObject*, int) void (*GOTREF)(PyObject*, PyObject*, int) void (*GIVEREF)(PyObject*, PyObject*, int) PyObject* (*SetupContext)(char*, int, char*) except NULL void (*FinishContext)(PyObject**) cdef RefNannyAPIStruct api api.INCREF = INCREF api.DECREF = DECREF api.GOTREF = GOTREF api.GIVEREF = GIVEREF api.SetupContext = SetupContext api.FinishContext = FinishContext cdef extern from "Python.h": object PyLong_FromVoidPtr(void*) RefNannyAPI = PyLong_FromVoidPtr(&api) cython-0.20.1+git90-g0e6e38e/Cython/Shadow.py000066400000000000000000000257531231323242300203240ustar00rootroot00000000000000# cython.* namespace for pure mode. __version__ = "0.20.1post0" # BEGIN shameless copy from Cython/minivect/minitypes.py class _ArrayType(object): is_array = True subtypes = ['dtype'] def __init__(self, dtype, ndim, is_c_contig=False, is_f_contig=False, inner_contig=False, broadcasting=None): self.dtype = dtype self.ndim = ndim self.is_c_contig = is_c_contig self.is_f_contig = is_f_contig self.inner_contig = inner_contig or is_c_contig or is_f_contig self.broadcasting = broadcasting def __repr__(self): axes = [":"] * self.ndim if self.is_c_contig: axes[-1] = "::1" elif self.is_f_contig: axes[0] = "::1" return "%s[%s]" % (self.dtype, ", ".join(axes)) def index_type(base_type, item): """ Support array type creation by slicing, e.g. double[:, :] specifies a 2D strided array of doubles. The syntax is the same as for Cython memoryviews. """ assert isinstance(item, (tuple, slice)) class InvalidTypeSpecification(Exception): pass def verify_slice(s): if s.start or s.stop or s.step not in (None, 1): raise InvalidTypeSpecification( "Only a step of 1 may be provided to indicate C or " "Fortran contiguity") if isinstance(item, tuple): step_idx = None for idx, s in enumerate(item): verify_slice(s) if s.step and (step_idx or idx not in (0, len(item) - 1)): raise InvalidTypeSpecification( "Step may only be provided once, and only in the " "first or last dimension.") if s.step == 1: step_idx = idx return _ArrayType(base_type, len(item), is_c_contig=step_idx == len(item) - 1, is_f_contig=step_idx == 0) else: verify_slice(item) return _ArrayType(base_type, 1, is_c_contig=bool(item.step)) # END shameless copy compiled = False _Unspecified = object() # Function decorators def _empty_decorator(x): return x def locals(**arg_types): return _empty_decorator def test_assert_path_exists(*paths): return _empty_decorator def test_fail_if_path_exists(*paths): return _empty_decorator class _EmptyDecoratorAndManager(object): def __call__(self, x): return x def __enter__(self): pass def __exit__(self, exc_type, exc_value, traceback): pass cclass = ccall = cfunc = _EmptyDecoratorAndManager() returns = lambda type_arg: _EmptyDecoratorAndManager() final = internal = type_version_tag = no_gc_clear = _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 def compile(f): from Cython.Build.Inline import RuntimeCompiledFunction return RuntimeCompiledFunction(f) # Special functions def cdiv(a, b): q = a / b if q < 0: q += 1 def cmod(a, b): r = a % b if (a*b) < 0: r -= b return r # Emulated language constructs def cast(type, *args): if hasattr(type, '__call__'): return type(*args) else: return args[0] def sizeof(arg): return 1 def typeof(arg): return arg.__class__.__name__ # return type(arg) def address(arg): return pointer(type(arg))([arg]) def declare(type=None, value=_Unspecified, **kwds): if type not in (None, object) and hasattr(type, '__call__'): if value is not _Unspecified: return type(value) else: return type() else: return value class _nogil(object): """Support for 'with nogil' statement """ def __enter__(self): pass def __exit__(self, exc_class, exc, tb): return exc_class is None nogil = _nogil() gil = _nogil() del _nogil # Emulated types class CythonMetaType(type): def __getitem__(type, ix): return array(type, ix) CythonTypeObject = CythonMetaType('CythonTypeObject', (object,), {}) class CythonType(CythonTypeObject): def _pointer(self, n=1): for i in range(n): self = pointer(self) return self class PointerType(CythonType): def __init__(self, value=None): if isinstance(value, (ArrayType, PointerType)): self._items = [cast(self._basetype, a) for a in value._items] elif isinstance(value, list): self._items = [cast(self._basetype, a) for a in value] elif value is None or value == 0: self._items = [] else: raise ValueError def __getitem__(self, ix): if ix < 0: raise IndexError("negative indexing not allowed in C") return self._items[ix] def __setitem__(self, ix, value): if ix < 0: raise IndexError("negative indexing not allowed in C") self._items[ix] = cast(self._basetype, value) def __eq__(self, value): if value is None and not self._items: return True elif type(self) != type(value): return False else: return not self._items and not value._items def __repr__(self): return "%s *" % (self._basetype,) class ArrayType(PointerType): def __init__(self): self._items = [None] * self._n class StructType(CythonType): def __init__(self, cast_from=_Unspecified, **data): if cast_from is not _Unspecified: # do cast if len(data) > 0: raise ValueError('Cannot accept keyword arguments when casting.') if type(cast_from) is not type(self): raise ValueError('Cannot cast from %s'%cast_from) for key, value in cast_from.__dict__.items(): setattr(self, key, value) else: for key, value in data.iteritems(): setattr(self, key, value) def __setattr__(self, key, value): if key in self._members: self.__dict__[key] = cast(self._members[key], value) else: raise AttributeError("Struct has no member '%s'" % key) class UnionType(CythonType): def __init__(self, cast_from=_Unspecified, **data): if cast_from is not _Unspecified: # do type cast if len(data) > 0: raise ValueError('Cannot accept keyword arguments when casting.') if isinstance(cast_from, dict): datadict = cast_from elif type(cast_from) is type(self): datadict = cast_from.__dict__ else: raise ValueError('Cannot cast from %s'%cast_from) else: datadict = data if len(datadict) > 1: raise AttributeError("Union can only store one field at a time.") for key, value in datadict.iteritems(): setattr(self, key, value) def __setattr__(self, key, value): if key in '__dict__': CythonType.__setattr__(self, key, value) elif key in self._members: self.__dict__ = {key: cast(self._members[key], value)} else: raise AttributeError("Union has no member '%s'" % key) def pointer(basetype): class PointerInstance(PointerType): _basetype = basetype return PointerInstance def array(basetype, n): class ArrayInstance(ArrayType): _basetype = basetype _n = n return ArrayInstance def struct(**members): class StructInstance(StructType): _members = members for key in members: setattr(StructInstance, key, None) return StructInstance def union(**members): class UnionInstance(UnionType): _members = members for key in members: setattr(UnionInstance, key, None) return UnionInstance class typedef(CythonType): def __init__(self, type, name=None): self._basetype = type self.name = name def __call__(self, *arg): value = cast(self._basetype, *arg) return value def __repr__(self): return self.name or str(self._basetype) __getitem__ = index_type class _FusedType(CythonType): pass def fused_type(*args): if not args: raise TypeError("Expected at least one type as argument") # Find the numeric type with biggest rank if all types are numeric rank = -1 for type in args: if type not in (py_int, py_long, py_float, py_complex): break if type_ordering.index(type) > rank: result_type = type else: return result_type # Not a simple numeric type, return a fused type instance. The result # isn't really meant to be used, as we can't keep track of the context in # pure-mode. Casting won't do anything in this case. return _FusedType() def _specialized_from_args(signatures, args, kwargs): "Perhaps this should be implemented in a TreeFragment in Cython code" raise Exception("yet to be implemented") py_int = typedef(int, "int") try: py_long = typedef(long, "long") except NameError: # Py3 py_long = typedef(int, "long") py_float = typedef(float, "float") py_complex = typedef(complex, "double complex") # Predefined types int_types = ['char', 'short', 'Py_UNICODE', 'int', 'long', 'longlong', 'Py_ssize_t', 'size_t'] float_types = ['longdouble', 'double', 'float'] complex_types = ['longdoublecomplex', 'doublecomplex', 'floatcomplex', 'complex'] other_types = ['bint', 'void'] to_repr = { 'longlong': 'long long', 'longdouble': 'long double', 'longdoublecomplex': 'long double complex', 'doublecomplex': 'double complex', 'floatcomplex': 'float complex', }.get gs = globals() for name in int_types: reprname = to_repr(name, name) gs[name] = typedef(py_int, reprname) if name != 'Py_UNICODE' and not name.endswith('size_t'): gs['u'+name] = typedef(py_int, "unsigned " + reprname) gs['s'+name] = typedef(py_int, "signed " + reprname) for name in float_types: gs[name] = typedef(py_float, to_repr(name, name)) for name in complex_types: gs[name] = typedef(py_complex, to_repr(name, name)) bint = typedef(bool, "bint") void = typedef(int, "void") for t in int_types + float_types + complex_types + other_types: for i in range(1, 4): gs["%s_%s" % ('p'*i, t)] = globals()[t]._pointer(i) void = typedef(None, "void") NULL = p_void(0) integral = floating = numeric = _FusedType() type_ordering = [py_int, py_long, py_float, py_complex] class CythonDotParallel(object): """ The cython.parallel module. """ __all__ = ['parallel', 'prange', 'threadid'] def parallel(self, num_threads=None): return nogil def prange(self, start=0, stop=None, step=1, schedule=None, nogil=False): if stop is None: stop = start start = 0 return range(start, stop, step) def threadid(self): return 0 # def threadsavailable(self): # return 1 import sys sys.modules['cython.parallel'] = CythonDotParallel() del sys cython-0.20.1+git90-g0e6e38e/Cython/StringIOTree.py000066400000000000000000000060271231323242300214060ustar00rootroot00000000000000from cStringIO import StringIO class StringIOTree(object): """ See module docs. """ def __init__(self, stream=None): self.prepended_children = [] if stream is None: stream = StringIO() self.stream = stream self.write = stream.write self.markers = [] def getvalue(self): content = [x.getvalue() for x in self.prepended_children] content.append(self.stream.getvalue()) return "".join(content) def copyto(self, target): """Potentially cheaper than getvalue as no string concatenation needs to happen.""" for child in self.prepended_children: child.copyto(target) stream_content = self.stream.getvalue() if stream_content: target.write(stream_content) def commit(self): # Save what we have written until now so that the buffer # itself is empty -- this makes it ready for insertion if self.stream.tell(): self.prepended_children.append(StringIOTree(self.stream)) self.prepended_children[-1].markers = self.markers self.markers = [] self.stream = StringIO() self.write = self.stream.write def insert(self, iotree): """ Insert a StringIOTree (and all of its contents) at this location. Further writing to self appears after what is inserted. """ self.commit() self.prepended_children.append(iotree) def insertion_point(self): """ Returns a new StringIOTree, which is left behind at the current position (it what is written to the result will appear right before whatever is next written to self). Calling getvalue() or copyto() on the result will only return the contents written to it. """ # Save what we have written until now # This is so that getvalue on the result doesn't include it. self.commit() # Construct the new forked object to return other = StringIOTree() self.prepended_children.append(other) return other def allmarkers(self): children = self.prepended_children return [m for c in children for m in c.allmarkers()] + self.markers __doc__ = r""" Implements a buffer with insertion points. When you know you need to "get back" to a place and write more later, simply call insertion_point() at that spot and get a new StringIOTree object that is "left behind". EXAMPLE: >>> a = StringIOTree() >>> a.write('first\n') >>> b = a.insertion_point() >>> a.write('third\n') >>> b.write('second\n') >>> a.getvalue().split() ['first', 'second', 'third'] >>> c = b.insertion_point() >>> d = c.insertion_point() >>> d.write('alpha\n') >>> b.write('gamma\n') >>> c.write('beta\n') >>> b.getvalue().split() ['second', 'alpha', 'beta', 'gamma'] >>> i = StringIOTree() >>> d.insert(i) >>> i.write('inserted\n') >>> out = StringIO() >>> a.copyto(out) >>> out.getvalue().split() ['first', 'second', 'alpha', 'inserted', 'beta', 'gamma', 'third'] """ cython-0.20.1+git90-g0e6e38e/Cython/Tempita/000077500000000000000000000000001231323242300201145ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Cython/Tempita/__init__.py000066400000000000000000000002271231323242300222260ustar00rootroot00000000000000# The original Tempita implements all of its templating code here. # Moved it to _tempita.py to make the compilation portable. from _tempita import * cython-0.20.1+git90-g0e6e38e/Cython/Tempita/_looper.py000066400000000000000000000101101231323242300221160ustar00rootroot00000000000000""" Helper for looping over sequences, particular in templates. Often in a loop in a template it's handy to know what's next up, previously up, if this is the first or last item in the sequence, etc. These can be awkward to manage in a normal Python loop, but using the looper you can get a better sense of the context. Use like:: >>> for loop, item in looper(['a', 'b', 'c']): ... print loop.number, item ... if not loop.last: ... print '---' 1 a --- 2 b --- 3 c """ import sys from Cython.Tempita.compat3 import basestring_ __all__ = ['looper'] class looper(object): """ Helper for looping (particularly in templates) Use this like:: for loop, item in looper(seq): if loop.first: ... """ def __init__(self, seq): self.seq = seq def __iter__(self): return looper_iter(self.seq) def __repr__(self): return '<%s for %r>' % ( self.__class__.__name__, self.seq) class looper_iter(object): def __init__(self, seq): self.seq = list(seq) self.pos = 0 def __iter__(self): return self def __next__(self): if self.pos >= len(self.seq): raise StopIteration result = loop_pos(self.seq, self.pos), self.seq[self.pos] self.pos += 1 return result if sys.version < "3": next = __next__ class loop_pos(object): def __init__(self, seq, pos): self.seq = seq self.pos = pos def __repr__(self): return '' % ( self.seq[self.pos], self.pos) def index(self): return self.pos index = property(index) def number(self): return self.pos + 1 number = property(number) def item(self): return self.seq[self.pos] item = property(item) def __next__(self): try: return self.seq[self.pos + 1] except IndexError: return None __next__ = property(__next__) if sys.version < "3": next = __next__ def previous(self): if self.pos == 0: return None return self.seq[self.pos - 1] previous = property(previous) def odd(self): return not self.pos % 2 odd = property(odd) def even(self): return self.pos % 2 even = property(even) def first(self): return self.pos == 0 first = property(first) def last(self): return self.pos == len(self.seq) - 1 last = property(last) def length(self): return len(self.seq) length = property(length) def first_group(self, getter=None): """ Returns true if this item is the start of a new group, where groups mean that some attribute has changed. The getter can be None (the item itself changes), an attribute name like ``'.attr'``, a function, or a dict key or list index. """ if self.first: return True return self._compare_group(self.item, self.previous, getter) def last_group(self, getter=None): """ Returns true if this item is the end of a new group, where groups mean that some attribute has changed. The getter can be None (the item itself changes), an attribute name like ``'.attr'``, a function, or a dict key or list index. """ if self.last: return True return self._compare_group(self.item, self.__next__, getter) def _compare_group(self, item, other, getter): if getter is None: return item != other elif (isinstance(getter, basestring_) and getter.startswith('.')): getter = getter[1:] if getter.endswith('()'): getter = getter[:-2] return getattr(item, getter)() != getattr(other, getter)() else: return getattr(item, getter) != getattr(other, getter) elif hasattr(getter, '__call__'): return getter(item) != getter(other) else: return item[getter] != other[getter] cython-0.20.1+git90-g0e6e38e/Cython/Tempita/_tempita.py000066400000000000000000001160631231323242300222770ustar00rootroot00000000000000""" A small templating language This implements a small templating language. This language implements if/elif/else, for/continue/break, expressions, and blocks of Python code. The syntax is:: {{any expression (function calls etc)}} {{any expression | filter}} {{for x in y}}...{{endfor}} {{if x}}x{{elif y}}y{{else}}z{{endif}} {{py:x=1}} {{py: def foo(bar): return 'baz' }} {{default var = default_value}} {{# comment}} You use this with the ``Template`` class or the ``sub`` shortcut. The ``Template`` class takes the template string and the name of the template (for errors) and a default namespace. Then (like ``string.Template``) you can call the ``tmpl.substitute(**kw)`` method to make a substitution (or ``tmpl.substitute(a_dict)``). ``sub(content, **kw)`` substitutes the template immediately. You can use ``__name='tmpl.html'`` to set the name of the template. If there are syntax errors ``TemplateError`` will be raised. """ import re import sys import cgi try: from urllib import quote as url_quote except ImportError: # Py3 from urllib.parse import quote as url_quote import os import tokenize try: from io import StringIO except ImportError: from cStringIO import StringIO from Cython.Tempita._looper import looper from Cython.Tempita.compat3 import bytes, basestring_, next, is_unicode, coerce_text __all__ = ['TemplateError', 'Template', 'sub', 'HTMLTemplate', 'sub_html', 'html', 'bunch'] in_re = re.compile(r'\s+in\s+') var_re = re.compile(r'^[a-z_][a-z0-9_]*$', re.I) class TemplateError(Exception): """Exception raised while parsing a template """ def __init__(self, message, position, name=None): Exception.__init__(self, message) self.position = position self.name = name def __str__(self): msg = ' '.join(self.args) if self.position: msg = '%s at line %s column %s' % ( msg, self.position[0], self.position[1]) if self.name: msg += ' in %s' % self.name return msg class _TemplateContinue(Exception): pass class _TemplateBreak(Exception): pass def get_file_template(name, from_template): path = os.path.join(os.path.dirname(from_template.name), name) return from_template.__class__.from_filename( path, namespace=from_template.namespace, get_template=from_template.get_template) class Template(object): default_namespace = { 'start_braces': '{{', 'end_braces': '}}', 'looper': looper, } default_encoding = 'utf8' default_inherit = None def __init__(self, content, name=None, namespace=None, stacklevel=None, get_template=None, default_inherit=None, line_offset=0, delimeters=None): self.content = content # set delimeters if delimeters is None: delimeters = (self.default_namespace['start_braces'], self.default_namespace['end_braces']) else: #assert len(delimeters) == 2 and all([isinstance(delimeter, basestring) # for delimeter in delimeters]) self.default_namespace = self.__class__.default_namespace.copy() self.default_namespace['start_braces'] = delimeters[0] self.default_namespace['end_braces'] = delimeters[1] self.delimeters = delimeters self._unicode = is_unicode(content) if name is None and stacklevel is not None: try: caller = sys._getframe(stacklevel) except ValueError: pass else: globals = caller.f_globals lineno = caller.f_lineno if '__file__' in globals: name = globals['__file__'] if name.endswith('.pyc') or name.endswith('.pyo'): name = name[:-1] elif '__name__' in globals: name = globals['__name__'] else: name = '' if lineno: name += ':%s' % lineno self.name = name self._parsed = parse(content, name=name, line_offset=line_offset, delimeters=self.delimeters) if namespace is None: namespace = {} self.namespace = namespace self.get_template = get_template if default_inherit is not None: self.default_inherit = default_inherit def from_filename(cls, filename, namespace=None, encoding=None, default_inherit=None, get_template=get_file_template): f = open(filename, 'rb') c = f.read() f.close() if encoding: c = c.decode(encoding) return cls(content=c, name=filename, namespace=namespace, default_inherit=default_inherit, get_template=get_template) from_filename = classmethod(from_filename) def __repr__(self): return '<%s %s name=%r>' % ( self.__class__.__name__, hex(id(self))[2:], self.name) def substitute(self, *args, **kw): if args: if kw: raise TypeError( "You can only give positional *or* keyword arguments") if len(args) > 1: raise TypeError( "You can only give one positional argument") if not hasattr(args[0], 'items'): raise TypeError( "If you pass in a single argument, you must pass in a dictionary-like object (with a .items() method); you gave %r" % (args[0],)) kw = args[0] ns = kw ns['__template_name__'] = self.name if self.namespace: ns.update(self.namespace) result, defs, inherit = self._interpret(ns) if not inherit: inherit = self.default_inherit if inherit: result = self._interpret_inherit(result, defs, inherit, ns) return result def _interpret(self, ns): __traceback_hide__ = True parts = [] defs = {} self._interpret_codes(self._parsed, ns, out=parts, defs=defs) if '__inherit__' in defs: inherit = defs.pop('__inherit__') else: inherit = None return ''.join(parts), defs, inherit def _interpret_inherit(self, body, defs, inherit_template, ns): __traceback_hide__ = True if not self.get_template: raise TemplateError( 'You cannot use inheritance without passing in get_template', position=None, name=self.name) templ = self.get_template(inherit_template, self) self_ = TemplateObject(self.name) for name, value in defs.iteritems(): setattr(self_, name, value) self_.body = body ns = ns.copy() ns['self'] = self_ return templ.substitute(ns) def _interpret_codes(self, codes, ns, out, defs): __traceback_hide__ = True for item in codes: if isinstance(item, basestring_): out.append(item) else: self._interpret_code(item, ns, out, defs) def _interpret_code(self, code, ns, out, defs): __traceback_hide__ = True name, pos = code[0], code[1] if name == 'py': self._exec(code[2], ns, pos) elif name == 'continue': raise _TemplateContinue() elif name == 'break': raise _TemplateBreak() elif name == 'for': vars, expr, content = code[2], code[3], code[4] expr = self._eval(expr, ns, pos) self._interpret_for(vars, expr, content, ns, out, defs) elif name == 'cond': parts = code[2:] self._interpret_if(parts, ns, out, defs) elif name == 'expr': parts = code[2].split('|') base = self._eval(parts[0], ns, pos) for part in parts[1:]: func = self._eval(part, ns, pos) base = func(base) out.append(self._repr(base, pos)) elif name == 'default': var, expr = code[2], code[3] if var not in ns: result = self._eval(expr, ns, pos) ns[var] = result elif name == 'inherit': expr = code[2] value = self._eval(expr, ns, pos) defs['__inherit__'] = value elif name == 'def': name = code[2] signature = code[3] parts = code[4] ns[name] = defs[name] = TemplateDef(self, name, signature, body=parts, ns=ns, pos=pos) elif name == 'comment': return else: assert 0, "Unknown code: %r" % name def _interpret_for(self, vars, expr, content, ns, out, defs): __traceback_hide__ = True for item in expr: if len(vars) == 1: ns[vars[0]] = item else: if len(vars) != len(item): raise ValueError( 'Need %i items to unpack (got %i items)' % (len(vars), len(item))) for name, value in zip(vars, item): ns[name] = value try: self._interpret_codes(content, ns, out, defs) except _TemplateContinue: continue except _TemplateBreak: break def _interpret_if(self, parts, ns, out, defs): __traceback_hide__ = True # @@: if/else/else gets through for part in parts: assert not isinstance(part, basestring_) name, pos = part[0], part[1] if name == 'else': result = True else: result = self._eval(part[2], ns, pos) if result: self._interpret_codes(part[3], ns, out, defs) break def _eval(self, code, ns, pos): __traceback_hide__ = True try: try: value = eval(code, self.default_namespace, ns) except SyntaxError, e: raise SyntaxError( 'invalid syntax in expression: %s' % code) return value except: exc_info = sys.exc_info() e = exc_info[1] if getattr(e, 'args', None): arg0 = e.args[0] else: arg0 = coerce_text(e) e.args = (self._add_line_info(arg0, pos),) raise exc_info[0], e, exc_info[2] def _exec(self, code, ns, pos): __traceback_hide__ = True try: exec code in self.default_namespace, ns except: exc_info = sys.exc_info() e = exc_info[1] if e.args: e.args = (self._add_line_info(e.args[0], pos),) else: e.args = (self._add_line_info(None, pos),) raise exc_info[0], e, exc_info[2] def _repr(self, value, pos): __traceback_hide__ = True try: if value is None: return '' if self._unicode: try: value = unicode(value) except UnicodeDecodeError: value = bytes(value) else: if not isinstance(value, basestring_): value = coerce_text(value) if (is_unicode(value) and self.default_encoding): value = value.encode(self.default_encoding) except: exc_info = sys.exc_info() e = exc_info[1] e.args = (self._add_line_info(e.args[0], pos),) raise exc_info[0], e, exc_info[2] else: if self._unicode and isinstance(value, bytes): if not self.default_encoding: raise UnicodeDecodeError( 'Cannot decode bytes value %r into unicode ' '(no default_encoding provided)' % value) try: value = value.decode(self.default_encoding) except UnicodeDecodeError, e: raise UnicodeDecodeError( e.encoding, e.object, e.start, e.end, e.reason + ' in string %r' % value) elif not self._unicode and is_unicode(value): if not self.default_encoding: raise UnicodeEncodeError( 'Cannot encode unicode value %r into bytes ' '(no default_encoding provided)' % value) value = value.encode(self.default_encoding) return value def _add_line_info(self, msg, pos): msg = "%s at line %s column %s" % ( msg, pos[0], pos[1]) if self.name: msg += " in file %s" % self.name return msg def sub(content, delimeters=None, **kw): name = kw.get('__name') tmpl = Template(content, name=name, delimeters=delimeters) return tmpl.substitute(kw) def paste_script_template_renderer(content, vars, filename=None): tmpl = Template(content, name=filename) return tmpl.substitute(vars) class bunch(dict): def __init__(self, **kw): for name, value in kw.iteritems(): setattr(self, name, value) def __setattr__(self, name, value): self[name] = value def __getattr__(self, name): try: return self[name] except KeyError: raise AttributeError(name) def __getitem__(self, key): if 'default' in self: try: return dict.__getitem__(self, key) except KeyError: return dict.__getitem__(self, 'default') else: return dict.__getitem__(self, key) def __repr__(self): items = [ (k, v) for k, v in self.iteritems()] items.sort() return '<%s %s>' % ( self.__class__.__name__, ' '.join(['%s=%r' % (k, v) for k, v in items])) ############################################################ ## HTML Templating ############################################################ class html(object): def __init__(self, value): self.value = value def __str__(self): return self.value def __html__(self): return self.value def __repr__(self): return '<%s %r>' % ( self.__class__.__name__, self.value) def html_quote(value, force=True): if not force and hasattr(value, '__html__'): return value.__html__() if value is None: return '' if not isinstance(value, basestring_): value = coerce_text(value) if sys.version >= "3" and isinstance(value, bytes): value = cgi.escape(value.decode('latin1'), 1) value = value.encode('latin1') else: value = cgi.escape(value, 1) if sys.version < "3": if is_unicode(value): value = value.encode('ascii', 'xmlcharrefreplace') return value def url(v): v = coerce_text(v) if is_unicode(v): v = v.encode('utf8') return url_quote(v) def attr(**kw): kw = list(kw.iteritems()) kw.sort() parts = [] for name, value in kw: if value is None: continue if name.endswith('_'): name = name[:-1] parts.append('%s="%s"' % (html_quote(name), html_quote(value))) return html(' '.join(parts)) class HTMLTemplate(Template): default_namespace = Template.default_namespace.copy() default_namespace.update(dict( html=html, attr=attr, url=url, html_quote=html_quote, )) def _repr(self, value, pos): if hasattr(value, '__html__'): value = value.__html__() quote = False else: quote = True plain = Template._repr(self, value, pos) if quote: return html_quote(plain) else: return plain def sub_html(content, **kw): name = kw.get('__name') tmpl = HTMLTemplate(content, name=name) return tmpl.substitute(kw) class TemplateDef(object): def __init__(self, template, func_name, func_signature, body, ns, pos, bound_self=None): self._template = template self._func_name = func_name self._func_signature = func_signature self._body = body self._ns = ns self._pos = pos self._bound_self = bound_self def __repr__(self): return '' % ( self._func_name, self._func_signature, self._template.name, self._pos) def __str__(self): return self() def __call__(self, *args, **kw): values = self._parse_signature(args, kw) ns = self._ns.copy() ns.update(values) if self._bound_self is not None: ns['self'] = self._bound_self out = [] subdefs = {} self._template._interpret_codes(self._body, ns, out, subdefs) return ''.join(out) def __get__(self, obj, type=None): if obj is None: return self return self.__class__( self._template, self._func_name, self._func_signature, self._body, self._ns, self._pos, bound_self=obj) def _parse_signature(self, args, kw): values = {} sig_args, var_args, var_kw, defaults = self._func_signature extra_kw = {} for name, value in kw.iteritems(): if not var_kw and name not in sig_args: raise TypeError( 'Unexpected argument %s' % name) if name in sig_args: values[sig_args] = value else: extra_kw[name] = value args = list(args) sig_args = list(sig_args) while args: while sig_args and sig_args[0] in values: sig_args.pop(0) if sig_args: name = sig_args.pop(0) values[name] = args.pop(0) elif var_args: values[var_args] = tuple(args) break else: raise TypeError( 'Extra position arguments: %s' % ', '.join([repr(v) for v in args])) for name, value_expr in defaults.iteritems(): if name not in values: values[name] = self._template._eval( value_expr, self._ns, self._pos) for name in sig_args: if name not in values: raise TypeError( 'Missing argument: %s' % name) if var_kw: values[var_kw] = extra_kw return values class TemplateObject(object): def __init__(self, name): self.__name = name self.get = TemplateObjectGetter(self) def __repr__(self): return '<%s %s>' % (self.__class__.__name__, self.__name) class TemplateObjectGetter(object): def __init__(self, template_obj): self.__template_obj = template_obj def __getattr__(self, attr): return getattr(self.__template_obj, attr, Empty) def __repr__(self): return '<%s around %r>' % (self.__class__.__name__, self.__template_obj) class _Empty(object): def __call__(self, *args, **kw): return self def __str__(self): return '' def __repr__(self): return 'Empty' def __unicode__(self): return u'' def __iter__(self): return iter(()) def __bool__(self): return False if sys.version < "3": __nonzero__ = __bool__ Empty = _Empty() del _Empty ############################################################ ## Lexing and Parsing ############################################################ def lex(s, name=None, trim_whitespace=True, line_offset=0, delimeters=None): """ Lex a string into chunks: >>> lex('hey') ['hey'] >>> lex('hey {{you}}') ['hey ', ('you', (1, 7))] >>> lex('hey {{') Traceback (most recent call last): ... TemplateError: No }} to finish last expression at line 1 column 7 >>> lex('hey }}') Traceback (most recent call last): ... TemplateError: }} outside expression at line 1 column 7 >>> lex('hey {{ {{') Traceback (most recent call last): ... TemplateError: {{ inside expression at line 1 column 10 """ if delimeters is None: delimeters = ( Template.default_namespace['start_braces'], Template.default_namespace['end_braces'] ) in_expr = False chunks = [] last = 0 last_pos = (line_offset + 1, 1) token_re = re.compile(r'%s|%s' % (re.escape(delimeters[0]), re.escape(delimeters[1]))) for match in token_re.finditer(s): expr = match.group(0) pos = find_position(s, match.end(), last, last_pos) if expr == delimeters[0] and in_expr: raise TemplateError('%s inside expression' % delimeters[0], position=pos, name=name) elif expr == delimeters[1] and not in_expr: raise TemplateError('%s outside expression' % delimeters[1], position=pos, name=name) if expr == delimeters[0]: part = s[last:match.start()] if part: chunks.append(part) in_expr = True else: chunks.append((s[last:match.start()], last_pos)) in_expr = False last = match.end() last_pos = pos if in_expr: raise TemplateError('No %s to finish last expression' % delimeters[1], name=name, position=last_pos) part = s[last:] if part: chunks.append(part) if trim_whitespace: chunks = trim_lex(chunks) return chunks statement_re = re.compile(r'^(?:if |elif |for |def |inherit |default |py:)') single_statements = ['else', 'endif', 'endfor', 'enddef', 'continue', 'break'] trail_whitespace_re = re.compile(r'\n\r?[\t ]*$') lead_whitespace_re = re.compile(r'^[\t ]*\n') def trim_lex(tokens): r""" Takes a lexed set of tokens, and removes whitespace when there is a directive on a line by itself: >>> tokens = lex('{{if x}}\nx\n{{endif}}\ny', trim_whitespace=False) >>> tokens [('if x', (1, 3)), '\nx\n', ('endif', (3, 3)), '\ny'] >>> trim_lex(tokens) [('if x', (1, 3)), 'x\n', ('endif', (3, 3)), 'y'] """ last_trim = None for i, current in enumerate(tokens): if isinstance(current, basestring_): # we don't trim this continue item = current[0] if not statement_re.search(item) and item not in single_statements: continue if not i: prev = '' else: prev = tokens[i - 1] if i + 1 >= len(tokens): next_chunk = '' else: next_chunk = tokens[i + 1] if (not isinstance(next_chunk, basestring_) or not isinstance(prev, basestring_)): continue prev_ok = not prev or trail_whitespace_re.search(prev) if i == 1 and not prev.strip(): prev_ok = True if last_trim is not None and last_trim + 2 == i and not prev.strip(): prev_ok = 'last' if (prev_ok and (not next_chunk or lead_whitespace_re.search(next_chunk) or (i == len(tokens) - 2 and not next_chunk.strip()))): if prev: if ((i == 1 and not prev.strip()) or prev_ok == 'last'): tokens[i - 1] = '' else: m = trail_whitespace_re.search(prev) # +1 to leave the leading \n on: prev = prev[:m.start() + 1] tokens[i - 1] = prev if next_chunk: last_trim = i if i == len(tokens) - 2 and not next_chunk.strip(): tokens[i + 1] = '' else: m = lead_whitespace_re.search(next_chunk) next_chunk = next_chunk[m.end():] tokens[i + 1] = next_chunk return tokens def find_position(string, index, last_index, last_pos): """Given a string and index, return (line, column)""" lines = string.count('\n', last_index, index) if lines > 0: column = index - string.rfind('\n', last_index, index) else: column = last_pos[1] + (index - last_index) return (last_pos[0] + lines, column) def parse(s, name=None, line_offset=0, delimeters=None): r""" Parses a string into a kind of AST >>> parse('{{x}}') [('expr', (1, 3), 'x')] >>> parse('foo') ['foo'] >>> parse('{{if x}}test{{endif}}') [('cond', (1, 3), ('if', (1, 3), 'x', ['test']))] >>> parse('series->{{for x in y}}x={{x}}{{endfor}}') ['series->', ('for', (1, 11), ('x',), 'y', ['x=', ('expr', (1, 27), 'x')])] >>> parse('{{for x, y in z:}}{{continue}}{{endfor}}') [('for', (1, 3), ('x', 'y'), 'z', [('continue', (1, 21))])] >>> parse('{{py:x=1}}') [('py', (1, 3), 'x=1')] >>> parse('{{if x}}a{{elif y}}b{{else}}c{{endif}}') [('cond', (1, 3), ('if', (1, 3), 'x', ['a']), ('elif', (1, 12), 'y', ['b']), ('else', (1, 23), None, ['c']))] Some exceptions:: >>> parse('{{continue}}') Traceback (most recent call last): ... TemplateError: continue outside of for loop at line 1 column 3 >>> parse('{{if x}}foo') Traceback (most recent call last): ... TemplateError: No {{endif}} at line 1 column 3 >>> parse('{{else}}') Traceback (most recent call last): ... TemplateError: else outside of an if block at line 1 column 3 >>> parse('{{if x}}{{for x in y}}{{endif}}{{endfor}}') Traceback (most recent call last): ... TemplateError: Unexpected endif at line 1 column 25 >>> parse('{{if}}{{endif}}') Traceback (most recent call last): ... TemplateError: if with no expression at line 1 column 3 >>> parse('{{for x y}}{{endfor}}') Traceback (most recent call last): ... TemplateError: Bad for (no "in") in 'x y' at line 1 column 3 >>> parse('{{py:x=1\ny=2}}') Traceback (most recent call last): ... TemplateError: Multi-line py blocks must start with a newline at line 1 column 3 """ if delimeters is None: delimeters = ( Template.default_namespace['start_braces'], Template.default_namespace['end_braces'] ) tokens = lex(s, name=name, line_offset=line_offset, delimeters=delimeters) result = [] while tokens: next_chunk, tokens = parse_expr(tokens, name) result.append(next_chunk) return result def parse_expr(tokens, name, context=()): if isinstance(tokens[0], basestring_): return tokens[0], tokens[1:] expr, pos = tokens[0] expr = expr.strip() if expr.startswith('py:'): expr = expr[3:].lstrip(' \t') if expr.startswith('\n') or expr.startswith('\r'): expr = expr.lstrip('\r\n') if '\r' in expr: expr = expr.replace('\r\n', '\n') expr = expr.replace('\r', '') expr += '\n' else: if '\n' in expr: raise TemplateError( 'Multi-line py blocks must start with a newline', position=pos, name=name) return ('py', pos, expr), tokens[1:] elif expr in ('continue', 'break'): if 'for' not in context: raise TemplateError( 'continue outside of for loop', position=pos, name=name) return (expr, pos), tokens[1:] elif expr.startswith('if '): return parse_cond(tokens, name, context) elif (expr.startswith('elif ') or expr == 'else'): raise TemplateError( '%s outside of an if block' % expr.split()[0], position=pos, name=name) elif expr in ('if', 'elif', 'for'): raise TemplateError( '%s with no expression' % expr, position=pos, name=name) elif expr in ('endif', 'endfor', 'enddef'): raise TemplateError( 'Unexpected %s' % expr, position=pos, name=name) elif expr.startswith('for '): return parse_for(tokens, name, context) elif expr.startswith('default '): return parse_default(tokens, name, context) elif expr.startswith('inherit '): return parse_inherit(tokens, name, context) elif expr.startswith('def '): return parse_def(tokens, name, context) elif expr.startswith('#'): return ('comment', pos, tokens[0][0]), tokens[1:] return ('expr', pos, tokens[0][0]), tokens[1:] def parse_cond(tokens, name, context): start = tokens[0][1] pieces = [] context = context + ('if',) while 1: if not tokens: raise TemplateError( 'Missing {{endif}}', position=start, name=name) if (isinstance(tokens[0], tuple) and tokens[0][0] == 'endif'): return ('cond', start) + tuple(pieces), tokens[1:] next_chunk, tokens = parse_one_cond(tokens, name, context) pieces.append(next_chunk) def parse_one_cond(tokens, name, context): (first, pos), tokens = tokens[0], tokens[1:] content = [] if first.endswith(':'): first = first[:-1] if first.startswith('if '): part = ('if', pos, first[3:].lstrip(), content) elif first.startswith('elif '): part = ('elif', pos, first[5:].lstrip(), content) elif first == 'else': part = ('else', pos, None, content) else: assert 0, "Unexpected token %r at %s" % (first, pos) while 1: if not tokens: raise TemplateError( 'No {{endif}}', position=pos, name=name) if (isinstance(tokens[0], tuple) and (tokens[0][0] == 'endif' or tokens[0][0].startswith('elif ') or tokens[0][0] == 'else')): return part, tokens next_chunk, tokens = parse_expr(tokens, name, context) content.append(next_chunk) def parse_for(tokens, name, context): first, pos = tokens[0] tokens = tokens[1:] context = ('for',) + context content = [] assert first.startswith('for ') if first.endswith(':'): first = first[:-1] first = first[3:].strip() match = in_re.search(first) if not match: raise TemplateError( 'Bad for (no "in") in %r' % first, position=pos, name=name) vars = first[:match.start()] if '(' in vars: raise TemplateError( 'You cannot have () in the variable section of a for loop (%r)' % vars, position=pos, name=name) vars = tuple([ v.strip() for v in first[:match.start()].split(',') if v.strip()]) expr = first[match.end():] while 1: if not tokens: raise TemplateError( 'No {{endfor}}', position=pos, name=name) if (isinstance(tokens[0], tuple) and tokens[0][0] == 'endfor'): return ('for', pos, vars, expr, content), tokens[1:] next_chunk, tokens = parse_expr(tokens, name, context) content.append(next_chunk) def parse_default(tokens, name, context): first, pos = tokens[0] assert first.startswith('default ') first = first.split(None, 1)[1] parts = first.split('=', 1) if len(parts) == 1: raise TemplateError( "Expression must be {{default var=value}}; no = found in %r" % first, position=pos, name=name) var = parts[0].strip() if ',' in var: raise TemplateError( "{{default x, y = ...}} is not supported", position=pos, name=name) if not var_re.search(var): raise TemplateError( "Not a valid variable name for {{default}}: %r" % var, position=pos, name=name) expr = parts[1].strip() return ('default', pos, var, expr), tokens[1:] def parse_inherit(tokens, name, context): first, pos = tokens[0] assert first.startswith('inherit ') expr = first.split(None, 1)[1] return ('inherit', pos, expr), tokens[1:] def parse_def(tokens, name, context): first, start = tokens[0] tokens = tokens[1:] assert first.startswith('def ') first = first.split(None, 1)[1] if first.endswith(':'): first = first[:-1] if '(' not in first: func_name = first sig = ((), None, None, {}) elif not first.endswith(')'): raise TemplateError("Function definition doesn't end with ): %s" % first, position=start, name=name) else: first = first[:-1] func_name, sig_text = first.split('(', 1) sig = parse_signature(sig_text, name, start) context = context + ('def',) content = [] while 1: if not tokens: raise TemplateError( 'Missing {{enddef}}', position=start, name=name) if (isinstance(tokens[0], tuple) and tokens[0][0] == 'enddef'): return ('def', start, func_name, sig, content), tokens[1:] next_chunk, tokens = parse_expr(tokens, name, context) content.append(next_chunk) def parse_signature(sig_text, name, pos): tokens = tokenize.generate_tokens(StringIO(sig_text).readline) sig_args = [] var_arg = None var_kw = None defaults = {} def get_token(pos=False): try: tok_type, tok_string, (srow, scol), (erow, ecol), line = next(tokens) except StopIteration: return tokenize.ENDMARKER, '' if pos: return tok_type, tok_string, (srow, scol), (erow, ecol) else: return tok_type, tok_string while 1: var_arg_type = None tok_type, tok_string = get_token() if tok_type == tokenize.ENDMARKER: break if tok_type == tokenize.OP and (tok_string == '*' or tok_string == '**'): var_arg_type = tok_string tok_type, tok_string = get_token() if tok_type != tokenize.NAME: raise TemplateError('Invalid signature: (%s)' % sig_text, position=pos, name=name) var_name = tok_string tok_type, tok_string = get_token() if tok_type == tokenize.ENDMARKER or (tok_type == tokenize.OP and tok_string == ','): if var_arg_type == '*': var_arg = var_name elif var_arg_type == '**': var_kw = var_name else: sig_args.append(var_name) if tok_type == tokenize.ENDMARKER: break continue if var_arg_type is not None: raise TemplateError('Invalid signature: (%s)' % sig_text, position=pos, name=name) if tok_type == tokenize.OP and tok_string == '=': nest_type = None unnest_type = None nest_count = 0 start_pos = end_pos = None parts = [] while 1: tok_type, tok_string, s, e = get_token(True) if start_pos is None: start_pos = s end_pos = e if tok_type == tokenize.ENDMARKER and nest_count: raise TemplateError('Invalid signature: (%s)' % sig_text, position=pos, name=name) if (not nest_count and (tok_type == tokenize.ENDMARKER or (tok_type == tokenize.OP and tok_string == ','))): default_expr = isolate_expression(sig_text, start_pos, end_pos) defaults[var_name] = default_expr sig_args.append(var_name) break parts.append((tok_type, tok_string)) if nest_count and tok_type == tokenize.OP and tok_string == nest_type: nest_count += 1 elif nest_count and tok_type == tokenize.OP and tok_string == unnest_type: nest_count -= 1 if not nest_count: nest_type = unnest_type = None elif not nest_count and tok_type == tokenize.OP and tok_string in ('(', '[', '{'): nest_type = tok_string nest_count = 1 unnest_type = {'(': ')', '[': ']', '{': '}'}[nest_type] return sig_args, var_arg, var_kw, defaults def isolate_expression(string, start_pos, end_pos): srow, scol = start_pos srow -= 1 erow, ecol = end_pos erow -= 1 lines = string.splitlines(True) if srow == erow: return lines[srow][scol:ecol] parts = [lines[srow][scol:]] parts.extend(lines[srow+1:erow]) if erow < len(lines): # It'll sometimes give (end_row_past_finish, 0) parts.append(lines[erow][:ecol]) return ''.join(parts) _fill_command_usage = """\ %prog [OPTIONS] TEMPLATE arg=value Use py:arg=value to set a Python value; otherwise all values are strings. """ def fill_command(args=None): import sys import optparse import pkg_resources import os if args is None: args = sys.argv[1:] dist = pkg_resources.get_distribution('Paste') parser = optparse.OptionParser( version=coerce_text(dist), usage=_fill_command_usage) parser.add_option( '-o', '--output', dest='output', metavar="FILENAME", help="File to write output to (default stdout)") parser.add_option( '--html', dest='use_html', action='store_true', help="Use HTML style filling (including automatic HTML quoting)") parser.add_option( '--env', dest='use_env', action='store_true', help="Put the environment in as top-level variables") options, args = parser.parse_args(args) if len(args) < 1: print('You must give a template filename') sys.exit(2) template_name = args[0] args = args[1:] vars = {} if options.use_env: vars.update(os.environ) for value in args: if '=' not in value: print('Bad argument: %r' % value) sys.exit(2) name, value = value.split('=', 1) if name.startswith('py:'): name = name[:3] value = eval(value) vars[name] = value if template_name == '-': template_content = sys.stdin.read() template_name = '' else: f = open(template_name, 'rb') template_content = f.read() f.close() if options.use_html: TemplateClass = HTMLTemplate else: TemplateClass = Template template = TemplateClass(template_content, name=template_name) result = template.substitute(vars) if options.output: f = open(options.output, 'wb') f.write(result) f.close() else: sys.stdout.write(result) if __name__ == '__main__': fill_command() cython-0.20.1+git90-g0e6e38e/Cython/Tempita/compat3.py000066400000000000000000000015211231323242300220330ustar00rootroot00000000000000import sys __all__ = ['b', 'basestring_', 'bytes', 'next', 'is_unicode'] if sys.version < "3": b = bytes = str basestring_ = basestring else: def b(s): if isinstance(s, str): return s.encode('latin1') return bytes(s) basestring_ = (bytes, str) bytes = bytes text = str if sys.version < "3": def next(obj): return obj.next() else: next = next if sys.version < "3": def is_unicode(obj): return isinstance(obj, unicode) else: def is_unicode(obj): return isinstance(obj, str) def coerce_text(v): if not isinstance(v, basestring_): if sys.version < "3": attr = '__unicode__' else: attr = '__str__' if hasattr(v, attr): return unicode(v) else: return bytes(v) return v cython-0.20.1+git90-g0e6e38e/Cython/TestUtils.py000066400000000000000000000170201231323242300210230ustar00rootroot00000000000000import Cython.Compiler.Errors as Errors from Cython.CodeWriter import CodeWriter from Cython.Compiler.TreeFragment import TreeFragment, strip_common_indent from Cython.Compiler.Visitor import TreeVisitor, VisitorTransform from Cython.Compiler import TreePath import unittest import os, sys import tempfile class NodeTypeWriter(TreeVisitor): def __init__(self): super(NodeTypeWriter, self).__init__() self._indents = 0 self.result = [] def visit_Node(self, node): if not self.access_path: name = u"(root)" else: tip = self.access_path[-1] if tip[2] is not None: name = u"%s[%d]" % tip[1:3] else: name = tip[1] self.result.append(u" " * self._indents + u"%s: %s" % (name, node.__class__.__name__)) self._indents += 1 self.visitchildren(node) self._indents -= 1 def treetypes(root): """Returns a string representing the tree by class names. There's a leading and trailing whitespace so that it can be compared by simple string comparison while still making test cases look ok.""" w = NodeTypeWriter() w.visit(root) return u"\n".join([u""] + w.result + [u""]) class CythonTest(unittest.TestCase): def setUp(self): self.listing_file = Errors.listing_file self.echo_file = Errors.echo_file Errors.listing_file = Errors.echo_file = None def tearDown(self): Errors.listing_file = self.listing_file Errors.echo_file = self.echo_file def assertLines(self, expected, result): "Checks that the given strings or lists of strings are equal line by line" if not isinstance(expected, list): expected = expected.split(u"\n") if not isinstance(result, list): result = result.split(u"\n") for idx, (expected_line, result_line) in enumerate(zip(expected, result)): self.assertEqual(expected_line, result_line, "Line %d:\nExp: %s\nGot: %s" % (idx, expected_line, result_line)) self.assertEqual(len(expected), len(result), "Unmatched lines. Got:\n%s\nExpected:\n%s" % ("\n".join(expected), u"\n".join(result))) def codeToLines(self, tree): writer = CodeWriter() writer.write(tree) return writer.result.lines def codeToString(self, tree): return "\n".join(self.codeToLines(tree)) def assertCode(self, expected, result_tree): result_lines = self.codeToLines(result_tree) expected_lines = strip_common_indent(expected.split("\n")) for idx, (line, expected_line) in enumerate(zip(result_lines, expected_lines)): self.assertEqual(expected_line, line, "Line %d:\nGot: %s\nExp: %s" % (idx, line, expected_line)) self.assertEqual(len(result_lines), len(expected_lines), "Unmatched lines. Got:\n%s\nExpected:\n%s" % ("\n".join(result_lines), expected)) def assertNodeExists(self, path, result_tree): self.assertNotEqual(TreePath.find_first(result_tree, path), None, "Path '%s' not found in result tree" % path) def fragment(self, code, pxds={}, pipeline=[]): "Simply create a tree fragment using the name of the test-case in parse errors." name = self.id() if name.startswith("__main__."): name = name[len("__main__."):] name = name.replace(".", "_") return TreeFragment(code, name, pxds, pipeline=pipeline) def treetypes(self, root): return treetypes(root) def should_fail(self, func, exc_type=Exception): """Calls "func" and fails if it doesn't raise the right exception (any exception by default). Also returns the exception in question. """ try: func() self.fail("Expected an exception of type %r" % exc_type) except exc_type, e: self.assert_(isinstance(e, exc_type)) return e def should_not_fail(self, func): """Calls func and succeeds if and only if no exception is raised (i.e. converts exception raising into a failed testcase). Returns the return value of func.""" try: return func() except: self.fail(str(sys.exc_info()[1])) class TransformTest(CythonTest): """ Utility base class for transform unit tests. It is based around constructing test trees (either explicitly or by parsing a Cython code string); running the transform, serialize it using a customized Cython serializer (with special markup for nodes that cannot be represented in Cython), and do a string-comparison line-by-line of the result. To create a test case: - Call run_pipeline. The pipeline should at least contain the transform you are testing; pyx should be either a string (passed to the parser to create a post-parse tree) or a node representing input to pipeline. The result will be a transformed result. - Check that the tree is correct. If wanted, assertCode can be used, which takes a code string as expected, and a ModuleNode in result_tree (it serializes the ModuleNode to a string and compares line-by-line). All code strings are first stripped for whitespace lines and then common indentation. Plans: One could have a pxd dictionary parameter to run_pipeline. """ def run_pipeline(self, pipeline, pyx, pxds={}): tree = self.fragment(pyx, pxds).root # Run pipeline for T in pipeline: tree = T(tree) return tree class TreeAssertVisitor(VisitorTransform): # actually, a TreeVisitor would be enough, but this needs to run # as part of the compiler pipeline def visit_CompilerDirectivesNode(self, node): directives = node.directives if 'test_assert_path_exists' in directives: for path in directives['test_assert_path_exists']: if TreePath.find_first(node, path) is None: Errors.error( node.pos, "Expected path '%s' not found in result tree" % path) if 'test_fail_if_path_exists' in directives: for path in directives['test_fail_if_path_exists']: if TreePath.find_first(node, path) is not None: Errors.error( node.pos, "Unexpected path '%s' found in result tree" % path) self.visitchildren(node) return node visit_Node = VisitorTransform.recurse_to_children def unpack_source_tree(tree_file, dir=None): if dir is None: dir = tempfile.mkdtemp() header = [] cur_file = None f = open(tree_file) try: lines = f.readlines() finally: f.close() del f try: for line in lines: if line[:5] == '#####': filename = line.strip().strip('#').strip().replace('/', os.path.sep) path = os.path.join(dir, filename) if not os.path.exists(os.path.dirname(path)): os.makedirs(os.path.dirname(path)) if cur_file is not None: f, cur_file = cur_file, None f.close() cur_file = open(path, 'w') elif cur_file is not None: cur_file.write(line) elif line.strip() and not line.lstrip().startswith('#'): if line.strip() not in ('"""', "'''"): header.append(line) finally: if cur_file is not None: cur_file.close() return dir, ''.join(header) cython-0.20.1+git90-g0e6e38e/Cython/Tests/000077500000000000000000000000001231323242300176135ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Cython/Tests/TestCodeWriter.py000066400000000000000000000044141231323242300230770ustar00rootroot00000000000000from Cython.TestUtils import CythonTest class TestCodeWriter(CythonTest): # CythonTest uses the CodeWriter heavily, so do some checking by # roundtripping Cython code through the test framework. # Note that this test is dependant upon the normal Cython parser # to generate the input trees to the CodeWriter. This save *a lot* # of time; better to spend that time writing other tests than perfecting # this one... # Whitespace is very significant in this process: # - always newline on new block (!) # - indent 4 spaces # - 1 space around every operator def t(self, codestr): self.assertCode(codestr, self.fragment(codestr).root) def test_print(self): self.t(u""" print x, y print x + y ** 2 print x, y, z, """) def test_if(self): self.t(u"if x:\n pass") def test_ifelifelse(self): self.t(u""" if x: pass elif y: pass elif z + 34 ** 34 - 2: pass else: pass """) def test_def(self): self.t(u""" def f(x, y, z): pass def f(x = 34, y = 54, z): pass """) def test_longness_and_signedness(self): self.t(u"def f(unsigned long long long long long int y):\n pass") def test_signed_short(self): self.t(u"def f(signed short int y):\n pass") def test_typed_args(self): self.t(u"def f(int x, unsigned long int y):\n pass") def test_cdef_var(self): self.t(u""" cdef int hello cdef int hello = 4, x = 3, y, z """) def test_for_loop(self): self.t(u""" for x, y, z in f(g(h(34) * 2) + 23): print x, y, z else: print 43 """) def test_inplace_assignment(self): self.t(u"x += 43") def test_attribute(self): self.t(u"a.x") if __name__ == "__main__": import unittest unittest.main() cython-0.20.1+git90-g0e6e38e/Cython/Tests/TestStringIOTree.py000066400000000000000000000036241231323242300233500ustar00rootroot00000000000000import unittest from Cython import StringIOTree as stringtree code = """ cdef int spam # line 1 cdef ham(): a = 1 b = 2 c = 3 d = 4 def eggs(): pass cpdef bacon(): print spam print 'scotch' print 'tea?' print 'or coffee?' # line 16 """ linemap = dict(enumerate(code.splitlines())) class TestStringIOTree(unittest.TestCase): def setUp(self): self.tree = stringtree.StringIOTree() def test_markers(self): assert not self.tree.allmarkers() def test_insertion(self): self.write_lines((1, 2, 3)) line_4_to_6_insertion_point = self.tree.insertion_point() self.write_lines((7, 8)) line_9_to_13_insertion_point = self.tree.insertion_point() self.write_lines((14, 15, 16)) line_4_insertion_point = line_4_to_6_insertion_point.insertion_point() self.write_lines((5, 6), tree=line_4_to_6_insertion_point) line_9_to_12_insertion_point = ( line_9_to_13_insertion_point.insertion_point()) self.write_line(13, tree=line_9_to_13_insertion_point) self.write_line(4, tree=line_4_insertion_point) self.write_line(9, tree=line_9_to_12_insertion_point) line_10_insertion_point = line_9_to_12_insertion_point.insertion_point() self.write_line(11, tree=line_9_to_12_insertion_point) self.write_line(10, tree=line_10_insertion_point) self.write_line(12, tree=line_9_to_12_insertion_point) self.assertEqual(self.tree.allmarkers(), range(1, 17)) self.assertEqual(code.strip(), self.tree.getvalue().strip()) def write_lines(self, linenos, tree=None): for lineno in linenos: self.write_line(lineno, tree=tree) def write_line(self, lineno, tree=None): if tree is None: tree = self.tree tree.markers.append(lineno) tree.write(linemap[lineno] + '\n') cython-0.20.1+git90-g0e6e38e/Cython/Tests/__init__.py000066400000000000000000000000151231323242300217200ustar00rootroot00000000000000# empty file cython-0.20.1+git90-g0e6e38e/Cython/Tests/xmlrunner.py000066400000000000000000000335061231323242300222260ustar00rootroot00000000000000# -*- coding: utf-8 -*- """unittest-xml-reporting is a PyUnit-based TestRunner that can export test results to XML files that can be consumed by a wide range of tools, such as build systems, IDEs and Continuous Integration servers. This module provides the XMLTestRunner class, which is heavily based on the default TextTestRunner. This makes the XMLTestRunner very simple to use. The script below, adapted from the unittest documentation, shows how to use XMLTestRunner in a very simple way. In fact, the only difference between this script and the original one is the last line: import random import unittest import xmlrunner class TestSequenceFunctions(unittest.TestCase): def setUp(self): self.seq = range(10) def test_shuffle(self): # make sure the shuffled sequence does not lose any elements random.shuffle(self.seq) self.seq.sort() self.assertEqual(self.seq, range(10)) def test_choice(self): element = random.choice(self.seq) self.assert_(element in self.seq) def test_sample(self): self.assertRaises(ValueError, random.sample, self.seq, 20) for element in random.sample(self.seq, 5): self.assert_(element in self.seq) if __name__ == '__main__': unittest.main(testRunner=xmlrunner.XMLTestRunner(output='test-reports')) """ import os import sys import time from unittest import TestResult, _TextTestResult, TextTestRunner from cStringIO import StringIO import xml.dom.minidom class XMLDocument(xml.dom.minidom.Document): def createCDATAOrText(self, data): if ']]>' in data: return self.createTextNode(data) return self.createCDATASection(data) class _TestInfo(object): """This class is used to keep useful information about the execution of a test method. """ # Possible test outcomes (SUCCESS, FAILURE, ERROR) = range(3) def __init__(self, test_result, test_method, outcome=SUCCESS, err=None): "Create a new instance of _TestInfo." self.test_result = test_result self.test_method = test_method self.outcome = outcome self.err = err self.stdout = test_result.stdout and test_result.stdout.getvalue().strip() or '' self.stderr = test_result.stdout and test_result.stderr.getvalue().strip() or '' def get_elapsed_time(self): """Return the time that shows how long the test method took to execute. """ return self.test_result.stop_time - self.test_result.start_time def get_description(self): "Return a text representation of the test method." return self.test_result.getDescription(self.test_method) def get_error_info(self): """Return a text representation of an exception thrown by a test method. """ if not self.err: return '' if sys.version_info < (2,4): return self.test_result._exc_info_to_string(self.err) else: return self.test_result._exc_info_to_string( self.err, self.test_method) class _XMLTestResult(_TextTestResult): """A test result class that can express test results in a XML report. Used by XMLTestRunner. """ def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1, \ elapsed_times=True): "Create a new instance of _XMLTestResult." _TextTestResult.__init__(self, stream, descriptions, verbosity) self.successes = [] self.callback = None self.elapsed_times = elapsed_times self.output_patched = False def _prepare_callback(self, test_info, target_list, verbose_str, short_str): """Append a _TestInfo to the given target list and sets a callback method to be called by stopTest method. """ target_list.append(test_info) def callback(): """This callback prints the test method outcome to the stream, as well as the elapsed time. """ # Ignore the elapsed times for a more reliable unit testing if not self.elapsed_times: self.start_time = self.stop_time = 0 if self.showAll: self.stream.writeln('(%.3fs) %s' % \ (test_info.get_elapsed_time(), verbose_str)) elif self.dots: self.stream.write(short_str) self.callback = callback def _patch_standard_output(self): """Replace the stdout and stderr streams with string-based streams in order to capture the tests' output. """ if not self.output_patched: (self.old_stdout, self.old_stderr) = (sys.stdout, sys.stderr) self.output_patched = True (sys.stdout, sys.stderr) = (self.stdout, self.stderr) = \ (StringIO(), StringIO()) def _restore_standard_output(self): "Restore the stdout and stderr streams." (sys.stdout, sys.stderr) = (self.old_stdout, self.old_stderr) self.output_patched = False def startTest(self, test): "Called before execute each test method." self._patch_standard_output() self.start_time = time.time() TestResult.startTest(self, test) if self.showAll: self.stream.write(' ' + self.getDescription(test)) self.stream.write(" ... ") def stopTest(self, test): "Called after execute each test method." self._restore_standard_output() _TextTestResult.stopTest(self, test) self.stop_time = time.time() if self.callback and callable(self.callback): self.callback() self.callback = None def addSuccess(self, test): "Called when a test executes successfully." self._prepare_callback(_TestInfo(self, test), self.successes, 'OK', '.') def addFailure(self, test, err): "Called when a test method fails." self._prepare_callback(_TestInfo(self, test, _TestInfo.FAILURE, err), self.failures, 'FAIL', 'F') def addError(self, test, err): "Called when a test method raises an error." self._prepare_callback(_TestInfo(self, test, _TestInfo.ERROR, err), self.errors, 'ERROR', 'E') def printErrorList(self, flavour, errors): "Write some information about the FAIL or ERROR to the stream." for test_info in errors: if isinstance(test_info, tuple): test_info, exc_info = test_info self.stream.writeln(self.separator1) self.stream.writeln('%s [%.3fs]: %s' % ( flavour, test_info.get_elapsed_time(), test_info.get_description())) self.stream.writeln(self.separator2) self.stream.writeln('%s' % test_info.get_error_info()) def _get_info_by_testcase(self): """This method organizes test results by TestCase module. This information is used during the report generation, where a XML report will be generated for each TestCase. """ tests_by_testcase = {} for tests in (self.successes, self.failures, self.errors): for test_info in tests: testcase = type(test_info.test_method) # Ignore module name if it is '__main__' module = testcase.__module__ + '.' if module == '__main__.': module = '' testcase_name = module + testcase.__name__ if testcase_name not in tests_by_testcase: tests_by_testcase[testcase_name] = [] tests_by_testcase[testcase_name].append(test_info) return tests_by_testcase def _report_testsuite(suite_name, tests, xml_document): "Appends the testsuite section to the XML document." testsuite = xml_document.createElement('testsuite') xml_document.appendChild(testsuite) testsuite.setAttribute('name', str(suite_name)) testsuite.setAttribute('tests', str(len(tests))) testsuite.setAttribute('time', '%.3f' % sum([e.get_elapsed_time() for e in tests])) failures = len([1 for e in tests if e.outcome == _TestInfo.FAILURE]) testsuite.setAttribute('failures', str(failures)) errors = len([1 for e in tests if e.outcome == _TestInfo.ERROR]) testsuite.setAttribute('errors', str(errors)) return testsuite _report_testsuite = staticmethod(_report_testsuite) def _report_testcase(suite_name, test_result, xml_testsuite, xml_document): "Appends a testcase section to the XML document." testcase = xml_document.createElement('testcase') xml_testsuite.appendChild(testcase) testcase.setAttribute('classname', str(suite_name)) testcase.setAttribute('name', test_result.test_method.shortDescription() or getattr(test_result.test_method, '_testMethodName', str(test_result.test_method))) testcase.setAttribute('time', '%.3f' % test_result.get_elapsed_time()) if (test_result.outcome != _TestInfo.SUCCESS): elem_name = ('failure', 'error')[test_result.outcome-1] failure = xml_document.createElement(elem_name) testcase.appendChild(failure) failure.setAttribute('type', str(test_result.err[0].__name__)) failure.setAttribute('message', str(test_result.err[1])) error_info = test_result.get_error_info() failureText = xml_document.createCDATAOrText(error_info) failure.appendChild(failureText) _report_testcase = staticmethod(_report_testcase) def _report_output(test_runner, xml_testsuite, xml_document, stdout, stderr): "Appends the system-out and system-err sections to the XML document." systemout = xml_document.createElement('system-out') xml_testsuite.appendChild(systemout) systemout_text = xml_document.createCDATAOrText(stdout) systemout.appendChild(systemout_text) systemerr = xml_document.createElement('system-err') xml_testsuite.appendChild(systemerr) systemerr_text = xml_document.createCDATAOrText(stderr) systemerr.appendChild(systemerr_text) _report_output = staticmethod(_report_output) def generate_reports(self, test_runner): "Generates the XML reports to a given XMLTestRunner object." all_results = self._get_info_by_testcase() if type(test_runner.output) == str and not \ os.path.exists(test_runner.output): os.makedirs(test_runner.output) for suite, tests in all_results.items(): doc = XMLDocument() # Build the XML file testsuite = _XMLTestResult._report_testsuite(suite, tests, doc) stdout, stderr = [], [] for test in tests: _XMLTestResult._report_testcase(suite, test, testsuite, doc) if test.stdout: stdout.extend(['*****************', test.get_description(), test.stdout]) if test.stderr: stderr.extend(['*****************', test.get_description(), test.stderr]) _XMLTestResult._report_output(test_runner, testsuite, doc, '\n'.join(stdout), '\n'.join(stderr)) xml_content = doc.toprettyxml(indent='\t') if type(test_runner.output) is str: report_file = open('%s%sTEST-%s.xml' % \ (test_runner.output, os.sep, suite), 'w') try: report_file.write(xml_content) finally: report_file.close() else: # Assume that test_runner.output is a stream test_runner.output.write(xml_content) class XMLTestRunner(TextTestRunner): """A test runner class that outputs the results in JUnit like XML files. """ def __init__(self, output='.', stream=sys.stderr, descriptions=True, \ verbose=False, elapsed_times=True): "Create a new instance of XMLTestRunner." verbosity = (1, 2)[verbose] TextTestRunner.__init__(self, stream, descriptions, verbosity) self.output = output self.elapsed_times = elapsed_times def _make_result(self): """Create the TestResult object which will be used to store information about the executed tests. """ return _XMLTestResult(self.stream, self.descriptions, \ self.verbosity, self.elapsed_times) def run(self, test): "Run the given test case or test suite." # Prepare the test execution result = self._make_result() # Print a nice header self.stream.writeln() self.stream.writeln('Running tests...') self.stream.writeln(result.separator2) # Execute tests start_time = time.time() test(result) stop_time = time.time() time_taken = stop_time - start_time # Print results result.printErrors() self.stream.writeln(result.separator2) run = result.testsRun self.stream.writeln("Ran %d test%s in %.3fs" % (run, run != 1 and "s" or "", time_taken)) self.stream.writeln() # Error traces if not result.wasSuccessful(): self.stream.write("FAILED (") failed, errored = (len(result.failures), len(result.errors)) if failed: self.stream.write("failures=%d" % failed) if errored: if failed: self.stream.write(", ") self.stream.write("errors=%d" % errored) self.stream.writeln(")") else: self.stream.writeln("OK") # Generate reports self.stream.writeln() self.stream.writeln('Generating XML reports...') result.generate_reports(self) return result cython-0.20.1+git90-g0e6e38e/Cython/Utility/000077500000000000000000000000001231323242300201545ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Cython/Utility/Buffer.c000066400000000000000000000720721231323242300215410ustar00rootroot00000000000000/////////////// BufferStructDeclare.proto /////////////// /* structs for buffer access */ typedef struct { Py_ssize_t shape, strides, suboffsets; } __Pyx_Buf_DimInfo; typedef struct { size_t refcount; Py_buffer pybuffer; } __Pyx_Buffer; typedef struct { __Pyx_Buffer *rcbuffer; char *data; __Pyx_Buf_DimInfo diminfo[{{max_dims}}]; } __Pyx_LocalBuf_ND; /////////////// BufferIndexError.proto /////////////// static void __Pyx_RaiseBufferIndexError(int axis); /*proto*/ /////////////// BufferIndexError /////////////// static void __Pyx_RaiseBufferIndexError(int axis) { PyErr_Format(PyExc_IndexError, "Out of bounds on buffer access (axis %d)", axis); } /////////////// BufferIndexErrorNogil.proto /////////////// //@requires: BufferIndexError static void __Pyx_RaiseBufferIndexErrorNogil(int axis); /*proto*/ /////////////// BufferIndexErrorNogil /////////////// static void __Pyx_RaiseBufferIndexErrorNogil(int axis) { #ifdef WITH_THREAD PyGILState_STATE gilstate = PyGILState_Ensure(); #endif __Pyx_RaiseBufferIndexError(axis); #ifdef WITH_THREAD PyGILState_Release(gilstate); #endif } /////////////// BufferFallbackError.proto /////////////// static void __Pyx_RaiseBufferFallbackError(void); /*proto*/ /////////////// BufferFallbackError /////////////// static void __Pyx_RaiseBufferFallbackError(void) { PyErr_SetString(PyExc_ValueError, "Buffer acquisition failed on assignment; and then reacquiring the old buffer failed too!"); } /////////////// BufferFormatStructs.proto /////////////// #define IS_UNSIGNED(type) (((type) -1) > 0) /* Run-time type information about structs used with buffers */ struct __Pyx_StructField_; #define __PYX_BUF_FLAGS_PACKED_STRUCT (1 << 0) typedef struct { const char* name; /* for error messages only */ struct __Pyx_StructField_* fields; size_t size; /* sizeof(type) */ size_t arraysize[8]; /* length of array in each dimension */ int ndim; char typegroup; /* _R_eal, _C_omplex, Signed _I_nt, _U_nsigned int, _S_truct, _P_ointer, _O_bject, c_H_ar */ char is_unsigned; int flags; } __Pyx_TypeInfo; typedef struct __Pyx_StructField_ { __Pyx_TypeInfo* type; const char* name; size_t offset; } __Pyx_StructField; typedef struct { __Pyx_StructField* field; size_t parent_offset; } __Pyx_BufFmt_StackElem; typedef struct { __Pyx_StructField root; __Pyx_BufFmt_StackElem* head; size_t fmt_offset; size_t new_count, enc_count; size_t struct_alignment; int is_complex; char enc_type; char new_packmode; char enc_packmode; char is_valid_array; } __Pyx_BufFmt_Context; /////////////// GetAndReleaseBuffer.proto /////////////// #if PY_MAJOR_VERSION < 3 static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags); static void __Pyx_ReleaseBuffer(Py_buffer *view); #else #define __Pyx_GetBuffer PyObject_GetBuffer #define __Pyx_ReleaseBuffer PyBuffer_Release #endif /////////////// GetAndReleaseBuffer /////////////// #if PY_MAJOR_VERSION < 3 static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { #if PY_VERSION_HEX >= 0x02060000 if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags); #endif {{for type_ptr, getbuffer, releasebuffer in types}} {{if getbuffer}} if (PyObject_TypeCheck(obj, {{type_ptr}})) return {{getbuffer}}(obj, view, flags); {{endif}} {{endfor}} #if PY_VERSION_HEX < 0x02060000 if (obj->ob_type->tp_dict) { PyObject *getbuffer_cobj = PyObject_GetItem( obj->ob_type->tp_dict, PYIDENT("__pyx_getbuffer")); if (getbuffer_cobj) { getbufferproc func = (getbufferproc) PyCObject_AsVoidPtr(getbuffer_cobj); Py_DECREF(getbuffer_cobj); if (!func) goto fail; return func(obj, view, flags); } else { PyErr_Clear(); } } #endif PyErr_Format(PyExc_TypeError, "'%.200s' does not have the buffer interface", Py_TYPE(obj)->tp_name); #if PY_VERSION_HEX < 0x02060000 fail: #endif return -1; } static void __Pyx_ReleaseBuffer(Py_buffer *view) { PyObject *obj = view->obj; if (!obj) return; #if PY_VERSION_HEX >= 0x02060000 if (PyObject_CheckBuffer(obj)) { PyBuffer_Release(view); return; } #endif {{for type_ptr, getbuffer, releasebuffer in types}} {{if releasebuffer}} if (PyObject_TypeCheck(obj, {{type_ptr}})) { {{releasebuffer}}(obj, view); return; } {{endif}} {{endfor}} #if PY_VERSION_HEX < 0x02060000 if (obj->ob_type->tp_dict) { PyObject *releasebuffer_cobj = PyObject_GetItem( obj->ob_type->tp_dict, PYIDENT("__pyx_releasebuffer")); if (releasebuffer_cobj) { releasebufferproc func = (releasebufferproc) PyCObject_AsVoidPtr(releasebuffer_cobj); Py_DECREF(releasebuffer_cobj); if (!func) goto fail; func(obj, view); return; } else { PyErr_Clear(); } } #endif goto nofail; #if PY_VERSION_HEX < 0x02060000 fail: #endif PyErr_WriteUnraisable(obj); nofail: Py_DECREF(obj); view->obj = NULL; } #endif /* PY_MAJOR_VERSION < 3 */ /////////////// BufferFormatCheck.proto /////////////// {{# Buffer format string checking Buffer type checking. Utility code for checking that acquired buffers match our assumptions. We only need to check ndim and the format string; the access mode/flags is checked by the exporter. See: http://docs.python.org/3/library/struct.html http://legacy.python.org/dev/peps/pep-3118/#additions-to-the-struct-string-syntax The alignment code is copied from _struct.c in Python. }} static CYTHON_INLINE int __Pyx_GetBufferAndValidate(Py_buffer* buf, PyObject* obj, __Pyx_TypeInfo* dtype, int flags, int nd, int cast, __Pyx_BufFmt_StackElem* stack); static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info); /////////////// BufferFormatCheck /////////////// static CYTHON_INLINE int __Pyx_IsLittleEndian(void) { unsigned int n = 1; return *(unsigned char*)(&n) != 0; } static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx, __Pyx_BufFmt_StackElem* stack, __Pyx_TypeInfo* type) { stack[0].field = &ctx->root; stack[0].parent_offset = 0; ctx->root.type = type; ctx->root.name = "buffer dtype"; ctx->root.offset = 0; ctx->head = stack; ctx->head->field = &ctx->root; ctx->fmt_offset = 0; ctx->head->parent_offset = 0; ctx->new_packmode = '@'; ctx->enc_packmode = '@'; ctx->new_count = 1; ctx->enc_count = 0; ctx->enc_type = 0; ctx->is_complex = 0; ctx->is_valid_array = 0; ctx->struct_alignment = 0; while (type->typegroup == 'S') { ++ctx->head; ctx->head->field = type->fields; ctx->head->parent_offset = 0; type = type->fields->type; } } static int __Pyx_BufFmt_ParseNumber(const char** ts) { int count; const char* t = *ts; if (*t < '0' || *t > '9') { return -1; } else { count = *t++ - '0'; while (*t >= '0' && *t < '9') { count *= 10; count += *t++ - '0'; } } *ts = t; return count; } static int __Pyx_BufFmt_ExpectNumber(const char **ts) { int number = __Pyx_BufFmt_ParseNumber(ts); if (number == -1) /* First char was not a digit */ PyErr_Format(PyExc_ValueError,\ "Does not understand character buffer dtype format string ('%c')", **ts); return number; } static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) { PyErr_Format(PyExc_ValueError, "Unexpected format string character: '%c'", ch); } static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) { switch (ch) { case 'c': return "'char'"; case 'b': return "'signed char'"; case 'B': return "'unsigned char'"; case 'h': return "'short'"; case 'H': return "'unsigned short'"; case 'i': return "'int'"; case 'I': return "'unsigned int'"; case 'l': return "'long'"; case 'L': return "'unsigned long'"; case 'q': return "'long long'"; case 'Q': return "'unsigned long long'"; case 'f': return (is_complex ? "'complex float'" : "'float'"); case 'd': return (is_complex ? "'complex double'" : "'double'"); case 'g': return (is_complex ? "'complex long double'" : "'long double'"); case 'T': return "a struct"; case 'O': return "Python object"; case 'P': return "a pointer"; case 's': case 'p': return "a string"; case 0: return "end"; default: return "unparseable format string"; } } static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) { switch (ch) { case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; case 'h': case 'H': return 2; case 'i': case 'I': case 'l': case 'L': return 4; case 'q': case 'Q': return 8; case 'f': return (is_complex ? 8 : 4); case 'd': return (is_complex ? 16 : 8); case 'g': { PyErr_SetString(PyExc_ValueError, "Python does not define a standard format string size for long double ('g').."); return 0; } case 'O': case 'P': return sizeof(void*); default: __Pyx_BufFmt_RaiseUnexpectedChar(ch); return 0; } } static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) { switch (ch) { case 'c': case 'b': case 'B': case 's': case 'p': return 1; case 'h': case 'H': return sizeof(short); case 'i': case 'I': return sizeof(int); case 'l': case 'L': return sizeof(long); #ifdef HAVE_LONG_LONG case 'q': case 'Q': return sizeof(PY_LONG_LONG); #endif case 'f': return sizeof(float) * (is_complex ? 2 : 1); case 'd': return sizeof(double) * (is_complex ? 2 : 1); case 'g': return sizeof(long double) * (is_complex ? 2 : 1); case 'O': case 'P': return sizeof(void*); default: { __Pyx_BufFmt_RaiseUnexpectedChar(ch); return 0; } } } typedef struct { char c; short x; } __Pyx_st_short; typedef struct { char c; int x; } __Pyx_st_int; typedef struct { char c; long x; } __Pyx_st_long; typedef struct { char c; float x; } __Pyx_st_float; typedef struct { char c; double x; } __Pyx_st_double; typedef struct { char c; long double x; } __Pyx_st_longdouble; typedef struct { char c; void *x; } __Pyx_st_void_p; #ifdef HAVE_LONG_LONG typedef struct { char c; PY_LONG_LONG x; } __Pyx_st_longlong; #endif static size_t __Pyx_BufFmt_TypeCharToAlignment(char ch, CYTHON_UNUSED int is_complex) { switch (ch) { case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; case 'h': case 'H': return sizeof(__Pyx_st_short) - sizeof(short); case 'i': case 'I': return sizeof(__Pyx_st_int) - sizeof(int); case 'l': case 'L': return sizeof(__Pyx_st_long) - sizeof(long); #ifdef HAVE_LONG_LONG case 'q': case 'Q': return sizeof(__Pyx_st_longlong) - sizeof(PY_LONG_LONG); #endif case 'f': return sizeof(__Pyx_st_float) - sizeof(float); case 'd': return sizeof(__Pyx_st_double) - sizeof(double); case 'g': return sizeof(__Pyx_st_longdouble) - sizeof(long double); case 'P': case 'O': return sizeof(__Pyx_st_void_p) - sizeof(void*); default: __Pyx_BufFmt_RaiseUnexpectedChar(ch); return 0; } } /* These are for computing the padding at the end of the struct to align on the first member of the struct. This will probably the same as above, but we don't have any guarantees. */ typedef struct { short x; char c; } __Pyx_pad_short; typedef struct { int x; char c; } __Pyx_pad_int; typedef struct { long x; char c; } __Pyx_pad_long; typedef struct { float x; char c; } __Pyx_pad_float; typedef struct { double x; char c; } __Pyx_pad_double; typedef struct { long double x; char c; } __Pyx_pad_longdouble; typedef struct { void *x; char c; } __Pyx_pad_void_p; #ifdef HAVE_LONG_LONG typedef struct { PY_LONG_LONG x; char c; } __Pyx_pad_longlong; #endif static size_t __Pyx_BufFmt_TypeCharToPadding(char ch, CYTHON_UNUSED int is_complex) { switch (ch) { case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; case 'h': case 'H': return sizeof(__Pyx_pad_short) - sizeof(short); case 'i': case 'I': return sizeof(__Pyx_pad_int) - sizeof(int); case 'l': case 'L': return sizeof(__Pyx_pad_long) - sizeof(long); #ifdef HAVE_LONG_LONG case 'q': case 'Q': return sizeof(__Pyx_pad_longlong) - sizeof(PY_LONG_LONG); #endif case 'f': return sizeof(__Pyx_pad_float) - sizeof(float); case 'd': return sizeof(__Pyx_pad_double) - sizeof(double); case 'g': return sizeof(__Pyx_pad_longdouble) - sizeof(long double); case 'P': case 'O': return sizeof(__Pyx_pad_void_p) - sizeof(void*); default: __Pyx_BufFmt_RaiseUnexpectedChar(ch); return 0; } } static char __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) { switch (ch) { case 'c': return 'H'; case 'b': case 'h': case 'i': case 'l': case 'q': case 's': case 'p': return 'I'; case 'B': case 'H': case 'I': case 'L': case 'Q': return 'U'; case 'f': case 'd': case 'g': return (is_complex ? 'C' : 'R'); case 'O': return 'O'; case 'P': return 'P'; default: { __Pyx_BufFmt_RaiseUnexpectedChar(ch); return 0; } } } static void __Pyx_BufFmt_RaiseExpected(__Pyx_BufFmt_Context* ctx) { if (ctx->head == NULL || ctx->head->field == &ctx->root) { const char* expected; const char* quote; if (ctx->head == NULL) { expected = "end"; quote = ""; } else { expected = ctx->head->field->type->name; quote = "'"; } PyErr_Format(PyExc_ValueError, "Buffer dtype mismatch, expected %s%s%s but got %s", quote, expected, quote, __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex)); } else { __Pyx_StructField* field = ctx->head->field; __Pyx_StructField* parent = (ctx->head - 1)->field; PyErr_Format(PyExc_ValueError, "Buffer dtype mismatch, expected '%s' but got %s in '%s.%s'", field->type->name, __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex), parent->type->name, field->name); } } static int __Pyx_BufFmt_ProcessTypeChunk(__Pyx_BufFmt_Context* ctx) { char group; size_t size, offset, arraysize = 1; /* printf("processing... %s\n", ctx->head->field->type->name); */ if (ctx->enc_type == 0) return 0; /* Validate array size */ if (ctx->head->field->type->arraysize[0]) { int i, ndim = 0; /* handle strings ('s' and 'p') */ if (ctx->enc_type == 's' || ctx->enc_type == 'p') { ctx->is_valid_array = ctx->head->field->type->ndim == 1; ndim = 1; if (ctx->enc_count != ctx->head->field->type->arraysize[0]) { PyErr_Format(PyExc_ValueError, "Expected a dimension of size %zu, got %zu", ctx->head->field->type->arraysize[0], ctx->enc_count); return -1; } } if (!ctx->is_valid_array) { PyErr_Format(PyExc_ValueError, "Expected %d dimensions, got %d", ctx->head->field->type->ndim, ndim); return -1; } for (i = 0; i < ctx->head->field->type->ndim; i++) { arraysize *= ctx->head->field->type->arraysize[i]; } ctx->is_valid_array = 0; ctx->enc_count = 1; } group = __Pyx_BufFmt_TypeCharToGroup(ctx->enc_type, ctx->is_complex); do { __Pyx_StructField* field = ctx->head->field; __Pyx_TypeInfo* type = field->type; if (ctx->enc_packmode == '@' || ctx->enc_packmode == '^') { size = __Pyx_BufFmt_TypeCharToNativeSize(ctx->enc_type, ctx->is_complex); } else { size = __Pyx_BufFmt_TypeCharToStandardSize(ctx->enc_type, ctx->is_complex); } if (ctx->enc_packmode == '@') { size_t align_at = __Pyx_BufFmt_TypeCharToAlignment(ctx->enc_type, ctx->is_complex); size_t align_mod_offset; if (align_at == 0) return -1; align_mod_offset = ctx->fmt_offset % align_at; if (align_mod_offset > 0) ctx->fmt_offset += align_at - align_mod_offset; if (ctx->struct_alignment == 0) ctx->struct_alignment = __Pyx_BufFmt_TypeCharToPadding(ctx->enc_type, ctx->is_complex); } if (type->size != size || type->typegroup != group) { if (type->typegroup == 'C' && type->fields != NULL) { /* special case -- treat as struct rather than complex number */ size_t parent_offset = ctx->head->parent_offset + field->offset; ++ctx->head; ctx->head->field = type->fields; ctx->head->parent_offset = parent_offset; continue; } if ((type->typegroup == 'H' || group == 'H') && type->size == size) { /* special case -- chars don't care about sign */ } else { __Pyx_BufFmt_RaiseExpected(ctx); return -1; } } offset = ctx->head->parent_offset + field->offset; if (ctx->fmt_offset != offset) { PyErr_Format(PyExc_ValueError, "Buffer dtype mismatch; next field is at offset %" CYTHON_FORMAT_SSIZE_T "d but %" CYTHON_FORMAT_SSIZE_T "d expected", (Py_ssize_t)ctx->fmt_offset, (Py_ssize_t)offset); return -1; } ctx->fmt_offset += size; if (arraysize) ctx->fmt_offset += (arraysize - 1) * size; --ctx->enc_count; /* Consume from buffer string */ /* Done checking, move to next field, pushing or popping struct stack if needed */ while (1) { if (field == &ctx->root) { ctx->head = NULL; if (ctx->enc_count != 0) { __Pyx_BufFmt_RaiseExpected(ctx); return -1; } break; /* breaks both loops as ctx->enc_count == 0 */ } ctx->head->field = ++field; if (field->type == NULL) { --ctx->head; field = ctx->head->field; continue; } else if (field->type->typegroup == 'S') { size_t parent_offset = ctx->head->parent_offset + field->offset; if (field->type->fields->type == NULL) continue; /* empty struct */ field = field->type->fields; ++ctx->head; ctx->head->field = field; ctx->head->parent_offset = parent_offset; break; } else { break; } } } while (ctx->enc_count); ctx->enc_type = 0; ctx->is_complex = 0; return 0; } /* Parse an array in the format string (e.g. (1,2,3)) */ static CYTHON_INLINE PyObject * __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) { const char *ts = *tsp; int i = 0, number; int ndim = ctx->head->field->type->ndim; ; ++ts; if (ctx->new_count != 1) { PyErr_SetString(PyExc_ValueError, "Cannot handle repeated arrays in format string"); return NULL; } /* Process the previous element */ if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; /* Parse all numbers in the format string */ while (*ts && *ts != ')') { // ignore space characters (not using isspace() due to C/C++ problem on MacOS-X) switch (*ts) { case ' ': case '\f': case '\r': case '\n': case '\t': case '\v': continue; default: break; /* not a 'break' in the loop */ } number = __Pyx_BufFmt_ExpectNumber(&ts); if (number == -1) return NULL; if (i < ndim && (size_t) number != ctx->head->field->type->arraysize[i]) return PyErr_Format(PyExc_ValueError, "Expected a dimension of size %zu, got %d", ctx->head->field->type->arraysize[i], number); if (*ts != ',' && *ts != ')') return PyErr_Format(PyExc_ValueError, "Expected a comma in format string, got '%c'", *ts); if (*ts == ',') ts++; i++; } if (i != ndim) return PyErr_Format(PyExc_ValueError, "Expected %d dimension(s), got %d", ctx->head->field->type->ndim, i); if (!*ts) { PyErr_SetString(PyExc_ValueError, "Unexpected end of format string, expected ')'"); return NULL; } ctx->is_valid_array = 1; ctx->new_count = 1; *tsp = ++ts; return Py_None; } static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts) { int got_Z = 0; while (1) { /* puts(ts); */ switch(*ts) { case 0: if (ctx->enc_type != 0 && ctx->head == NULL) { __Pyx_BufFmt_RaiseExpected(ctx); return NULL; } if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; if (ctx->head != NULL) { __Pyx_BufFmt_RaiseExpected(ctx); return NULL; } return ts; case ' ': case '\r': case '\n': ++ts; break; case '<': if (!__Pyx_IsLittleEndian()) { PyErr_SetString(PyExc_ValueError, "Little-endian buffer not supported on big-endian compiler"); return NULL; } ctx->new_packmode = '='; ++ts; break; case '>': case '!': if (__Pyx_IsLittleEndian()) { PyErr_SetString(PyExc_ValueError, "Big-endian buffer not supported on little-endian compiler"); return NULL; } ctx->new_packmode = '='; ++ts; break; case '=': case '@': case '^': ctx->new_packmode = *ts++; break; case 'T': /* substruct */ { const char* ts_after_sub; size_t i, struct_count = ctx->new_count; size_t struct_alignment = ctx->struct_alignment; ctx->new_count = 1; ++ts; if (*ts != '{') { PyErr_SetString(PyExc_ValueError, "Buffer acquisition: Expected '{' after 'T'"); return NULL; } if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; ctx->enc_type = 0; /* Erase processed last struct element */ ctx->enc_count = 0; ctx->struct_alignment = 0; ++ts; ts_after_sub = ts; for (i = 0; i != struct_count; ++i) { ts_after_sub = __Pyx_BufFmt_CheckString(ctx, ts); if (!ts_after_sub) return NULL; } ts = ts_after_sub; if (struct_alignment) ctx->struct_alignment = struct_alignment; } break; case '}': /* end of substruct; either repeat or move on */ { size_t alignment = ctx->struct_alignment; ++ts; if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; ctx->enc_type = 0; /* Erase processed last struct element */ if (alignment && ctx->fmt_offset % alignment) { /* Pad struct on size of the first member */ ctx->fmt_offset += alignment - (ctx->fmt_offset % alignment); } } return ts; case 'x': if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; ctx->fmt_offset += ctx->new_count; ctx->new_count = 1; ctx->enc_count = 0; ctx->enc_type = 0; ctx->enc_packmode = ctx->new_packmode; ++ts; break; case 'Z': got_Z = 1; ++ts; if (*ts != 'f' && *ts != 'd' && *ts != 'g') { __Pyx_BufFmt_RaiseUnexpectedChar('Z'); return NULL; } /* fall through */ case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': case 'l': case 'L': case 'q': case 'Q': case 'f': case 'd': case 'g': case 'O': case 'p': if (ctx->enc_type == *ts && got_Z == ctx->is_complex && ctx->enc_packmode == ctx->new_packmode) { /* Continue pooling same type */ ctx->enc_count += ctx->new_count; ctx->new_count = 1; got_Z = 0; ++ts; break; } /* fall through */ case 's': /* 's' or new type (cannot be added to current pool) */ if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; ctx->enc_count = ctx->new_count; ctx->enc_packmode = ctx->new_packmode; ctx->enc_type = *ts; ctx->is_complex = got_Z; ++ts; ctx->new_count = 1; got_Z = 0; break; case ':': ++ts; while(*ts != ':') ++ts; ++ts; break; case '(': if (!__pyx_buffmt_parse_array(ctx, &ts)) return NULL; break; default: { int number = __Pyx_BufFmt_ExpectNumber(&ts); if (number == -1) return NULL; ctx->new_count = (size_t)number; } } } } static CYTHON_INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) { buf->buf = NULL; buf->obj = NULL; buf->strides = __Pyx_zeros; buf->shape = __Pyx_zeros; buf->suboffsets = __Pyx_minusones; } static CYTHON_INLINE int __Pyx_GetBufferAndValidate( Py_buffer* buf, PyObject* obj, __Pyx_TypeInfo* dtype, int flags, int nd, int cast, __Pyx_BufFmt_StackElem* stack) { if (obj == Py_None || obj == NULL) { __Pyx_ZeroBuffer(buf); return 0; } buf->buf = NULL; if (__Pyx_GetBuffer(obj, buf, flags) == -1) goto fail; if (buf->ndim != nd) { PyErr_Format(PyExc_ValueError, "Buffer has wrong number of dimensions (expected %d, got %d)", nd, buf->ndim); goto fail; } if (!cast) { __Pyx_BufFmt_Context ctx; __Pyx_BufFmt_Init(&ctx, stack, dtype); if (!__Pyx_BufFmt_CheckString(&ctx, buf->format)) goto fail; } if ((unsigned)buf->itemsize != dtype->size) { PyErr_Format(PyExc_ValueError, "Item size of buffer (%" CYTHON_FORMAT_SSIZE_T "d byte%s) does not match size of '%s' (%" CYTHON_FORMAT_SSIZE_T "d byte%s)", buf->itemsize, (buf->itemsize > 1) ? "s" : "", dtype->name, (Py_ssize_t)dtype->size, (dtype->size > 1) ? "s" : ""); goto fail; } if (buf->suboffsets == NULL) buf->suboffsets = __Pyx_minusones; return 0; fail:; __Pyx_ZeroBuffer(buf); return -1; } static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info) { if (info->buf == NULL) return; if (info->suboffsets == __Pyx_minusones) info->suboffsets = NULL; __Pyx_ReleaseBuffer(info); } /////////////// TypeInfoCompare.proto /////////////// static int __pyx_typeinfo_cmp(__Pyx_TypeInfo *a, __Pyx_TypeInfo *b); /////////////// TypeInfoCompare /////////////// /* See if two dtypes are equal */ static int __pyx_typeinfo_cmp(__Pyx_TypeInfo *a, __Pyx_TypeInfo *b) { int i; if (!a || !b) return 0; if (a == b) return 1; if (a->size != b->size || a->typegroup != b->typegroup || a->is_unsigned != b->is_unsigned || a->ndim != b->ndim) { if (a->typegroup == 'H' || b->typegroup == 'H') { /* Special case for chars */ return a->size == b->size; } else { return 0; } } if (a->ndim) { /* Verify multidimensional C arrays */ for (i = 0; i < a->ndim; i++) if (a->arraysize[i] != b->arraysize[i]) return 0; } if (a->typegroup == 'S') { /* Check for packed struct */ if (a->flags != b->flags) return 0; /* compare all struct fields */ if (a->fields || b->fields) { /* Check if both have fields */ if (!(a->fields && b->fields)) return 0; /* compare */ for (i = 0; a->fields[i].type && b->fields[i].type; i++) { __Pyx_StructField *field_a = a->fields + i; __Pyx_StructField *field_b = b->fields + i; if (field_a->offset != field_b->offset || !__pyx_typeinfo_cmp(field_a->type, field_b->type)) return 0; } /* If all fields are processed, we have a match */ return !a->fields[i].type && !b->fields[i].type; } } return 1; } /////////////// TypeInfoToFormat.proto /////////////// struct __pyx_typeinfo_string { char string[3]; }; static struct __pyx_typeinfo_string __Pyx_TypeInfoToFormat(__Pyx_TypeInfo *type); /////////////// TypeInfoToFormat /////////////// {{# See also MemoryView.pyx:BufferFormatFromTypeInfo }} static struct __pyx_typeinfo_string __Pyx_TypeInfoToFormat(__Pyx_TypeInfo *type) { struct __pyx_typeinfo_string result = { {0} }; char *buf = (char *) result.string; size_t size = type->size; switch (type->typegroup) { case 'H': *buf = 'c'; break; case 'I': case 'U': if (size == 1) *buf = 'b'; else if (size == 2) *buf = 'h'; else if (size == 4) *buf = 'i'; else if (size == 8) *buf = 'q'; if (type->is_unsigned) *buf = toupper(*buf); break; case 'P': *buf = 'P'; break; case 'C': { __Pyx_TypeInfo complex_type = *type; complex_type.typegroup = 'R'; complex_type.size /= 2; *buf++ = 'Z'; *buf = __Pyx_TypeInfoToFormat(&complex_type).string[0]; break; } case 'R': if (size == 4) *buf = 'f'; else if (size == 8) *buf = 'd'; else *buf = 'g'; break; } return result; } cython-0.20.1+git90-g0e6e38e/Cython/Utility/Builtins.c000066400000000000000000000334451231323242300221220ustar00rootroot00000000000000/* * Special implementations of built-in functions and methods. * * Optional optimisations for builtins are in Optimize.c. * * General object operations and protocols are in ObjectHandling.c. */ //////////////////// Globals.proto //////////////////// static PyObject* __Pyx_Globals(void); /*proto*/ //////////////////// Globals //////////////////// //@substitute: naming //@requires: ObjectHandling.c::GetAttr // This is a stub implementation until we have something more complete. // Currently, we only handle the most common case of a read-only dict // of Python names. Supporting cdef names in the module and write // access requires a rewrite as a dedicated class. static PyObject* __Pyx_Globals(void) { Py_ssize_t i; //PyObject *d; PyObject *names = NULL; PyObject *globals = PyObject_GetAttr($module_cname, PYIDENT("__dict__")); if (!globals) { PyErr_SetString(PyExc_TypeError, "current module must have __dict__ attribute"); goto bad; } names = PyObject_Dir($module_cname); if (!names) goto bad; for (i = PyList_GET_SIZE(names)-1; i >= 0; i--) { #if CYTHON_COMPILING_IN_PYPY PyObject* name = PySequence_GetItem(names, i); if (!name) goto bad; #else PyObject* name = PyList_GET_ITEM(names, i); #endif if (!PyDict_Contains(globals, name)) { PyObject* value = __Pyx_GetAttr($module_cname, name); if (!value) { #if CYTHON_COMPILING_IN_PYPY Py_DECREF(name); #endif goto bad; } if (PyDict_SetItem(globals, name, value) < 0) { #if CYTHON_COMPILING_IN_PYPY Py_DECREF(name); #endif Py_DECREF(value); goto bad; } } #if CYTHON_COMPILING_IN_PYPY Py_DECREF(name); #endif } Py_DECREF(names); return globals; // d = PyDictProxy_New(globals); // Py_DECREF(globals); // return d; bad: Py_XDECREF(names); Py_XDECREF(globals); return NULL; } //////////////////// PyExecGlobals.proto //////////////////// static PyObject* __Pyx_PyExecGlobals(PyObject*); //////////////////// PyExecGlobals //////////////////// //@requires: Globals //@requires: PyExec static PyObject* __Pyx_PyExecGlobals(PyObject* code) { PyObject* result; PyObject* globals = __Pyx_Globals(); if (unlikely(!globals)) return NULL; result = __Pyx_PyExec2(code, globals); Py_DECREF(globals); return result; } //////////////////// PyExec.proto //////////////////// static PyObject* __Pyx_PyExec3(PyObject*, PyObject*, PyObject*); static CYTHON_INLINE PyObject* __Pyx_PyExec2(PyObject*, PyObject*); //////////////////// PyExec //////////////////// //@substitute: naming static CYTHON_INLINE PyObject* __Pyx_PyExec2(PyObject* o, PyObject* globals) { return __Pyx_PyExec3(o, globals, NULL); } static PyObject* __Pyx_PyExec3(PyObject* o, PyObject* globals, PyObject* locals) { PyObject* result; PyObject* s = 0; char *code = 0; if (!globals || globals == Py_None) { globals = PyModule_GetDict($module_cname); if (!globals) goto bad; } else if (!PyDict_Check(globals)) { PyErr_Format(PyExc_TypeError, "exec() arg 2 must be a dict, not %.200s", Py_TYPE(globals)->tp_name); goto bad; } if (!locals || locals == Py_None) { locals = globals; } if (PyDict_GetItem(globals, PYIDENT("__builtins__")) == NULL) { if (PyDict_SetItem(globals, PYIDENT("__builtins__"), PyEval_GetBuiltins()) < 0) goto bad; } if (PyCode_Check(o)) { if (PyCode_GetNumFree((PyCodeObject *)o) > 0) { PyErr_SetString(PyExc_TypeError, "code object passed to exec() may not contain free variables"); goto bad; } #if PY_VERSION_HEX < 0x030200B1 result = PyEval_EvalCode((PyCodeObject *)o, globals, locals); #else result = PyEval_EvalCode(o, globals, locals); #endif } else { PyCompilerFlags cf; cf.cf_flags = 0; if (PyUnicode_Check(o)) { cf.cf_flags = PyCF_SOURCE_IS_UTF8; s = PyUnicode_AsUTF8String(o); if (!s) goto bad; o = s; #if PY_MAJOR_VERSION >= 3 } else if (!PyBytes_Check(o)) { #else } else if (!PyString_Check(o)) { #endif PyErr_Format(PyExc_TypeError, "exec: arg 1 must be string, bytes or code object, got %.200s", Py_TYPE(o)->tp_name); goto bad; } #if PY_MAJOR_VERSION >= 3 code = PyBytes_AS_STRING(o); #else code = PyString_AS_STRING(o); #endif if (PyEval_MergeCompilerFlags(&cf)) { result = PyRun_StringFlags(code, Py_file_input, globals, locals, &cf); } else { result = PyRun_String(code, Py_file_input, globals, locals); } Py_XDECREF(s); } return result; bad: Py_XDECREF(s); return 0; } //////////////////// GetAttr3.proto //////////////////// static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *); /*proto*/ //////////////////// GetAttr3 //////////////////// //@requires: ObjectHandling.c::GetAttr static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *o, PyObject *n, PyObject *d) { PyObject *r = __Pyx_GetAttr(o, n); if (unlikely(!r)) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; PyErr_Clear(); r = d; Py_INCREF(d); } return r; bad: return NULL; } //////////////////// Intern.proto //////////////////// static PyObject* __Pyx_Intern(PyObject* s); /* proto */ //////////////////// Intern //////////////////// static PyObject* __Pyx_Intern(PyObject* s) { if (!(likely(PyString_CheckExact(s)))) { PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(s)->tp_name); return 0; } Py_INCREF(s); #if PY_MAJOR_VERSION >= 3 PyUnicode_InternInPlace(&s); #else PyString_InternInPlace(&s); #endif return s; } //////////////////// abs_int.proto //////////////////// static CYTHON_INLINE unsigned int __Pyx_abs_int(int x) { if (unlikely(x == -INT_MAX-1)) return ((unsigned int)INT_MAX) + 1U; return (unsigned int) abs(x); } //////////////////// abs_long.proto //////////////////// static CYTHON_INLINE unsigned long __Pyx_abs_long(long x) { if (unlikely(x == -LONG_MAX-1)) return ((unsigned long)LONG_MAX) + 1U; return (unsigned long) labs(x); } //////////////////// abs_longlong.proto //////////////////// static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_abs_longlong(PY_LONG_LONG x) { #ifndef PY_LLONG_MAX #ifdef LLONG_MAX const PY_LONG_LONG PY_LLONG_MAX = LLONG_MAX; #else // copied from pyport.h in CPython 3.3, missing in 2.4 const PY_LONG_LONG PY_LLONG_MAX = (1 + 2 * ((1LL << (CHAR_BIT * sizeof(PY_LONG_LONG) - 2)) - 1)); #endif #endif if (unlikely(x == -PY_LLONG_MAX-1)) return ((unsigned PY_LONG_LONG)PY_LLONG_MAX) + 1U; #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L return (unsigned PY_LONG_LONG) llabs(x); #else return (x<0) ? (unsigned PY_LONG_LONG)-x : (unsigned PY_LONG_LONG)x; #endif } //////////////////// pow2.proto //////////////////// #define __Pyx_PyNumber_Power2(a, b) PyNumber_Power(a, b, Py_None) //////////////////// py_dict_keys.proto //////////////////// static CYTHON_INLINE PyObject* __Pyx_PyDict_Keys(PyObject* d); /*proto*/ //////////////////// py_dict_keys //////////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx_PyDict_Keys(PyObject* d) { if (PY_MAJOR_VERSION >= 3) return __Pyx_PyObject_CallMethod1((PyObject*)&PyDict_Type, PYIDENT("keys"), d); else return PyDict_Keys(d); } //////////////////// py_dict_values.proto //////////////////// static CYTHON_INLINE PyObject* __Pyx_PyDict_Values(PyObject* d); /*proto*/ //////////////////// py_dict_values //////////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx_PyDict_Values(PyObject* d) { if (PY_MAJOR_VERSION >= 3) return __Pyx_PyObject_CallMethod1((PyObject*)&PyDict_Type, PYIDENT("values"), d); else return PyDict_Values(d); } //////////////////// py_dict_items.proto //////////////////// static CYTHON_INLINE PyObject* __Pyx_PyDict_Items(PyObject* d); /*proto*/ //////////////////// py_dict_items //////////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx_PyDict_Items(PyObject* d) { if (PY_MAJOR_VERSION >= 3) return __Pyx_PyObject_CallMethod1((PyObject*)&PyDict_Type, PYIDENT("items"), d); else return PyDict_Items(d); } //////////////////// py_dict_iterkeys.proto //////////////////// static CYTHON_INLINE PyObject* __Pyx_PyDict_IterKeys(PyObject* d); /*proto*/ //////////////////// py_dict_iterkeys //////////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx_PyDict_IterKeys(PyObject* d) { return __Pyx_PyObject_CallMethod0(d, (PY_MAJOR_VERSION >= 3) ? PYIDENT("keys") : PYIDENT("iterkeys")); } //////////////////// py_dict_itervalues.proto //////////////////// static CYTHON_INLINE PyObject* __Pyx_PyDict_IterValues(PyObject* d); /*proto*/ //////////////////// py_dict_itervalues //////////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx_PyDict_IterValues(PyObject* d) { return __Pyx_PyObject_CallMethod0(d, (PY_MAJOR_VERSION >= 3) ? PYIDENT("values") : PYIDENT("itervalues")); } //////////////////// py_dict_iteritems.proto //////////////////// static CYTHON_INLINE PyObject* __Pyx_PyDict_IterItems(PyObject* d); /*proto*/ //////////////////// py_dict_iteritems //////////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx_PyDict_IterItems(PyObject* d) { return __Pyx_PyObject_CallMethod0(d, (PY_MAJOR_VERSION >= 3) ? PYIDENT("items") : PYIDENT("iteritems")); } //////////////////// py_dict_viewkeys.proto //////////////////// #if PY_VERSION_HEX < 0x02070000 #error This module uses dict views, which require Python 2.7 or later #endif static CYTHON_INLINE PyObject* __Pyx_PyDict_ViewKeys(PyObject* d); /*proto*/ //////////////////// py_dict_viewkeys //////////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx_PyDict_ViewKeys(PyObject* d) { return __Pyx_PyObject_CallMethod0(d, (PY_MAJOR_VERSION >= 3) ? PYIDENT("keys") : PYIDENT("viewkeys")); } //////////////////// py_dict_viewvalues.proto //////////////////// #if PY_VERSION_HEX < 0x02070000 #error This module uses dict views, which require Python 2.7 or later #endif static CYTHON_INLINE PyObject* __Pyx_PyDict_ViewValues(PyObject* d); /*proto*/ //////////////////// py_dict_viewvalues //////////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx_PyDict_ViewValues(PyObject* d) { return __Pyx_PyObject_CallMethod0(d, (PY_MAJOR_VERSION >= 3) ? PYIDENT("values") : PYIDENT("viewvalues")); } //////////////////// py_dict_viewitems.proto //////////////////// #if PY_VERSION_HEX < 0x02070000 #error This module uses dict views, which require Python 2.7 or later #endif static CYTHON_INLINE PyObject* __Pyx_PyDict_ViewItems(PyObject* d); /*proto*/ //////////////////// py_dict_viewitems //////////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx_PyDict_ViewItems(PyObject* d) { return __Pyx_PyObject_CallMethod0(d, (PY_MAJOR_VERSION >= 3) ? PYIDENT("items") : PYIDENT("viewitems")); } //////////////////// pyset_compat.proto //////////////////// #if PY_VERSION_HEX < 0x02050000 #ifndef PyAnySet_CheckExact #define PyAnySet_CheckExact(ob) \ ((ob)->ob_type == &PySet_Type || \ (ob)->ob_type == &PyFrozenSet_Type) #define PySet_New(iterable) \ PyObject_CallFunctionObjArgs((PyObject *)&PySet_Type, (iterable), NULL) #define PyFrozenSet_New(iterable) \ PyObject_CallFunctionObjArgs((PyObject *)&PyFrozenSet_Type, (iterable), NULL) #define PySet_Size(anyset) \ PyObject_Size((anyset)) #define PySet_GET_SIZE(anyset) \ PyObject_Size((anyset)) #define PySet_Contains(anyset, key) \ PySequence_Contains((anyset), (key)) #define PySet_Pop(set) \ PyObject_CallMethod((set), (char*)"pop", NULL) static CYTHON_INLINE int PySet_Clear(PyObject *set) { PyObject *ret = PyObject_CallMethod(set, (char*)"clear", NULL); if (!ret) return -1; Py_DECREF(ret); return 0; } static CYTHON_INLINE int PySet_Discard(PyObject *set, PyObject *key) { PyObject *ret = PyObject_CallMethod(set, (char*)"discard", (char*)"(O)", key); if (!ret) return -1; Py_DECREF(ret); return 0; } static CYTHON_INLINE int PySet_Add(PyObject *set, PyObject *key) { PyObject *ret = PyObject_CallMethod(set, (char*)"add", (char*)"(O)", key); if (!ret) return -1; Py_DECREF(ret); return 0; } #endif /* PyAnySet_CheckExact (<= Py2.4) */ #endif /* < Py2.5 */ //////////////////// pyfrozenset_new.proto //////////////////// //@substitute: naming //@requires: pyset_compat static CYTHON_INLINE PyObject* __Pyx_PyFrozenSet_New(PyObject* it) { if (it) { PyObject* result; if (PyFrozenSet_CheckExact(it)) { Py_INCREF(it); return it; } result = PyFrozenSet_New(it); if (unlikely(!result)) return NULL; if (likely(PySet_GET_SIZE(result))) return result; // empty frozenset is a singleton // seems wasteful, but CPython does the same Py_DECREF(result); } #if CYTHON_COMPILING_IN_CPYTHON return PyFrozenSet_Type.tp_new(&PyFrozenSet_Type, $empty_tuple, NULL); #else return PyObject_Call((PyObject*)&PyFrozenSet_Type, $empty_tuple, NULL); #endif } cython-0.20.1+git90-g0e6e38e/Cython/Utility/Capsule.c000066400000000000000000000010561231323242300217160ustar00rootroot00000000000000//////////////// Capsule.proto //////////////// /* Todo: wrap the rest of the functionality in similar functions */ static CYTHON_INLINE PyObject *__pyx_capsule_create(void *p, const char *sig); //////////////// Capsule //////////////// static CYTHON_INLINE PyObject * __pyx_capsule_create(void *p, CYTHON_UNUSED const char *sig) { PyObject *cobj; #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 0) cobj = PyCapsule_New(p, sig, NULL); #else cobj = PyCObject_FromVoidPtr(p, NULL); #endif return cobj; } cython-0.20.1+git90-g0e6e38e/Cython/Utility/CommonTypes.c000066400000000000000000000027741231323242300226070ustar00rootroot00000000000000/////////////// FetchCommonType.proto /////////////// static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); /////////////// FetchCommonType /////////////// static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { PyObject* fake_module; PyTypeObject* cached_type = NULL; fake_module = PyImport_AddModule((char*) "_cython_" CYTHON_ABI); if (!fake_module) return NULL; Py_INCREF(fake_module); cached_type = (PyTypeObject*) PyObject_GetAttrString(fake_module, type->tp_name); if (cached_type) { if (!PyType_Check((PyObject*)cached_type)) { PyErr_Format(PyExc_TypeError, "Shared Cython type %.200s is not a type object", type->tp_name); goto bad; } if (cached_type->tp_basicsize != type->tp_basicsize) { PyErr_Format(PyExc_TypeError, "Shared Cython type %.200s has the wrong size, try recompiling", type->tp_name); goto bad; } } else { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; PyErr_Clear(); if (PyType_Ready(type) < 0) goto bad; if (PyObject_SetAttrString(fake_module, type->tp_name, (PyObject*) type) < 0) goto bad; Py_INCREF(type); cached_type = type; } done: Py_DECREF(fake_module); // NOTE: always returns owned reference, or NULL on error return cached_type; bad: Py_XDECREF(cached_type); cached_type = NULL; goto done; } cython-0.20.1+git90-g0e6e38e/Cython/Utility/CppConvert.pyx000066400000000000000000000133171231323242300230060ustar00rootroot00000000000000# TODO: Figure out how many of the pass-by-value copies the compiler can eliminate. #################### string.from_py #################### cdef extern from *: cdef cppclass string "std::string": string() string(char* c_str, size_t size) cdef char* __Pyx_PyObject_AsStringAndSize(object, Py_ssize_t*) except NULL @cname("{{cname}}") cdef string {{cname}}(object o) except *: cdef Py_ssize_t length cdef char* data = __Pyx_PyObject_AsStringAndSize(o, &length) return string(data, length) #################### string.to_py #################### #cimport cython #from libcpp.string cimport string cdef extern from *: cdef cppclass string "const std::string": char* data() size_t size() cdef object __Pyx_PyObject_FromStringAndSize(char*, size_t) @cname("{{cname}}") cdef object {{cname}}(string& s): return __Pyx_PyObject_FromStringAndSize(s.data(), s.size()) #################### vector.from_py #################### {{template_type_declarations}} cdef extern from *: cdef cppclass vector "std::vector" [T]: void push_back(T&) @cname("{{cname}}") cdef vector[X] {{cname}}(object o) except *: cdef vector[X] v for item in o: v.push_back(X_from_py(item)) return v #################### vector.to_py #################### {{template_type_declarations}} cdef extern from *: cdef cppclass vector "const std::vector" [T]: size_t size() T& operator[](size_t) @cname("{{cname}}") cdef object {{cname}}(vector[X]& v): return [X_to_py(v[i]) for i in range(v.size())] #################### list.from_py #################### {{template_type_declarations}} cdef extern from *: cdef cppclass cpp_list "std::list" [T]: void push_back(T&) @cname("{{cname}}") cdef cpp_list[X] {{cname}}(object o) except *: cdef cpp_list[X] l for item in o: l.push_back(X_from_py(item)) return l #################### list.to_py #################### cimport cython {{template_type_declarations}} cdef extern from *: cdef cppclass cpp_list "std::list" [T]: cppclass const_iterator: T& operator*() const_iterator operator++() bint operator!=(const_iterator) const_iterator begin() const_iterator end() cdef cppclass const_cpp_list "const std::list" [T] (cpp_list): pass @cname("{{cname}}") cdef object {{cname}}(const_cpp_list[X]& v): o = [] cdef cpp_list[X].const_iterator iter = v.begin() while iter != v.end(): o.append(X_to_py(cython.operator.dereference(iter))) cython.operator.preincrement(iter) return o #################### set.from_py #################### {{template_type_declarations}} cdef extern from *: cdef cppclass set "std::{{maybe_unordered}}set" [T]: void insert(T&) @cname("{{cname}}") cdef set[X] {{cname}}(object o) except *: cdef set[X] s for item in o: s.insert(X_from_py(item)) return s #################### set.to_py #################### cimport cython {{template_type_declarations}} cdef extern from *: cdef cppclass cpp_set "std::{{maybe_unordered}}set" [T]: cppclass const_iterator: T& operator*() const_iterator operator++() bint operator!=(const_iterator) const_iterator begin() const_iterator end() cdef cppclass const_cpp_set "const std::{{maybe_unordered}}set" [T](cpp_set): pass @cname("{{cname}}") cdef object {{cname}}(const_cpp_set[X]& s): o = set() cdef cpp_set[X].const_iterator iter = s.begin() while iter != s.end(): o.add(X_to_py(cython.operator.dereference(iter))) cython.operator.preincrement(iter) return o #################### pair.from_py #################### {{template_type_declarations}} cdef extern from *: cdef cppclass pair "std::pair" [T, U]: pair() pair(T&, U&) @cname("{{cname}}") cdef pair[X,Y] {{cname}}(object o) except *: x, y = o return pair[X,Y](X_from_py(x), Y_from_py(y)) #################### pair.to_py #################### {{template_type_declarations}} cdef extern from *: cdef cppclass pair "const std::pair" [T, U]: T first U second @cname("{{cname}}") cdef object {{cname}}(pair[X,Y]& p): return X_to_py(p.first), Y_to_py(p.second) #################### map.from_py #################### {{template_type_declarations}} cdef extern from *: cdef cppclass pair "std::pair" [T, U]: pair(T&, U&) cdef cppclass map "std::{{maybe_unordered}}map" [T, U]: void insert(pair[T, U]&) cdef cppclass pair "std::pair" [T, U]: pass cdef cppclass vector "std::vector" [T]: pass @cname("{{cname}}") cdef map[X,Y] {{cname}}(object o) except *: cdef dict d = o cdef map[X,Y] m for key, value in d.iteritems(): m.insert(pair[X,Y](X_from_py(key), Y_from_py(value))) return m #################### map.to_py #################### # TODO: Work out const so that this can take a const # reference rather than pass by value. cimport cython {{template_type_declarations}} cdef extern from *: cdef cppclass map "std::{{maybe_unordered}}map" [T, U]: cppclass value_type: T first U second cppclass iterator: value_type& operator*() iterator operator++() bint operator!=(iterator) iterator begin() iterator end() @cname("{{cname}}") cdef object {{cname}}(map[X,Y] s): o = {} cdef map[X,Y].value_type *key_value cdef map[X,Y].iterator iter = s.begin() while iter != s.end(): key_value = &cython.operator.dereference(iter) o[X_to_py(key_value.first)] = Y_to_py(key_value.second) cython.operator.preincrement(iter) return o cython-0.20.1+git90-g0e6e38e/Cython/Utility/CppSupport.cpp000066400000000000000000000031771231323242300230070ustar00rootroot00000000000000/////////////// CppExceptionConversion.proto /////////////// #ifndef __Pyx_CppExn2PyErr #include #include #include #include static void __Pyx_CppExn2PyErr() { // Catch a handful of different errors here and turn them into the // equivalent Python errors. try { if (PyErr_Occurred()) ; // let the latest Python exn pass through and ignore the current one else throw; } catch (const std::bad_alloc& exn) { PyErr_SetString(PyExc_MemoryError, exn.what()); } catch (const std::bad_cast& exn) { PyErr_SetString(PyExc_TypeError, exn.what()); } catch (const std::domain_error& exn) { PyErr_SetString(PyExc_ValueError, exn.what()); } catch (const std::invalid_argument& exn) { PyErr_SetString(PyExc_ValueError, exn.what()); } catch (const std::ios_base::failure& exn) { // Unfortunately, in standard C++ we have no way of distinguishing EOF // from other errors here; be careful with the exception mask PyErr_SetString(PyExc_IOError, exn.what()); } catch (const std::out_of_range& exn) { // Change out_of_range to IndexError PyErr_SetString(PyExc_IndexError, exn.what()); } catch (const std::overflow_error& exn) { PyErr_SetString(PyExc_OverflowError, exn.what()); } catch (const std::range_error& exn) { PyErr_SetString(PyExc_ArithmeticError, exn.what()); } catch (const std::underflow_error& exn) { PyErr_SetString(PyExc_ArithmeticError, exn.what()); } catch (const std::exception& exn) { PyErr_SetString(PyExc_RuntimeError, exn.what()); } catch (...) { PyErr_SetString(PyExc_RuntimeError, "Unknown exception"); } } #endif cython-0.20.1+git90-g0e6e38e/Cython/Utility/CythonFunction.c000066400000000000000000001151661231323242300233040ustar00rootroot00000000000000 //////////////////// CythonFunction.proto //////////////////// #define __Pyx_CyFunction_USED 1 #include #define __Pyx_CYFUNCTION_STATICMETHOD 0x01 #define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 #define __Pyx_CYFUNCTION_CCLASS 0x04 #define __Pyx_CyFunction_GetClosure(f) \ (((__pyx_CyFunctionObject *) (f))->func_closure) #define __Pyx_CyFunction_GetClassObj(f) \ (((__pyx_CyFunctionObject *) (f))->func_classobj) #define __Pyx_CyFunction_Defaults(type, f) \ ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) #define __Pyx_CyFunction_SetDefaultsGetter(f, g) \ ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) typedef struct { PyCFunctionObject func; PyObject *func_dict; PyObject *func_weakreflist; PyObject *func_name; PyObject *func_qualname; PyObject *func_doc; PyObject *func_globals; PyObject *func_code; PyObject *func_closure; PyObject *func_classobj; /* No-args super() class cell */ /* Dynamic default args and annotations */ void *defaults; int defaults_pyobjects; int flags; /* Defaults info */ PyObject *defaults_tuple; /* Const defaults tuple */ PyObject *defaults_kwdict; /* Const kwonly defaults dict */ PyObject *(*defaults_getter)(PyObject *); PyObject *func_annotations; /* function annotations dict */ } __pyx_CyFunctionObject; static PyTypeObject *__pyx_CyFunctionType = 0; #define __Pyx_CyFunction_NewEx(ml, flags, qualname, self, module, globals, code) \ __Pyx_CyFunction_New(__pyx_CyFunctionType, ml, flags, qualname, self, module, globals, code) static PyObject *__Pyx_CyFunction_New(PyTypeObject *, PyMethodDef *ml, int flags, PyObject* qualname, PyObject *self, PyObject *module, PyObject *globals, PyObject* code); static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, size_t size, int pyobjects); static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, PyObject *tuple); static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, PyObject *dict); static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, PyObject *dict); static int __Pyx_CyFunction_init(void); //////////////////// CythonFunction //////////////////// //@substitute: naming //@requires: CommonTypes.c::FetchCommonType ////@requires: ObjectHandling.c::PyObjectGetAttrStr static PyObject * __Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *closure) { if (unlikely(op->func_doc == NULL)) { if (op->func.m_ml->ml_doc) { #if PY_MAJOR_VERSION >= 3 op->func_doc = PyUnicode_FromString(op->func.m_ml->ml_doc); #else op->func_doc = PyString_FromString(op->func.m_ml->ml_doc); #endif if (unlikely(op->func_doc == NULL)) return NULL; } else { Py_INCREF(Py_None); return Py_None; } } Py_INCREF(op->func_doc); return op->func_doc; } static int __Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value) { PyObject *tmp = op->func_doc; if (value == NULL) value = Py_None; /* Mark as deleted */ Py_INCREF(value); op->func_doc = value; Py_XDECREF(tmp); return 0; } static PyObject * __Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op) { if (unlikely(op->func_name == NULL)) { #if PY_MAJOR_VERSION >= 3 op->func_name = PyUnicode_InternFromString(op->func.m_ml->ml_name); #else op->func_name = PyString_InternFromString(op->func.m_ml->ml_name); #endif if (unlikely(op->func_name == NULL)) return NULL; } Py_INCREF(op->func_name); return op->func_name; } static int __Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value) { PyObject *tmp; #if PY_MAJOR_VERSION >= 3 if (unlikely(value == NULL || !PyUnicode_Check(value))) { #else if (unlikely(value == NULL || !PyString_Check(value))) { #endif PyErr_SetString(PyExc_TypeError, "__name__ must be set to a string object"); return -1; } tmp = op->func_name; Py_INCREF(value); op->func_name = value; Py_XDECREF(tmp); return 0; } static PyObject * __Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op) { Py_INCREF(op->func_qualname); return op->func_qualname; } static int __Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value) { PyObject *tmp; #if PY_MAJOR_VERSION >= 3 if (unlikely(value == NULL || !PyUnicode_Check(value))) { #else if (unlikely(value == NULL || !PyString_Check(value))) { #endif PyErr_SetString(PyExc_TypeError, "__qualname__ must be set to a string object"); return -1; } tmp = op->func_qualname; Py_INCREF(value); op->func_qualname = value; Py_XDECREF(tmp); return 0; } static PyObject * __Pyx_CyFunction_get_self(__pyx_CyFunctionObject *m, CYTHON_UNUSED void *closure) { PyObject *self; self = m->func_closure; if (self == NULL) self = Py_None; Py_INCREF(self); return self; } static PyObject * __Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op) { if (unlikely(op->func_dict == NULL)) { op->func_dict = PyDict_New(); if (unlikely(op->func_dict == NULL)) return NULL; } Py_INCREF(op->func_dict); return op->func_dict; } static int __Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value) { PyObject *tmp; if (unlikely(value == NULL)) { PyErr_SetString(PyExc_TypeError, "function's dictionary may not be deleted"); return -1; } if (unlikely(!PyDict_Check(value))) { PyErr_SetString(PyExc_TypeError, "setting function's dictionary to a non-dict"); return -1; } tmp = op->func_dict; Py_INCREF(value); op->func_dict = value; Py_XDECREF(tmp); return 0; } static PyObject * __Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op) { Py_INCREF(op->func_globals); return op->func_globals; } static PyObject * __Pyx_CyFunction_get_closure(CYTHON_UNUSED __pyx_CyFunctionObject *op) { Py_INCREF(Py_None); return Py_None; } static PyObject * __Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op) { PyObject* result = (op->func_code) ? op->func_code : Py_None; Py_INCREF(result); return result; } static int __Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { PyObject *res = op->defaults_getter((PyObject *) op); if (unlikely(!res)) return -1; /* Cache result */ op->defaults_tuple = PyTuple_GET_ITEM(res, 0); Py_INCREF(op->defaults_tuple); op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); Py_INCREF(op->defaults_kwdict); Py_DECREF(res); return 0; } static int __Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value) { PyObject* tmp; if (!value) { // del => explicit None to prevent rebuilding value = Py_None; } else if (value != Py_None && !PyTuple_Check(value)) { PyErr_SetString(PyExc_TypeError, "__defaults__ must be set to a tuple object"); return -1; } Py_INCREF(value); tmp = op->defaults_tuple; op->defaults_tuple = value; Py_XDECREF(tmp); return 0; } static PyObject * __Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op) { PyObject* result = op->defaults_tuple; if (unlikely(!result)) { if (op->defaults_getter) { if (__Pyx_CyFunction_init_defaults(op) < 0) return NULL; result = op->defaults_tuple; } else { result = Py_None; } } Py_INCREF(result); return result; } static int __Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value) { PyObject* tmp; if (!value) { // del => explicit None to prevent rebuilding value = Py_None; } else if (value != Py_None && !PyDict_Check(value)) { PyErr_SetString(PyExc_TypeError, "__kwdefaults__ must be set to a dict object"); return -1; } Py_INCREF(value); tmp = op->defaults_kwdict; op->defaults_kwdict = value; Py_XDECREF(tmp); return 0; } static PyObject * __Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op) { PyObject* result = op->defaults_kwdict; if (unlikely(!result)) { if (op->defaults_getter) { if (__Pyx_CyFunction_init_defaults(op) < 0) return NULL; result = op->defaults_kwdict; } else { result = Py_None; } } Py_INCREF(result); return result; } static int __Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value) { PyObject* tmp; if (!value || value == Py_None) { value = NULL; } else if (!PyDict_Check(value)) { PyErr_SetString(PyExc_TypeError, "__annotations__ must be set to a dict object"); return -1; } Py_XINCREF(value); tmp = op->func_annotations; op->func_annotations = value; Py_XDECREF(tmp); return 0; } static PyObject * __Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op) { PyObject* result = op->func_annotations; if (unlikely(!result)) { result = PyDict_New(); if (unlikely(!result)) return NULL; op->func_annotations = result; } Py_INCREF(result); return result; } //#if PY_VERSION_HEX >= 0x030400C1 //static PyObject * //__Pyx_CyFunction_get_signature(__pyx_CyFunctionObject *op) { // PyObject *inspect_module, *signature_class, *signature; // // from inspect import Signature // inspect_module = PyImport_ImportModuleLevelObject(PYIDENT("inspect"), NULL, NULL, NULL, 0); // if (unlikely(!inspect_module)) // goto bad; // signature_class = __Pyx_PyObject_GetAttrStr(inspect_module, PYIDENT("Signature")); // Py_DECREF(inspect_module); // if (unlikely(!signature_class)) // goto bad; // // return Signature.from_function(op) // signature = PyObject_CallMethodObjArgs(signature_class, PYIDENT("from_function"), op, NULL); // Py_DECREF(signature_class); // if (likely(signature)) // return signature; //bad: // // make sure we raise an AttributeError from this property on any errors // if (!PyErr_ExceptionMatches(PyExc_AttributeError)) // PyErr_SetString(PyExc_AttributeError, "failed to calculate __signature__"); // return NULL; //} //#endif static PyGetSetDef __pyx_CyFunction_getsets[] = { {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, {(char *) "__self__", (getter)__Pyx_CyFunction_get_self, 0, 0, 0}, {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, //#if PY_VERSION_HEX >= 0x030400C1 // {(char *) "__signature__", (getter)__Pyx_CyFunction_get_signature, 0, 0, 0}, //#endif {0, 0, 0, 0, 0} }; #ifndef PY_WRITE_RESTRICTED /* < Py2.5 */ #define PY_WRITE_RESTRICTED WRITE_RESTRICTED #endif static PyMemberDef __pyx_CyFunction_members[] = { {(char *) "__module__", T_OBJECT, offsetof(__pyx_CyFunctionObject, func.m_module), PY_WRITE_RESTRICTED, 0}, {0, 0, 0, 0, 0} }; static PyObject * __Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, CYTHON_UNUSED PyObject *args) { #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromString(m->func.m_ml->ml_name); #else return PyString_FromString(m->func.m_ml->ml_name); #endif } static PyMethodDef __pyx_CyFunction_methods[] = { {__Pyx_NAMESTR("__reduce__"), (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, {0, 0, 0, 0} }; static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags, PyObject* qualname, PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { __pyx_CyFunctionObject *op = PyObject_GC_New(__pyx_CyFunctionObject, type); if (op == NULL) return NULL; op->flags = flags; op->func_weakreflist = NULL; op->func.m_ml = ml; op->func.m_self = (PyObject *) op; Py_XINCREF(closure); op->func_closure = closure; Py_XINCREF(module); op->func.m_module = module; op->func_dict = NULL; op->func_name = NULL; Py_INCREF(qualname); op->func_qualname = qualname; op->func_doc = NULL; op->func_classobj = NULL; op->func_globals = globals; Py_INCREF(op->func_globals); Py_XINCREF(code); op->func_code = code; /* Dynamic Default args */ op->defaults_pyobjects = 0; op->defaults = NULL; op->defaults_tuple = NULL; op->defaults_kwdict = NULL; op->defaults_getter = NULL; op->func_annotations = NULL; PyObject_GC_Track(op); return (PyObject *) op; } static int __Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) { Py_CLEAR(m->func_closure); Py_CLEAR(m->func.m_module); Py_CLEAR(m->func_dict); Py_CLEAR(m->func_name); Py_CLEAR(m->func_qualname); Py_CLEAR(m->func_doc); Py_CLEAR(m->func_globals); Py_CLEAR(m->func_code); Py_CLEAR(m->func_classobj); Py_CLEAR(m->defaults_tuple); Py_CLEAR(m->defaults_kwdict); Py_CLEAR(m->func_annotations); if (m->defaults) { PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); int i; for (i = 0; i < m->defaults_pyobjects; i++) Py_XDECREF(pydefaults[i]); PyMem_Free(m->defaults); m->defaults = NULL; } return 0; } static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) { PyObject_GC_UnTrack(m); if (m->func_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) m); __Pyx_CyFunction_clear(m); PyObject_GC_Del(m); } static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) { Py_VISIT(m->func_closure); Py_VISIT(m->func.m_module); Py_VISIT(m->func_dict); Py_VISIT(m->func_name); Py_VISIT(m->func_qualname); Py_VISIT(m->func_doc); Py_VISIT(m->func_globals); Py_VISIT(m->func_code); Py_VISIT(m->func_classobj); Py_VISIT(m->defaults_tuple); Py_VISIT(m->defaults_kwdict); if (m->defaults) { PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); int i; for (i = 0; i < m->defaults_pyobjects; i++) Py_VISIT(pydefaults[i]); } return 0; } static PyObject *__Pyx_CyFunction_descr_get(PyObject *func, PyObject *obj, PyObject *type) { __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; if (m->flags & __Pyx_CYFUNCTION_STATICMETHOD) { Py_INCREF(func); return func; } if (m->flags & __Pyx_CYFUNCTION_CLASSMETHOD) { if (type == NULL) type = (PyObject *)(Py_TYPE(obj)); return PyMethod_New(func, type, (PyObject *)(Py_TYPE(type))); } if (obj == Py_None) obj = NULL; return PyMethod_New(func, obj, type); } static PyObject* __Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) { #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromFormat("", op->func_qualname, (void *)op); #else return PyString_FromFormat("", PyString_AsString(op->func_qualname), (void *)op); #endif } #if CYTHON_COMPILING_IN_PYPY /* originally copied from PyCFunction_Call() in CPython's Objects/methodobject.c */ /* PyPy does not have this function */ static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { PyCFunctionObject* f = (PyCFunctionObject*)func; PyCFunction meth = PyCFunction_GET_FUNCTION(func); PyObject *self = PyCFunction_GET_SELF(func); Py_ssize_t size; switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) { case METH_VARARGS: if (likely(kw == NULL) || PyDict_Size(kw) == 0) return (*meth)(self, arg); break; case METH_VARARGS | METH_KEYWORDS: return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); case METH_NOARGS: if (likely(kw == NULL) || PyDict_Size(kw) == 0) { size = PyTuple_GET_SIZE(arg); if (size == 0) return (*meth)(self, NULL); PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", f->m_ml->ml_name, size); return NULL; } break; case METH_O: if (likely(kw == NULL) || PyDict_Size(kw) == 0) { size = PyTuple_GET_SIZE(arg); if (size == 1) return (*meth)(self, PyTuple_GET_ITEM(arg, 0)); PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", f->m_ml->ml_name, size); return NULL; } break; default: PyErr_SetString(PyExc_SystemError, "Bad call flags in " "__Pyx_CyFunction_Call. METH_OLDARGS is no " "longer supported!"); return NULL; } PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", f->m_ml->ml_name); return NULL; } #else static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { return PyCFunction_Call(func, arg, kw); } #endif static PyTypeObject __pyx_CyFunctionType_type = { PyVarObject_HEAD_INIT(0, 0) __Pyx_NAMESTR("cython_function_or_method"), /*tp_name*/ sizeof(__pyx_CyFunctionObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor) __Pyx_CyFunction_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ #if PY_MAJOR_VERSION < 3 0, /*tp_compare*/ #else 0, /*reserved*/ #endif (reprfunc) __Pyx_CyFunction_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ __Pyx_CyFunction_Call, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags*/ 0, /*tp_doc*/ (traverseproc) __Pyx_CyFunction_traverse, /*tp_traverse*/ (inquiry) __Pyx_CyFunction_clear, /*tp_clear*/ 0, /*tp_richcompare*/ offsetof(__pyx_CyFunctionObject, func_weakreflist), /* tp_weaklistoffse */ 0, /*tp_iter*/ 0, /*tp_iternext*/ __pyx_CyFunction_methods, /*tp_methods*/ __pyx_CyFunction_members, /*tp_members*/ __pyx_CyFunction_getsets, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ __Pyx_CyFunction_descr_get, /*tp_descr_get*/ 0, /*tp_descr_set*/ offsetof(__pyx_CyFunctionObject, func_dict),/*tp_dictoffset*/ 0, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ 0, /*tp_bases*/ 0, /*tp_mro*/ 0, /*tp_cache*/ 0, /*tp_subclasses*/ 0, /*tp_weaklist*/ 0, /*tp_del*/ #if PY_VERSION_HEX >= 0x02060000 0, /*tp_version_tag*/ #endif #if PY_VERSION_HEX >= 0x030400a1 0, /*tp_finalize*/ #endif }; static int __Pyx_CyFunction_init(void) { #if !CYTHON_COMPILING_IN_PYPY // avoid a useless level of call indirection __pyx_CyFunctionType_type.tp_call = PyCFunction_Call; #endif __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); if (__pyx_CyFunctionType == NULL) { return -1; } return 0; } static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; m->defaults = PyMem_Malloc(size); if (!m->defaults) return PyErr_NoMemory(); memset(m->defaults, 0, size); m->defaults_pyobjects = pyobjects; return m->defaults; } static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; m->defaults_tuple = tuple; Py_INCREF(tuple); } static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; m->defaults_kwdict = dict; Py_INCREF(dict); } static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; m->func_annotations = dict; Py_INCREF(dict); } //////////////////// CyFunctionClassCell.proto //////////////////// static CYTHON_INLINE void __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *classobj); //////////////////// CyFunctionClassCell //////////////////// //@requires: CythonFunction static CYTHON_INLINE void __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *classobj) { int i; for (i = 0; i < PyList_GET_SIZE(cyfunctions); i++) { __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) PyList_GET_ITEM(cyfunctions, i); m->func_classobj = classobj; Py_INCREF(classobj); } } //////////////////// FusedFunction.proto //////////////////// typedef struct { __pyx_CyFunctionObject func; PyObject *__signatures__; PyObject *type; PyObject *self; } __pyx_FusedFunctionObject; #define __pyx_FusedFunction_NewEx(ml, flags, qualname, self, module, globals, code) \ __pyx_FusedFunction_New(__pyx_FusedFunctionType, ml, flags, qualname, self, module, globals, code) static PyObject *__pyx_FusedFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags, PyObject *qualname, PyObject *self, PyObject *module, PyObject *globals, PyObject *code); static int __pyx_FusedFunction_clear(__pyx_FusedFunctionObject *self); static PyTypeObject *__pyx_FusedFunctionType = NULL; static int __pyx_FusedFunction_init(void); #define __Pyx_FusedFunction_USED //////////////////// FusedFunction //////////////////// //@requires: CythonFunction static PyObject * __pyx_FusedFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags, PyObject *qualname, PyObject *self, PyObject *module, PyObject *globals, PyObject *code) { __pyx_FusedFunctionObject *fusedfunc = (__pyx_FusedFunctionObject *) __Pyx_CyFunction_New(type, ml, flags, qualname, self, module, globals, code); if (!fusedfunc) return NULL; fusedfunc->__signatures__ = NULL; fusedfunc->type = NULL; fusedfunc->self = NULL; return (PyObject *) fusedfunc; } static void __pyx_FusedFunction_dealloc(__pyx_FusedFunctionObject *self) { __pyx_FusedFunction_clear(self); __pyx_FusedFunctionType->tp_free((PyObject *) self); } static int __pyx_FusedFunction_traverse(__pyx_FusedFunctionObject *self, visitproc visit, void *arg) { Py_VISIT(self->self); Py_VISIT(self->type); Py_VISIT(self->__signatures__); return __Pyx_CyFunction_traverse((__pyx_CyFunctionObject *) self, visit, arg); } static int __pyx_FusedFunction_clear(__pyx_FusedFunctionObject *self) { Py_CLEAR(self->self); Py_CLEAR(self->type); Py_CLEAR(self->__signatures__); return __Pyx_CyFunction_clear((__pyx_CyFunctionObject *) self); } static PyObject * __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type) { __pyx_FusedFunctionObject *func, *meth; func = (__pyx_FusedFunctionObject *) self; if (func->self || func->func.flags & __Pyx_CYFUNCTION_STATICMETHOD) { /* Do not allow rebinding and don't do anything for static methods */ Py_INCREF(self); return self; } if (obj == Py_None) obj = NULL; meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_NewEx( ((PyCFunctionObject *) func)->m_ml, ((__pyx_CyFunctionObject *) func)->flags, ((__pyx_CyFunctionObject *) func)->func_qualname, ((__pyx_CyFunctionObject *) func)->func_closure, ((PyCFunctionObject *) func)->m_module, ((__pyx_CyFunctionObject *) func)->func_globals, ((__pyx_CyFunctionObject *) func)->func_code); if (!meth) return NULL; Py_XINCREF(func->func.func_classobj); meth->func.func_classobj = func->func.func_classobj; Py_XINCREF(func->__signatures__); meth->__signatures__ = func->__signatures__; Py_XINCREF(type); meth->type = type; Py_XINCREF(func->func.defaults_tuple); meth->func.defaults_tuple = func->func.defaults_tuple; if (func->func.flags & __Pyx_CYFUNCTION_CLASSMETHOD) obj = type; Py_XINCREF(obj); meth->self = obj; return (PyObject *) meth; } static PyObject * _obj_to_str(PyObject *obj) { if (PyType_Check(obj)) return PyObject_GetAttr(obj, PYIDENT("__name__")); else return PyObject_Str(obj); } static PyObject * __pyx_FusedFunction_getitem(__pyx_FusedFunctionObject *self, PyObject *idx) { PyObject *signature = NULL; PyObject *unbound_result_func; PyObject *result_func = NULL; if (self->__signatures__ == NULL) { PyErr_SetString(PyExc_TypeError, "Function is not fused"); return NULL; } if (PyTuple_Check(idx)) { PyObject *list = PyList_New(0); Py_ssize_t n = PyTuple_GET_SIZE(idx); PyObject *string = NULL; PyObject *sep = NULL; int i; if (!list) return NULL; for (i = 0; i < n; i++) { PyObject *item = PyTuple_GET_ITEM(idx, i); string = _obj_to_str(item); if (!string || PyList_Append(list, string) < 0) goto __pyx_err; Py_DECREF(string); } sep = PyUnicode_FromString("|"); if (sep) signature = PyUnicode_Join(sep, list); __pyx_err: ; Py_DECREF(list); Py_XDECREF(sep); } else { signature = _obj_to_str(idx); } if (!signature) return NULL; unbound_result_func = PyObject_GetItem(self->__signatures__, signature); if (unbound_result_func) { if (self->self || self->type) { __pyx_FusedFunctionObject *unbound = (__pyx_FusedFunctionObject *) unbound_result_func; /* Todo: move this to InitClassCell */ Py_CLEAR(unbound->func.func_classobj); Py_XINCREF(self->func.func_classobj); unbound->func.func_classobj = self->func.func_classobj; result_func = __pyx_FusedFunction_descr_get(unbound_result_func, self->self, self->type); } else { result_func = unbound_result_func; Py_INCREF(result_func); } } Py_DECREF(signature); Py_XDECREF(unbound_result_func); return result_func; } static PyObject * __pyx_FusedFunction_callfunction(PyObject *func, PyObject *args, PyObject *kw) { __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; PyObject *result; int static_specialized = (cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD && !((__pyx_FusedFunctionObject *) func)->__signatures__); if (cyfunc->flags & __Pyx_CYFUNCTION_CCLASS && !static_specialized) { Py_ssize_t argc; PyObject *new_args; PyObject *self; PyObject *m_self; argc = PyTuple_GET_SIZE(args); new_args = PyTuple_GetSlice(args, 1, argc); if (!new_args) return NULL; self = PyTuple_GetItem(args, 0); if (!self) return NULL; m_self = cyfunc->func.m_self; cyfunc->func.m_self = self; result = __Pyx_CyFunction_Call(func, new_args, kw); cyfunc->func.m_self = m_self; Py_DECREF(new_args); } else { result = __Pyx_CyFunction_Call(func, args, kw); } return result; } /* Note: the 'self' from method binding is passed in in the args tuple, whereas PyCFunctionObject's m_self is passed in as the first argument to the C function. For extension methods we need to pass 'self' as 'm_self' and not as the first element of the args tuple. */ static PyObject * __pyx_FusedFunction_call(PyObject *func, PyObject *args, PyObject *kw) { __pyx_FusedFunctionObject *binding_func = (__pyx_FusedFunctionObject *) func; Py_ssize_t argc = PyTuple_GET_SIZE(args); PyObject *new_args = NULL; __pyx_FusedFunctionObject *new_func = NULL; PyObject *result = NULL; PyObject *self = NULL; int is_staticmethod = binding_func->func.flags & __Pyx_CYFUNCTION_STATICMETHOD; int is_classmethod = binding_func->func.flags & __Pyx_CYFUNCTION_CLASSMETHOD; if (binding_func->self) { /* Bound method call, put 'self' in the args tuple */ Py_ssize_t i; new_args = PyTuple_New(argc + 1); if (!new_args) return NULL; self = binding_func->self; Py_INCREF(self); PyTuple_SET_ITEM(new_args, 0, self); for (i = 0; i < argc; i++) { PyObject *item = PyTuple_GET_ITEM(args, i); Py_INCREF(item); PyTuple_SET_ITEM(new_args, i + 1, item); } args = new_args; } else if (binding_func->type) { /* Unbound method call */ if (argc < 1) { PyErr_SetString(PyExc_TypeError, "Need at least one argument, 0 given."); return NULL; } self = PyTuple_GET_ITEM(args, 0); } if (self && !is_classmethod && !is_staticmethod && !PyObject_IsInstance(self, binding_func->type)) { PyErr_Format(PyExc_TypeError, "First argument should be of type %.200s, got %.200s.", ((PyTypeObject *) binding_func->type)->tp_name, self->ob_type->tp_name); goto __pyx_err; } if (binding_func->__signatures__) { PyObject *tup = PyTuple_Pack(4, binding_func->__signatures__, args, kw == NULL ? Py_None : kw, binding_func->func.defaults_tuple); if (!tup) goto __pyx_err; new_func = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_callfunction(func, tup, NULL); Py_DECREF(tup); if (!new_func) goto __pyx_err; Py_XINCREF(binding_func->func.func_classobj); Py_CLEAR(new_func->func.func_classobj); new_func->func.func_classobj = binding_func->func.func_classobj; func = (PyObject *) new_func; } result = __pyx_FusedFunction_callfunction(func, args, kw); __pyx_err: Py_XDECREF(new_args); Py_XDECREF((PyObject *) new_func); return result; } static PyMemberDef __pyx_FusedFunction_members[] = { {(char *) "__signatures__", T_OBJECT, offsetof(__pyx_FusedFunctionObject, __signatures__), READONLY, __Pyx_DOCSTR(0)}, {0, 0, 0, 0, 0}, }; static PyMappingMethods __pyx_FusedFunction_mapping_methods = { 0, (binaryfunc) __pyx_FusedFunction_getitem, 0, }; static PyTypeObject __pyx_FusedFunctionType_type = { PyVarObject_HEAD_INIT(0, 0) __Pyx_NAMESTR("fused_cython_function"), /*tp_name*/ sizeof(__pyx_FusedFunctionObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor) __pyx_FusedFunction_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ #if PY_MAJOR_VERSION < 3 0, /*tp_compare*/ #else 0, /*reserved*/ #endif 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ &__pyx_FusedFunction_mapping_methods, /*tp_as_mapping*/ 0, /*tp_hash*/ (ternaryfunc) __pyx_FusedFunction_call, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags*/ 0, /*tp_doc*/ (traverseproc) __pyx_FusedFunction_traverse, /*tp_traverse*/ (inquiry) __pyx_FusedFunction_clear,/*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ __pyx_FusedFunction_members, /*tp_members*/ /* __doc__ is None for the fused function type, but we need it to be */ /* a descriptor for the instance's __doc__, so rebuild descriptors in our subclass */ __pyx_CyFunction_getsets, /*tp_getset*/ &__pyx_CyFunctionType_type, /*tp_base*/ 0, /*tp_dict*/ __pyx_FusedFunction_descr_get, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ 0, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ 0, /*tp_bases*/ 0, /*tp_mro*/ 0, /*tp_cache*/ 0, /*tp_subclasses*/ 0, /*tp_weaklist*/ 0, /*tp_del*/ #if PY_VERSION_HEX >= 0x02060000 0, /*tp_version_tag*/ #endif #if PY_VERSION_HEX >= 0x030400a1 0, /*tp_finalize*/ #endif }; static int __pyx_FusedFunction_init(void) { __pyx_FusedFunctionType = __Pyx_FetchCommonType(&__pyx_FusedFunctionType_type); if (__pyx_FusedFunctionType == NULL) { return -1; } return 0; } //////////////////// ClassMethod.proto //////////////////// #include "descrobject.h" static PyObject* __Pyx_Method_ClassMethod(PyObject *method); /*proto*/ //////////////////// ClassMethod //////////////////// static PyObject* __Pyx_Method_ClassMethod(PyObject *method) { #if CYTHON_COMPILING_IN_PYPY if (PyObject_TypeCheck(method, &PyWrapperDescr_Type)) { /* cdef classes */ return PyClassMethod_New(method); } #else /* It appears that PyMethodDescr_Type is not anywhere exposed in the Python/C API */ static PyTypeObject *methoddescr_type = NULL; if (methoddescr_type == NULL) { PyObject *meth = __Pyx_GetAttrString((PyObject*)&PyList_Type, "append"); if (!meth) return NULL; methoddescr_type = Py_TYPE(meth); Py_DECREF(meth); } if (PyObject_TypeCheck(method, methoddescr_type)) { /* cdef classes */ PyMethodDescrObject *descr = (PyMethodDescrObject *)method; #if PY_VERSION_HEX < 0x03020000 PyTypeObject *d_type = descr->d_type; #else PyTypeObject *d_type = descr->d_common.d_type; #endif return PyDescr_NewClassMethod(d_type, descr->d_method); } #endif else if (PyMethod_Check(method)) { /* python classes */ return PyClassMethod_New(PyMethod_GET_FUNCTION(method)); } else if (PyCFunction_Check(method)) { return PyClassMethod_New(method); } #ifdef __Pyx_CyFunction_USED else if (PyObject_TypeCheck(method, __pyx_CyFunctionType)) { return PyClassMethod_New(method); } #endif PyErr_SetString(PyExc_TypeError, "Class-level classmethod() can only be called on " "a method_descriptor or instance method."); return NULL; } cython-0.20.1+git90-g0e6e38e/Cython/Utility/Embed.c000066400000000000000000000132641231323242300213420ustar00rootroot00000000000000//////////////////// MainFunction //////////////////// #ifdef __FreeBSD__ #include #endif #if PY_MAJOR_VERSION < 3 int %(main_method)s(int argc, char** argv) { #elif defined(WIN32) || defined(MS_WINDOWS) int %(wmain_method)s(int argc, wchar_t **argv) { #else static int __Pyx_main(int argc, wchar_t **argv) { #endif /* 754 requires that FP exceptions run in "no stop" mode by default, * and until C vendors implement C99's ways to control FP exceptions, * Python requires non-stop mode. Alas, some platforms enable FP * exceptions by default. Here we disable them. */ #ifdef __FreeBSD__ fp_except_t m; m = fpgetmask(); fpsetmask(m & ~FP_X_OFL); #endif if (argc && argv) Py_SetProgramName(argv[0]); Py_Initialize(); if (argc && argv) PySys_SetArgv(argc, argv); { /* init module '%(module_name)s' as '__main__' */ PyObject* m = NULL; %(module_is_main)s = 1; #if PY_MAJOR_VERSION < 3 init%(module_name)s(); #else m = PyInit_%(module_name)s(); #endif if (PyErr_Occurred()) { PyErr_Print(); /* This exits with the right code if SystemExit. */ #if PY_MAJOR_VERSION < 3 if (Py_FlushLine()) PyErr_Clear(); #endif return 1; } Py_XDECREF(m); } Py_Finalize(); return 0; } #if PY_MAJOR_VERSION >= 3 && !defined(WIN32) && !defined(MS_WINDOWS) #include static wchar_t* __Pyx_char2wchar(char* arg) { wchar_t *res; #ifdef HAVE_BROKEN_MBSTOWCS /* Some platforms have a broken implementation of * mbstowcs which does not count the characters that * would result from conversion. Use an upper bound. */ size_t argsize = strlen(arg); #else size_t argsize = mbstowcs(NULL, arg, 0); #endif size_t count; unsigned char *in; wchar_t *out; #ifdef HAVE_MBRTOWC mbstate_t mbs; #endif if (argsize != (size_t)-1) { res = (wchar_t *)malloc((argsize+1)*sizeof(wchar_t)); if (!res) goto oom; count = mbstowcs(res, arg, argsize+1); if (count != (size_t)-1) { wchar_t *tmp; /* Only use the result if it contains no surrogate characters. */ for (tmp = res; *tmp != 0 && (*tmp < 0xd800 || *tmp > 0xdfff); tmp++) ; if (*tmp == 0) return res; } free(res); } /* Conversion failed. Fall back to escaping with surrogateescape. */ #ifdef HAVE_MBRTOWC /* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */ /* Overallocate; as multi-byte characters are in the argument, the actual output could use less memory. */ argsize = strlen(arg) + 1; res = malloc(argsize*sizeof(wchar_t)); if (!res) goto oom; in = (unsigned char*)arg; out = res; memset(&mbs, 0, sizeof mbs); while (argsize) { size_t converted = mbrtowc(out, (char*)in, argsize, &mbs); if (converted == 0) /* Reached end of string; null char stored. */ break; if (converted == (size_t)-2) { /* Incomplete character. This should never happen, since we provide everything that we have - unless there is a bug in the C library, or I misunderstood how mbrtowc works. */ fprintf(stderr, "unexpected mbrtowc result -2\\n"); return NULL; } if (converted == (size_t)-1) { /* Conversion error. Escape as UTF-8b, and start over in the initial shift state. */ *out++ = 0xdc00 + *in++; argsize--; memset(&mbs, 0, sizeof mbs); continue; } if (*out >= 0xd800 && *out <= 0xdfff) { /* Surrogate character. Escape the original byte sequence with surrogateescape. */ argsize -= converted; while (converted--) *out++ = 0xdc00 + *in++; continue; } /* successfully converted some bytes */ in += converted; argsize -= converted; out++; } #else /* Cannot use C locale for escaping; manually escape as if charset is ASCII (i.e. escape all bytes > 128. This will still roundtrip correctly in the locale's charset, which must be an ASCII superset. */ res = malloc((strlen(arg)+1)*sizeof(wchar_t)); if (!res) goto oom; in = (unsigned char*)arg; out = res; while(*in) if(*in < 128) *out++ = *in++; else *out++ = 0xdc00 + *in++; *out = 0; #endif return res; oom: fprintf(stderr, "out of memory\\n"); return NULL; } int %(main_method)s(int argc, char **argv) { if (!argc) { return __Pyx_main(0, NULL); } else { wchar_t **argv_copy = (wchar_t **)malloc(sizeof(wchar_t*)*argc); /* We need a second copies, as Python might modify the first one. */ wchar_t **argv_copy2 = (wchar_t **)malloc(sizeof(wchar_t*)*argc); int i, res; char *oldloc; if (!argv_copy || !argv_copy2) { fprintf(stderr, "out of memory\\n"); return 1; } oldloc = strdup(setlocale(LC_ALL, NULL)); setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { argv_copy2[i] = argv_copy[i] = __Pyx_char2wchar(argv[i]); if (!argv_copy[i]) return 1; } setlocale(LC_ALL, oldloc); free(oldloc); res = __Pyx_main(argc, argv_copy); for (i = 0; i < argc; i++) { free(argv_copy2[i]); } free(argv_copy); free(argv_copy2); return res; } } #endif cython-0.20.1+git90-g0e6e38e/Cython/Utility/Exceptions.c000066400000000000000000000416321231323242300224470ustar00rootroot00000000000000// Exception raising code // // Exceptions are raised by __Pyx_Raise() and stored as plain // type/value/tb in PyThreadState->curexc_*. When being caught by an // 'except' statement, curexc_* is moved over to exc_* by // __Pyx_GetException() /////////////// PyErrFetchRestore.proto /////////////// static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ /////////////// PyErrFetchRestore /////////////// static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) { #if CYTHON_COMPILING_IN_CPYTHON PyObject *tmp_type, *tmp_value, *tmp_tb; PyThreadState *tstate = PyThreadState_GET(); tmp_type = tstate->curexc_type; tmp_value = tstate->curexc_value; tmp_tb = tstate->curexc_traceback; tstate->curexc_type = type; tstate->curexc_value = value; tstate->curexc_traceback = tb; Py_XDECREF(tmp_type); Py_XDECREF(tmp_value); Py_XDECREF(tmp_tb); #else PyErr_Restore(type, value, tb); #endif } static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) { #if CYTHON_COMPILING_IN_CPYTHON PyThreadState *tstate = PyThreadState_GET(); *type = tstate->curexc_type; *value = tstate->curexc_value; *tb = tstate->curexc_traceback; tstate->curexc_type = 0; tstate->curexc_value = 0; tstate->curexc_traceback = 0; #else PyErr_Fetch(type, value, tb); #endif } /////////////// RaiseException.proto /////////////// static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); /*proto*/ /////////////// RaiseException /////////////// //@requires: PyErrFetchRestore // The following function is based on do_raise() from ceval.c. There // are separate versions for Python2 and Python3 as exception handling // has changed quite a lot between the two versions. #if PY_MAJOR_VERSION < 3 static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, CYTHON_UNUSED PyObject *cause) { /* 'cause' is only used in Py3 */ Py_XINCREF(type); if (!value || value == Py_None) value = NULL; else Py_INCREF(value); if (!tb || tb == Py_None) tb = NULL; else { Py_INCREF(tb); if (!PyTraceBack_Check(tb)) { PyErr_SetString(PyExc_TypeError, "raise: arg 3 must be a traceback or None"); goto raise_error; } } #if PY_VERSION_HEX < 0x02050000 if (PyClass_Check(type)) { #else if (PyType_Check(type)) { #endif /* instantiate the type now (we don't know when and how it will be caught) */ #if CYTHON_COMPILING_IN_PYPY /* PyPy can't handle value == NULL */ if (!value) { Py_INCREF(Py_None); value = Py_None; } #endif PyErr_NormalizeException(&type, &value, &tb); } else { /* Raising an instance. The value should be a dummy. */ if (value) { PyErr_SetString(PyExc_TypeError, "instance exception may not have a separate value"); goto raise_error; } /* Normalize to raise , */ value = type; #if PY_VERSION_HEX < 0x02050000 if (PyInstance_Check(type)) { type = (PyObject*) ((PyInstanceObject*)type)->in_class; Py_INCREF(type); } else { type = 0; PyErr_SetString(PyExc_TypeError, "raise: exception must be an old-style class or instance"); goto raise_error; } #else type = (PyObject*) Py_TYPE(type); Py_INCREF(type); if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { PyErr_SetString(PyExc_TypeError, "raise: exception class must be a subclass of BaseException"); goto raise_error; } #endif } __Pyx_ErrRestore(type, value, tb); return; raise_error: Py_XDECREF(value); Py_XDECREF(type); Py_XDECREF(tb); return; } #else /* Python 3+ */ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { PyObject* owned_instance = NULL; if (tb == Py_None) { tb = 0; } else if (tb && !PyTraceBack_Check(tb)) { PyErr_SetString(PyExc_TypeError, "raise: arg 3 must be a traceback or None"); goto bad; } if (value == Py_None) value = 0; if (PyExceptionInstance_Check(type)) { if (value) { PyErr_SetString(PyExc_TypeError, "instance exception may not have a separate value"); goto bad; } value = type; type = (PyObject*) Py_TYPE(value); } else if (PyExceptionClass_Check(type)) { // make sure value is an exception instance of type PyObject *instance_class = NULL; if (value && PyExceptionInstance_Check(value)) { instance_class = (PyObject*) Py_TYPE(value); if (instance_class != type) { if (PyObject_IsSubclass(instance_class, type)) { // believe the instance type = instance_class; } else { instance_class = NULL; } } } if (!instance_class) { // instantiate the type now (we don't know when and how it will be caught) // assuming that 'value' is an argument to the type's constructor // not using PyErr_NormalizeException() to avoid ref-counting problems PyObject *args; if (!value) args = PyTuple_New(0); else if (PyTuple_Check(value)) { Py_INCREF(value); args = value; } else args = PyTuple_Pack(1, value); if (!args) goto bad; owned_instance = PyObject_Call(type, args, NULL); Py_DECREF(args); if (!owned_instance) goto bad; value = owned_instance; if (!PyExceptionInstance_Check(value)) { PyErr_Format(PyExc_TypeError, "calling %R should have returned an instance of " "BaseException, not %R", type, Py_TYPE(value)); goto bad; } } } else { PyErr_SetString(PyExc_TypeError, "raise: exception class must be a subclass of BaseException"); goto bad; } #if PY_VERSION_HEX >= 0x03030000 if (cause) { #else if (cause && cause != Py_None) { #endif PyObject *fixed_cause; if (cause == Py_None) { // raise ... from None fixed_cause = NULL; } else if (PyExceptionClass_Check(cause)) { fixed_cause = PyObject_CallObject(cause, NULL); if (fixed_cause == NULL) goto bad; } else if (PyExceptionInstance_Check(cause)) { fixed_cause = cause; Py_INCREF(fixed_cause); } else { PyErr_SetString(PyExc_TypeError, "exception causes must derive from " "BaseException"); goto bad; } PyException_SetCause(value, fixed_cause); } PyErr_SetObject(type, value); if (tb) { PyThreadState *tstate = PyThreadState_GET(); PyObject* tmp_tb = tstate->curexc_traceback; if (tb != tmp_tb) { Py_INCREF(tb); tstate->curexc_traceback = tb; Py_XDECREF(tmp_tb); } } bad: Py_XDECREF(owned_instance); return; } #endif /////////////// GetException.proto /////////////// static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ /////////////// GetException /////////////// static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) { PyObject *local_type, *local_value, *local_tb; #if CYTHON_COMPILING_IN_CPYTHON PyObject *tmp_type, *tmp_value, *tmp_tb; PyThreadState *tstate = PyThreadState_GET(); local_type = tstate->curexc_type; local_value = tstate->curexc_value; local_tb = tstate->curexc_traceback; tstate->curexc_type = 0; tstate->curexc_value = 0; tstate->curexc_traceback = 0; #else PyErr_Fetch(&local_type, &local_value, &local_tb); #endif PyErr_NormalizeException(&local_type, &local_value, &local_tb); #if CYTHON_COMPILING_IN_CPYTHON if (unlikely(tstate->curexc_type)) #else if (unlikely(PyErr_Occurred())) #endif goto bad; #if PY_MAJOR_VERSION >= 3 if (local_tb) { if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) goto bad; } #endif // traceback may be NULL for freshly raised exceptions Py_XINCREF(local_tb); // exception state may be temporarily empty in parallel loops (race condition) Py_XINCREF(local_type); Py_XINCREF(local_value); *type = local_type; *value = local_value; *tb = local_tb; #if CYTHON_COMPILING_IN_CPYTHON tmp_type = tstate->exc_type; tmp_value = tstate->exc_value; tmp_tb = tstate->exc_traceback; tstate->exc_type = local_type; tstate->exc_value = local_value; tstate->exc_traceback = local_tb; // Make sure tstate is in a consistent state when we XDECREF // these objects (DECREF may run arbitrary code). Py_XDECREF(tmp_type); Py_XDECREF(tmp_value); Py_XDECREF(tmp_tb); #else PyErr_SetExcInfo(local_type, local_value, local_tb); #endif return 0; bad: *type = 0; *value = 0; *tb = 0; Py_XDECREF(local_type); Py_XDECREF(local_value); Py_XDECREF(local_tb); return -1; } /////////////// ReRaiseException.proto /////////////// static CYTHON_INLINE void __Pyx_ReraiseException(void); /*proto*/ /////////////// ReRaiseException.proto /////////////// static CYTHON_INLINE void __Pyx_ReraiseException(void) { PyObject *type = NULL, *value = NULL, *tb = NULL; #if CYTHON_COMPILING_IN_CPYTHON PyThreadState *tstate = PyThreadState_GET(); type = tstate->exc_type; value = tstate->exc_value; tb = tstate->exc_traceback; #else PyErr_GetExcInfo(&type, &value, &tb); #endif if (!type || type == Py_None) { #if !CYTHON_COMPILING_IN_CPYTHON Py_XDECREF(type); Py_XDECREF(value); Py_XDECREF(tb); #endif // message copied from Py3 PyErr_SetString(PyExc_RuntimeError, "No active exception to reraise"); } else { #if CYTHON_COMPILING_IN_CPYTHON Py_INCREF(type); Py_XINCREF(value); Py_XINCREF(tb); #endif PyErr_Restore(type, value, tb); } } /////////////// SaveResetException.proto /////////////// static CYTHON_INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ /////////////// SaveResetException /////////////// static CYTHON_INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) { #if CYTHON_COMPILING_IN_CPYTHON PyThreadState *tstate = PyThreadState_GET(); *type = tstate->exc_type; *value = tstate->exc_value; *tb = tstate->exc_traceback; Py_XINCREF(*type); Py_XINCREF(*value); Py_XINCREF(*tb); #else PyErr_GetExcInfo(type, value, tb); #endif } static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) { #if CYTHON_COMPILING_IN_CPYTHON PyObject *tmp_type, *tmp_value, *tmp_tb; PyThreadState *tstate = PyThreadState_GET(); tmp_type = tstate->exc_type; tmp_value = tstate->exc_value; tmp_tb = tstate->exc_traceback; tstate->exc_type = type; tstate->exc_value = value; tstate->exc_traceback = tb; Py_XDECREF(tmp_type); Py_XDECREF(tmp_value); Py_XDECREF(tmp_tb); #else PyErr_SetExcInfo(type, value, tb); #endif } /////////////// SwapException.proto /////////////// static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ /////////////// SwapException /////////////// static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { PyObject *tmp_type, *tmp_value, *tmp_tb; #if CYTHON_COMPILING_IN_CPYTHON PyThreadState *tstate = PyThreadState_GET(); tmp_type = tstate->exc_type; tmp_value = tstate->exc_value; tmp_tb = tstate->exc_traceback; tstate->exc_type = *type; tstate->exc_value = *value; tstate->exc_traceback = *tb; #else PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); PyErr_SetExcInfo(*type, *value, *tb); #endif *type = tmp_type; *value = tmp_value; *tb = tmp_tb; } /////////////// WriteUnraisableException.proto /////////////// static void __Pyx_WriteUnraisable(const char *name, int clineno, int lineno, const char *filename, int full_traceback); /*proto*/ /////////////// WriteUnraisableException /////////////// //@requires: PyErrFetchRestore static void __Pyx_WriteUnraisable(const char *name, CYTHON_UNUSED int clineno, CYTHON_UNUSED int lineno, CYTHON_UNUSED const char *filename, int full_traceback) { PyObject *old_exc, *old_val, *old_tb; PyObject *ctx; __Pyx_ErrFetch(&old_exc, &old_val, &old_tb); if (full_traceback) { Py_XINCREF(old_exc); Py_XINCREF(old_val); Py_XINCREF(old_tb); __Pyx_ErrRestore(old_exc, old_val, old_tb); PyErr_PrintEx(1); } #if PY_MAJOR_VERSION < 3 ctx = PyString_FromString(name); #else ctx = PyUnicode_FromString(name); #endif __Pyx_ErrRestore(old_exc, old_val, old_tb); if (!ctx) { PyErr_WriteUnraisable(Py_None); } else { PyErr_WriteUnraisable(ctx); Py_DECREF(ctx); } } /////////////// AddTraceback.proto /////////////// static void __Pyx_AddTraceback(const char *funcname, int c_line, int py_line, const char *filename); /*proto*/ /////////////// AddTraceback /////////////// //@requires: ModuleSetupCode.c::CodeObjectCache //@substitute: naming #include "compile.h" #include "frameobject.h" #include "traceback.h" static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( const char *funcname, int c_line, int py_line, const char *filename) { PyCodeObject *py_code = 0; PyObject *py_srcfile = 0; PyObject *py_funcname = 0; #if PY_MAJOR_VERSION < 3 py_srcfile = PyString_FromString(filename); #else py_srcfile = PyUnicode_FromString(filename); #endif if (!py_srcfile) goto bad; if (c_line) { #if PY_MAJOR_VERSION < 3 py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, $cfilenm_cname, c_line); #else py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, $cfilenm_cname, c_line); #endif } else { #if PY_MAJOR_VERSION < 3 py_funcname = PyString_FromString(funcname); #else py_funcname = PyUnicode_FromString(funcname); #endif } if (!py_funcname) goto bad; py_code = __Pyx_PyCode_New( 0, /*int argcount,*/ 0, /*int kwonlyargcount,*/ 0, /*int nlocals,*/ 0, /*int stacksize,*/ 0, /*int flags,*/ $empty_bytes, /*PyObject *code,*/ $empty_tuple, /*PyObject *consts,*/ $empty_tuple, /*PyObject *names,*/ $empty_tuple, /*PyObject *varnames,*/ $empty_tuple, /*PyObject *freevars,*/ $empty_tuple, /*PyObject *cellvars,*/ py_srcfile, /*PyObject *filename,*/ py_funcname, /*PyObject *name,*/ py_line, /*int firstlineno,*/ $empty_bytes /*PyObject *lnotab*/ ); Py_DECREF(py_srcfile); Py_DECREF(py_funcname); return py_code; bad: Py_XDECREF(py_srcfile); Py_XDECREF(py_funcname); return NULL; } static void __Pyx_AddTraceback(const char *funcname, int c_line, int py_line, const char *filename) { PyCodeObject *py_code = 0; PyObject *py_globals = 0; PyFrameObject *py_frame = 0; py_code = $global_code_object_cache_find(c_line ? c_line : py_line); if (!py_code) { py_code = __Pyx_CreateCodeObjectForTraceback( funcname, c_line, py_line, filename); if (!py_code) goto bad; $global_code_object_cache_insert(c_line ? c_line : py_line, py_code); } py_globals = PyModule_GetDict($module_cname); if (!py_globals) goto bad; py_frame = PyFrame_New( PyThreadState_GET(), /*PyThreadState *tstate,*/ py_code, /*PyCodeObject *code,*/ py_globals, /*PyObject *globals,*/ 0 /*PyObject *locals*/ ); if (!py_frame) goto bad; py_frame->f_lineno = py_line; PyTraceBack_Here(py_frame); bad: Py_XDECREF(py_code); Py_XDECREF(py_frame); } cython-0.20.1+git90-g0e6e38e/Cython/Utility/ExtensionTypes.c000066400000000000000000000037531231323242300233310ustar00rootroot00000000000000 /////////////// CallNextTpDealloc.proto /////////////// static void __Pyx_call_next_tp_dealloc(PyObject* obj, destructor current_tp_dealloc); /////////////// CallNextTpDealloc /////////////// static void __Pyx_call_next_tp_dealloc(PyObject* obj, destructor current_tp_dealloc) { PyTypeObject* type = Py_TYPE(obj); /* try to find the first parent type that has a different tp_dealloc() function */ while (type && type->tp_dealloc != current_tp_dealloc) type = type->tp_base; while (type && type->tp_dealloc == current_tp_dealloc) type = type->tp_base; if (type) type->tp_dealloc(obj); } /////////////// CallNextTpTraverse.proto /////////////// static int __Pyx_call_next_tp_traverse(PyObject* obj, visitproc v, void *a, traverseproc current_tp_traverse); /////////////// CallNextTpTraverse /////////////// static int __Pyx_call_next_tp_traverse(PyObject* obj, visitproc v, void *a, traverseproc current_tp_traverse) { PyTypeObject* type = Py_TYPE(obj); /* try to find the first parent type that has a different tp_traverse() function */ while (type && type->tp_traverse != current_tp_traverse) type = type->tp_base; while (type && type->tp_traverse == current_tp_traverse) type = type->tp_base; if (type && type->tp_traverse) return type->tp_traverse(obj, v, a); // FIXME: really ignore? return 0; } /////////////// CallNextTpClear.proto /////////////// static void __Pyx_call_next_tp_clear(PyObject* obj, inquiry current_tp_dealloc); /////////////// CallNextTpClear /////////////// static void __Pyx_call_next_tp_clear(PyObject* obj, inquiry current_tp_clear) { PyTypeObject* type = Py_TYPE(obj); /* try to find the first parent type that has a different tp_clear() function */ while (type && type->tp_clear != current_tp_clear) type = type->tp_base; while (type && type->tp_clear == current_tp_clear) type = type->tp_base; if (type && type->tp_clear) type->tp_clear(obj); } cython-0.20.1+git90-g0e6e38e/Cython/Utility/FunctionArguments.c000066400000000000000000000235451231323242300240040ustar00rootroot00000000000000//////////////////// ArgTypeTest.proto //////////////////// static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, const char *name, int exact); /*proto*/ //////////////////// ArgTypeTest //////////////////// static void __Pyx_RaiseArgumentTypeInvalid(const char* name, PyObject *obj, PyTypeObject *type) { PyErr_Format(PyExc_TypeError, "Argument '%.200s' has incorrect type (expected %.200s, got %.200s)", name, type->tp_name, Py_TYPE(obj)->tp_name); } static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, const char *name, int exact) { if (unlikely(!type)) { PyErr_SetString(PyExc_SystemError, "Missing type object"); return 0; } if (none_allowed && obj == Py_None) return 1; else if (exact) { if (likely(Py_TYPE(obj) == type)) return 1; #if PY_MAJOR_VERSION == 2 else if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; #endif } else { if (likely(PyObject_TypeCheck(obj, type))) return 1; } __Pyx_RaiseArgumentTypeInvalid(name, obj, type); return 0; } //////////////////// RaiseArgTupleInvalid.proto //////////////////// static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/ //////////////////// RaiseArgTupleInvalid //////////////////// // __Pyx_RaiseArgtupleInvalid raises the correct exception when too // many or too few positional arguments were found. This handles // Py_ssize_t formatting correctly. static void __Pyx_RaiseArgtupleInvalid( const char* func_name, int exact, Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found) { Py_ssize_t num_expected; const char *more_or_less; if (num_found < num_min) { num_expected = num_min; more_or_less = "at least"; } else { num_expected = num_max; more_or_less = "at most"; } if (exact) { more_or_less = "exactly"; } PyErr_Format(PyExc_TypeError, "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", func_name, more_or_less, num_expected, (num_expected == 1) ? "" : "s", num_found); } //////////////////// RaiseKeywordRequired.proto //////////////////// static CYTHON_INLINE void __Pyx_RaiseKeywordRequired(const char* func_name, PyObject* kw_name); /*proto*/ //////////////////// RaiseKeywordRequired //////////////////// static CYTHON_INLINE void __Pyx_RaiseKeywordRequired( const char* func_name, PyObject* kw_name) { PyErr_Format(PyExc_TypeError, #if PY_MAJOR_VERSION >= 3 "%s() needs keyword-only argument %U", func_name, kw_name); #else "%s() needs keyword-only argument %s", func_name, PyString_AS_STRING(kw_name)); #endif } //////////////////// RaiseDoubleKeywords.proto //////////////////// static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); /*proto*/ //////////////////// RaiseDoubleKeywords //////////////////// static void __Pyx_RaiseDoubleKeywordsError( const char* func_name, PyObject* kw_name) { PyErr_Format(PyExc_TypeError, #if PY_MAJOR_VERSION >= 3 "%s() got multiple values for keyword argument '%U'", func_name, kw_name); #else "%s() got multiple values for keyword argument '%s'", func_name, PyString_AsString(kw_name)); #endif } //////////////////// KeywordStringCheck.proto //////////////////// static CYTHON_INLINE int __Pyx_CheckKeywordStrings(PyObject *kwdict, const char* function_name, int kw_allowed); /*proto*/ //////////////////// KeywordStringCheck //////////////////// // __Pyx_CheckKeywordStrings raises an error if non-string keywords // were passed to a function, or if any keywords were passed to a // function that does not accept them. static CYTHON_INLINE int __Pyx_CheckKeywordStrings( PyObject *kwdict, const char* function_name, int kw_allowed) { PyObject* key = 0; Py_ssize_t pos = 0; #if CPYTHON_COMPILING_IN_PYPY /* PyPy appears to check keywords at call time, not at unpacking time => not much to do here */ if (!kw_allowed && PyDict_Next(kwdict, &pos, &key, 0)) goto invalid_keyword; return 1; #else while (PyDict_Next(kwdict, &pos, &key, 0)) { #if PY_MAJOR_VERSION < 3 if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) #endif if (unlikely(!PyUnicode_Check(key))) goto invalid_keyword_type; } if ((!kw_allowed) && unlikely(key)) goto invalid_keyword; return 1; invalid_keyword_type: PyErr_Format(PyExc_TypeError, "%.200s() keywords must be strings", function_name); return 0; #endif invalid_keyword: PyErr_Format(PyExc_TypeError, #if PY_MAJOR_VERSION < 3 "%.200s() got an unexpected keyword argument '%.200s'", function_name, PyString_AsString(key)); #else "%s() got an unexpected keyword argument '%U'", function_name, key); #endif return 0; } //////////////////// ParseKeywords.proto //////////////////// static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], \ PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, \ const char* function_name); /*proto*/ //////////////////// ParseKeywords //////////////////// //@requires: RaiseDoubleKeywords // __Pyx_ParseOptionalKeywords copies the optional/unknown keyword // arguments from the kwds dict into kwds2. If kwds2 is NULL, unknown // keywords will raise an invalid keyword error. // // Three kinds of errors are checked: 1) non-string keywords, 2) // unexpected keywords and 3) overlap with positional arguments. // // If num_posargs is greater 0, it denotes the number of positional // arguments that were passed and that must therefore not appear // amongst the keywords as well. // // This method does not check for required keyword arguments. static int __Pyx_ParseOptionalKeywords( PyObject *kwds, PyObject **argnames[], PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, const char* function_name) { PyObject *key = 0, *value = 0; Py_ssize_t pos = 0; PyObject*** name; PyObject*** first_kw_arg = argnames + num_pos_args; while (PyDict_Next(kwds, &pos, &key, &value)) { name = first_kw_arg; while (*name && (**name != key)) name++; if (*name) { values[name-argnames] = value; continue; } name = first_kw_arg; #if PY_MAJOR_VERSION < 3 if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { while (*name) { if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) && _PyString_Eq(**name, key)) { values[name-argnames] = value; break; } name++; } if (*name) continue; else { // not found after positional args, check for duplicate PyObject*** argname = argnames; while (argname != first_kw_arg) { if ((**argname == key) || ( (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) && _PyString_Eq(**argname, key))) { goto arg_passed_twice; } argname++; } } } else #endif if (likely(PyUnicode_Check(key))) { while (*name) { int cmp = (**name == key) ? 0 : #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : #endif // need to convert argument name from bytes to unicode for comparison PyUnicode_Compare(**name, key); if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; if (cmp == 0) { values[name-argnames] = value; break; } name++; } if (*name) continue; else { // not found after positional args, check for duplicate PyObject*** argname = argnames; while (argname != first_kw_arg) { int cmp = (**argname == key) ? 0 : #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : #endif // need to convert argument name from bytes to unicode for comparison PyUnicode_Compare(**argname, key); if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; if (cmp == 0) goto arg_passed_twice; argname++; } } } else goto invalid_keyword_type; if (kwds2) { if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; } else { goto invalid_keyword; } } return 0; arg_passed_twice: __Pyx_RaiseDoubleKeywordsError(function_name, key); goto bad; invalid_keyword_type: PyErr_Format(PyExc_TypeError, "%.200s() keywords must be strings", function_name); goto bad; invalid_keyword: PyErr_Format(PyExc_TypeError, #if PY_MAJOR_VERSION < 3 "%.200s() got an unexpected keyword argument '%.200s'", function_name, PyString_AsString(key)); #else "%s() got an unexpected keyword argument '%U'", function_name, key); #endif bad: return -1; } cython-0.20.1+git90-g0e6e38e/Cython/Utility/Generator.c000066400000000000000000000513501231323242300222520ustar00rootroot00000000000000//////////////////// YieldFrom.proto //////////////////// static CYTHON_INLINE PyObject* __Pyx_Generator_Yield_From(__pyx_GeneratorObject *gen, PyObject *source); //////////////////// YieldFrom //////////////////// //@requires: Generator static CYTHON_INLINE PyObject* __Pyx_Generator_Yield_From(__pyx_GeneratorObject *gen, PyObject *source) { PyObject *source_gen, *retval; source_gen = PyObject_GetIter(source); if (unlikely(!source_gen)) return NULL; /* source_gen is now the iterator, make the first next() call */ retval = Py_TYPE(source_gen)->tp_iternext(source_gen); if (likely(retval)) { gen->yieldfrom = source_gen; return retval; } Py_DECREF(source_gen); return NULL; } //////////////////// Generator.proto //////////////////// #define __Pyx_Generator_USED #include #include typedef PyObject *(*__pyx_generator_body_t)(PyObject *, PyObject *); typedef struct { PyObject_HEAD __pyx_generator_body_t body; PyObject *closure; PyObject *exc_type; PyObject *exc_value; PyObject *exc_traceback; PyObject *gi_weakreflist; PyObject *classobj; PyObject *yieldfrom; int resume_label; // using T_BOOL for property below requires char value char is_running; } __pyx_GeneratorObject; static __pyx_GeneratorObject *__Pyx_Generator_New(__pyx_generator_body_t body, PyObject *closure); static int __pyx_Generator_init(void); static int __Pyx_Generator_clear(PyObject* self); #if 1 || PY_VERSION_HEX < 0x030300B0 static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue); #else #define __Pyx_PyGen_FetchStopIterationValue(pvalue) PyGen_FetchStopIterationValue(pvalue) #endif //////////////////// Generator //////////////////// //@requires: Exceptions.c::PyErrFetchRestore //@requires: Exceptions.c::SwapException //@requires: Exceptions.c::RaiseException //@requires: ObjectHandling.c::PyObjectCallMethod //@requires: CommonTypes.c::FetchCommonType static PyObject *__Pyx_Generator_Next(PyObject *self); static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value); static PyObject *__Pyx_Generator_Close(PyObject *self); static PyObject *__Pyx_Generator_Throw(PyObject *gen, PyObject *args); static PyTypeObject *__pyx_GeneratorType = 0; #define __Pyx_Generator_CheckExact(obj) (Py_TYPE(obj) == __pyx_GeneratorType) #define __Pyx_Generator_Undelegate(gen) Py_CLEAR((gen)->yieldfrom) // If StopIteration exception is set, fetches its 'value' // attribute if any, otherwise sets pvalue to None. // // Returns 0 if no exception or StopIteration is set. // If any other exception is set, returns -1 and leaves // pvalue unchanged. #if 1 || PY_VERSION_HEX < 0x030300B0 static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) { PyObject *et, *ev, *tb; PyObject *value = NULL; __Pyx_ErrFetch(&et, &ev, &tb); if (!et) { Py_XDECREF(tb); Py_XDECREF(ev); Py_INCREF(Py_None); *pvalue = Py_None; return 0; } if (unlikely(et != PyExc_StopIteration) && unlikely(!PyErr_GivenExceptionMatches(et, PyExc_StopIteration))) { __Pyx_ErrRestore(et, ev, tb); return -1; } // most common case: plain StopIteration without or with separate argument if (likely(et == PyExc_StopIteration)) { if (likely(!ev) || !PyObject_IsInstance(ev, PyExc_StopIteration)) { // PyErr_SetObject() and friends put the value directly into ev if (!ev) { Py_INCREF(Py_None); ev = Py_None; } Py_XDECREF(tb); Py_DECREF(et); *pvalue = ev; return 0; } } // otherwise: normalise and check what that gives us PyErr_NormalizeException(&et, &ev, &tb); if (unlikely(!PyObject_IsInstance(ev, PyExc_StopIteration))) { // looks like normalisation failed - raise the new exception __Pyx_ErrRestore(et, ev, tb); return -1; } Py_XDECREF(tb); Py_DECREF(et); #if PY_VERSION_HEX >= 0x030300A0 value = ((PyStopIterationObject *)ev)->value; Py_INCREF(value); Py_DECREF(ev); #else { PyObject* args = PyObject_GetAttr(ev, PYIDENT("args")); Py_DECREF(ev); if (likely(args)) { value = PyObject_GetItem(args, 0); Py_DECREF(args); } if (unlikely(!value)) { __Pyx_ErrRestore(NULL, NULL, NULL); Py_INCREF(Py_None); value = Py_None; } } #endif *pvalue = value; return 0; } #endif static CYTHON_INLINE void __Pyx_Generator_ExceptionClear(__pyx_GeneratorObject *self) { PyObject *exc_type = self->exc_type; PyObject *exc_value = self->exc_value; PyObject *exc_traceback = self->exc_traceback; self->exc_type = NULL; self->exc_value = NULL; self->exc_traceback = NULL; Py_XDECREF(exc_type); Py_XDECREF(exc_value); Py_XDECREF(exc_traceback); } static CYTHON_INLINE int __Pyx_Generator_CheckRunning(__pyx_GeneratorObject *gen) { if (unlikely(gen->is_running)) { PyErr_SetString(PyExc_ValueError, "generator already executing"); return 1; } return 0; } static CYTHON_INLINE PyObject *__Pyx_Generator_SendEx(__pyx_GeneratorObject *self, PyObject *value) { PyObject *retval; assert(!self->is_running); if (unlikely(self->resume_label == 0)) { if (unlikely(value && value != Py_None)) { PyErr_SetString(PyExc_TypeError, "can't send non-None value to a " "just-started generator"); return NULL; } } if (unlikely(self->resume_label == -1)) { PyErr_SetNone(PyExc_StopIteration); return NULL; } if (value) { #if CYTHON_COMPILING_IN_PYPY // FIXME: what to do in PyPy? #else /* Generators always return to their most recent caller, not * necessarily their creator. */ if (self->exc_traceback) { PyThreadState *tstate = PyThreadState_GET(); PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback; PyFrameObject *f = tb->tb_frame; Py_XINCREF(tstate->frame); assert(f->f_back == NULL); f->f_back = tstate->frame; } #endif __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value, &self->exc_traceback); } else { __Pyx_Generator_ExceptionClear(self); } self->is_running = 1; retval = self->body((PyObject *) self, value); self->is_running = 0; if (retval) { __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value, &self->exc_traceback); #if CYTHON_COMPILING_IN_PYPY // FIXME: what to do in PyPy? #else /* Don't keep the reference to f_back any longer than necessary. It * may keep a chain of frames alive or it could create a reference * cycle. */ if (self->exc_traceback) { PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback; PyFrameObject *f = tb->tb_frame; Py_CLEAR(f->f_back); } #endif } else { __Pyx_Generator_ExceptionClear(self); } return retval; } static CYTHON_INLINE PyObject *__Pyx_Generator_FinishDelegation(__pyx_GeneratorObject *gen) { PyObject *ret; PyObject *val = NULL; __Pyx_Generator_Undelegate(gen); __Pyx_PyGen_FetchStopIterationValue(&val); // val == NULL on failure => pass on exception ret = __Pyx_Generator_SendEx(gen, val); Py_XDECREF(val); return ret; } static PyObject *__Pyx_Generator_Next(PyObject *self) { __pyx_GeneratorObject *gen = (__pyx_GeneratorObject*) self; PyObject *yf = gen->yieldfrom; if (unlikely(__Pyx_Generator_CheckRunning(gen))) return NULL; if (yf) { PyObject *ret; // FIXME: does this really need an INCREF() ? //Py_INCREF(yf); /* YieldFrom code ensures that yf is an iterator */ gen->is_running = 1; ret = Py_TYPE(yf)->tp_iternext(yf); gen->is_running = 0; //Py_DECREF(yf); if (likely(ret)) { return ret; } return __Pyx_Generator_FinishDelegation(gen); } return __Pyx_Generator_SendEx(gen, Py_None); } static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value) { __pyx_GeneratorObject *gen = (__pyx_GeneratorObject*) self; PyObject *yf = gen->yieldfrom; if (unlikely(__Pyx_Generator_CheckRunning(gen))) return NULL; if (yf) { PyObject *ret; // FIXME: does this really need an INCREF() ? //Py_INCREF(yf); gen->is_running = 1; if (__Pyx_Generator_CheckExact(yf)) { ret = __Pyx_Generator_Send(yf, value); } else { if (value == Py_None) ret = PyIter_Next(yf); else ret = __Pyx_PyObject_CallMethod1(yf, PYIDENT("send"), value); } gen->is_running = 0; //Py_DECREF(yf); if (likely(ret)) { return ret; } return __Pyx_Generator_FinishDelegation(gen); } return __Pyx_Generator_SendEx(gen, value); } // This helper function is used by gen_close and gen_throw to // close a subiterator being delegated to by yield-from. static int __Pyx_Generator_CloseIter(__pyx_GeneratorObject *gen, PyObject *yf) { PyObject *retval = NULL; int err = 0; if (__Pyx_Generator_CheckExact(yf)) { retval = __Pyx_Generator_Close(yf); if (!retval) return -1; } else { PyObject *meth; gen->is_running = 1; meth = PyObject_GetAttr(yf, PYIDENT("close")); if (unlikely(!meth)) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_WriteUnraisable(yf); } PyErr_Clear(); } else { retval = PyObject_CallFunction(meth, NULL); Py_DECREF(meth); if (!retval) err = -1; } gen->is_running = 0; } Py_XDECREF(retval); return err; } static PyObject *__Pyx_Generator_Close(PyObject *self) { __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self; PyObject *retval, *raised_exception; PyObject *yf = gen->yieldfrom; int err = 0; if (unlikely(__Pyx_Generator_CheckRunning(gen))) return NULL; if (yf) { Py_INCREF(yf); err = __Pyx_Generator_CloseIter(gen, yf); __Pyx_Generator_Undelegate(gen); Py_DECREF(yf); } if (err == 0) #if PY_VERSION_HEX < 0x02050000 PyErr_SetNone(PyExc_StopIteration); #else PyErr_SetNone(PyExc_GeneratorExit); #endif retval = __Pyx_Generator_SendEx(gen, NULL); if (retval) { Py_DECREF(retval); PyErr_SetString(PyExc_RuntimeError, "generator ignored GeneratorExit"); return NULL; } raised_exception = PyErr_Occurred(); if (!raised_exception || raised_exception == PyExc_StopIteration #if PY_VERSION_HEX >= 0x02050000 || raised_exception == PyExc_GeneratorExit || PyErr_GivenExceptionMatches(raised_exception, PyExc_GeneratorExit) #endif || PyErr_GivenExceptionMatches(raised_exception, PyExc_StopIteration)) { if (raised_exception) PyErr_Clear(); /* ignore these errors */ Py_INCREF(Py_None); return Py_None; } return NULL; } static PyObject *__Pyx_Generator_Throw(PyObject *self, PyObject *args) { __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self; PyObject *typ; PyObject *tb = NULL; PyObject *val = NULL; PyObject *yf = gen->yieldfrom; if (!PyArg_UnpackTuple(args, (char *)"throw", 1, 3, &typ, &val, &tb)) return NULL; if (unlikely(__Pyx_Generator_CheckRunning(gen))) return NULL; if (yf) { PyObject *ret; Py_INCREF(yf); #if PY_VERSION_HEX >= 0x02050000 if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) { int err = __Pyx_Generator_CloseIter(gen, yf); Py_DECREF(yf); __Pyx_Generator_Undelegate(gen); if (err < 0) return __Pyx_Generator_SendEx(gen, NULL); goto throw_here; } #endif gen->is_running = 1; if (__Pyx_Generator_CheckExact(yf)) { ret = __Pyx_Generator_Throw(yf, args); } else { PyObject *meth = PyObject_GetAttr(yf, PYIDENT("throw")); if (unlikely(!meth)) { Py_DECREF(yf); if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { gen->is_running = 0; return NULL; } PyErr_Clear(); __Pyx_Generator_Undelegate(gen); gen->is_running = 0; goto throw_here; } ret = PyObject_CallObject(meth, args); Py_DECREF(meth); } gen->is_running = 0; Py_DECREF(yf); if (!ret) { ret = __Pyx_Generator_FinishDelegation(gen); } return ret; } throw_here: __Pyx_Raise(typ, val, tb, NULL); return __Pyx_Generator_SendEx(gen, NULL); } static int __Pyx_Generator_traverse(PyObject *self, visitproc visit, void *arg) { __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self; Py_VISIT(gen->closure); Py_VISIT(gen->classobj); Py_VISIT(gen->yieldfrom); Py_VISIT(gen->exc_type); Py_VISIT(gen->exc_value); Py_VISIT(gen->exc_traceback); return 0; } static int __Pyx_Generator_clear(PyObject *self) { __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self; Py_CLEAR(gen->closure); Py_CLEAR(gen->classobj); Py_CLEAR(gen->yieldfrom); Py_CLEAR(gen->exc_type); Py_CLEAR(gen->exc_value); Py_CLEAR(gen->exc_traceback); return 0; } static void __Pyx_Generator_dealloc(PyObject *self) { __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self; PyObject_GC_UnTrack(gen); if (gen->gi_weakreflist != NULL) PyObject_ClearWeakRefs(self); if (gen->resume_label > 0) { /* Generator is paused, so we need to close */ PyObject_GC_Track(self); #if PY_VERSION_HEX >= 0x030400a1 if (PyObject_CallFinalizerFromDealloc(self)) #else Py_TYPE(gen)->tp_del(self); if (self->ob_refcnt > 0) #endif return; /* resurrected. :( */ PyObject_GC_UnTrack(self); } __Pyx_Generator_clear(self); PyObject_GC_Del(gen); } static void __Pyx_Generator_del(PyObject *self) { PyObject *res; PyObject *error_type, *error_value, *error_traceback; __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self; if (gen->resume_label <= 0) return ; #if PY_VERSION_HEX < 0x030400a1 /* Temporarily resurrect the object. */ assert(self->ob_refcnt == 0); self->ob_refcnt = 1; #endif /* Save the current exception, if any. */ __Pyx_ErrFetch(&error_type, &error_value, &error_traceback); res = __Pyx_Generator_Close(self); if (res == NULL) PyErr_WriteUnraisable(self); else Py_DECREF(res); /* Restore the saved exception. */ __Pyx_ErrRestore(error_type, error_value, error_traceback); #if PY_VERSION_HEX < 0x030400a1 /* Undo the temporary resurrection; can't use DECREF here, it would * cause a recursive call. */ assert(self->ob_refcnt > 0); if (--self->ob_refcnt == 0) return; /* this is the normal path out */ /* close() resurrected it! Make it look like the original Py_DECREF * never happened. */ { Py_ssize_t refcnt = self->ob_refcnt; _Py_NewReference(self); self->ob_refcnt = refcnt; } #if CYTHON_COMPILING_IN_CPYTHON assert(PyType_IS_GC(self->ob_type) && _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so * we need to undo that. */ _Py_DEC_REFTOTAL; #endif /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object * chain, so no more to do there. * If COUNT_ALLOCS, the original decref bumped tp_frees, and * _Py_NewReference bumped tp_allocs: both of those need to be * undone. */ #ifdef COUNT_ALLOCS --Py_TYPE(self)->tp_frees; --Py_TYPE(self)->tp_allocs; #endif #endif } static PyMemberDef __pyx_Generator_memberlist[] = { {(char *) "gi_running", #if PY_VERSION_HEX >= 0x02060000 T_BOOL, #else T_BYTE, #endif offsetof(__pyx_GeneratorObject, is_running), READONLY, NULL}, {0, 0, 0, 0, 0} }; static PyMethodDef __pyx_Generator_methods[] = { {__Pyx_NAMESTR("send"), (PyCFunction) __Pyx_Generator_Send, METH_O, 0}, {__Pyx_NAMESTR("throw"), (PyCFunction) __Pyx_Generator_Throw, METH_VARARGS, 0}, {__Pyx_NAMESTR("close"), (PyCFunction) __Pyx_Generator_Close, METH_NOARGS, 0}, {0, 0, 0, 0} }; static PyTypeObject __pyx_GeneratorType_type = { PyVarObject_HEAD_INIT(0, 0) __Pyx_NAMESTR("generator"), /*tp_name*/ sizeof(__pyx_GeneratorObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor) __Pyx_Generator_dealloc,/*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ #if PY_MAJOR_VERSION < 3 0, /*tp_compare*/ #else 0, /*reserved*/ #endif 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags*/ 0, /*tp_doc*/ (traverseproc) __Pyx_Generator_traverse, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ offsetof(__pyx_GeneratorObject, gi_weakreflist), /* tp_weaklistoffse */ 0, /*tp_iter*/ (iternextfunc) __Pyx_Generator_Next, /*tp_iternext*/ __pyx_Generator_methods, /*tp_methods*/ __pyx_Generator_memberlist, /*tp_members*/ 0, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ 0, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ 0, /*tp_bases*/ 0, /*tp_mro*/ 0, /*tp_cache*/ 0, /*tp_subclasses*/ 0, /*tp_weaklist*/ #if PY_VERSION_HEX >= 0x030400a1 0, /*tp_del*/ #else __Pyx_Generator_del, /*tp_del*/ #endif #if PY_VERSION_HEX >= 0x02060000 0, /*tp_version_tag*/ #endif #if PY_VERSION_HEX >= 0x030400a1 __Pyx_Generator_del, /*tp_finalize*/ #endif }; static __pyx_GeneratorObject *__Pyx_Generator_New(__pyx_generator_body_t body, PyObject *closure) { __pyx_GeneratorObject *gen = PyObject_GC_New(__pyx_GeneratorObject, &__pyx_GeneratorType_type); if (gen == NULL) return NULL; gen->body = body; gen->closure = closure; Py_XINCREF(closure); gen->is_running = 0; gen->resume_label = 0; gen->classobj = NULL; gen->yieldfrom = NULL; gen->exc_type = NULL; gen->exc_value = NULL; gen->exc_traceback = NULL; gen->gi_weakreflist = NULL; PyObject_GC_Track(gen); return gen; } static int __pyx_Generator_init(void) { /* on Windows, C-API functions can't be used in slots statically */ __pyx_GeneratorType_type.tp_getattro = PyObject_GenericGetAttr; __pyx_GeneratorType_type.tp_iter = PyObject_SelfIter; __pyx_GeneratorType = __Pyx_FetchCommonType(&__pyx_GeneratorType_type); if (__pyx_GeneratorType == NULL) { return -1; } return 0; } cython-0.20.1+git90-g0e6e38e/Cython/Utility/ImportExport.c000066400000000000000000000401611231323242300227760ustar00rootroot00000000000000/////////////// PyIdentifierFromString.proto /////////////// #if !defined(__Pyx_PyIdentifier_FromString) #if PY_MAJOR_VERSION < 3 #define __Pyx_PyIdentifier_FromString(s) PyString_FromString(s) #else #define __Pyx_PyIdentifier_FromString(s) PyUnicode_FromString(s) #endif #endif /////////////// Import.proto /////////////// static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); /*proto*/ /////////////// Import /////////////// //@requires: ObjectHandling.c::PyObjectGetAttrStr //@substitute: naming static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { PyObject *empty_list = 0; PyObject *module = 0; PyObject *global_dict = 0; PyObject *empty_dict = 0; PyObject *list; #if PY_VERSION_HEX < 0x03030000 PyObject *py_import; py_import = __Pyx_PyObject_GetAttrStr($builtins_cname, PYIDENT("__import__")); if (!py_import) goto bad; #endif if (from_list) list = from_list; else { empty_list = PyList_New(0); if (!empty_list) goto bad; list = empty_list; } global_dict = PyModule_GetDict($module_cname); if (!global_dict) goto bad; empty_dict = PyDict_New(); if (!empty_dict) goto bad; #if PY_VERSION_HEX >= 0x02050000 { #if PY_MAJOR_VERSION >= 3 if (level == -1) { if (strchr(__Pyx_MODULE_NAME, '.')) { /* try package relative import first */ #if PY_VERSION_HEX < 0x03030000 PyObject *py_level = PyInt_FromLong(1); if (!py_level) goto bad; module = PyObject_CallFunctionObjArgs(py_import, name, global_dict, empty_dict, list, py_level, NULL); Py_DECREF(py_level); #else module = PyImport_ImportModuleLevelObject( name, global_dict, empty_dict, list, 1); #endif if (!module) { if (!PyErr_ExceptionMatches(PyExc_ImportError)) goto bad; PyErr_Clear(); } } level = 0; /* try absolute import on failure */ } #endif if (!module) { #if PY_VERSION_HEX < 0x03030000 PyObject *py_level = PyInt_FromLong(level); if (!py_level) goto bad; module = PyObject_CallFunctionObjArgs(py_import, name, global_dict, empty_dict, list, py_level, NULL); Py_DECREF(py_level); #else module = PyImport_ImportModuleLevelObject( name, global_dict, empty_dict, list, level); #endif } } #else if (level>0) { PyErr_SetString(PyExc_RuntimeError, "Relative import is not supported for Python <=2.4."); goto bad; } module = PyObject_CallFunctionObjArgs(py_import, name, global_dict, empty_dict, list, NULL); #endif bad: #if PY_VERSION_HEX < 0x03030000 Py_XDECREF(py_import); #endif Py_XDECREF(empty_list); Py_XDECREF(empty_dict); return module; } /////////////// ImportFrom.proto /////////////// static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); /*proto*/ /////////////// ImportFrom /////////////// //@requires: ObjectHandling.c::PyObjectGetAttrStr static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Format(PyExc_ImportError, #if PY_MAJOR_VERSION < 3 "cannot import name %.230s", PyString_AS_STRING(name)); #else "cannot import name %S", name); #endif } return value; } /////////////// ModuleImport.proto /////////////// static PyObject *__Pyx_ImportModule(const char *name); /*proto*/ /////////////// ModuleImport /////////////// //@requires: PyIdentifierFromString #ifndef __PYX_HAVE_RT_ImportModule #define __PYX_HAVE_RT_ImportModule static PyObject *__Pyx_ImportModule(const char *name) { PyObject *py_name = 0; PyObject *py_module = 0; py_name = __Pyx_PyIdentifier_FromString(name); if (!py_name) goto bad; py_module = PyImport_Import(py_name); Py_DECREF(py_name); return py_module; bad: Py_XDECREF(py_name); return 0; } #endif /////////////// SetPackagePathFromImportLib.proto /////////////// #if PY_VERSION_HEX >= 0x03030000 static int __Pyx_SetPackagePathFromImportLib(const char* parent_package_name, PyObject *module_name); #else #define __Pyx_SetPackagePathFromImportLib(a, b) 0 #endif /////////////// SetPackagePathFromImportLib /////////////// //@requires: ObjectHandling.c::PyObjectGetAttrStr //@substitute: naming #if PY_VERSION_HEX >= 0x03030000 static int __Pyx_SetPackagePathFromImportLib(const char* parent_package_name, PyObject *module_name) { PyObject *importlib, *loader, *osmod, *ossep, *parts, *package_path; PyObject *path = NULL, *file_path = NULL; int result; if (parent_package_name) { PyObject *package = PyImport_ImportModule(parent_package_name); if (unlikely(!package)) goto bad; path = PyObject_GetAttrString(package, "__path__"); Py_DECREF(package); if (unlikely(!path) || unlikely(path == Py_None)) goto bad; } else { path = Py_None; Py_INCREF(Py_None); } // package_path = [importlib.find_loader(module_name, path).path.rsplit(os.sep, 1)[0]] importlib = PyImport_ImportModule("importlib"); if (unlikely(!importlib)) goto bad; loader = PyObject_CallMethod(importlib, "find_loader", "(OO)", module_name, path); Py_DECREF(importlib); Py_DECREF(path); path = NULL; if (unlikely(!loader)) goto bad; file_path = PyObject_GetAttrString(loader, "path"); Py_DECREF(loader); if (unlikely(!file_path)) goto bad; if (unlikely(__Pyx_SetAttrString($module_cname, "__file__", file_path) < 0)) goto bad; osmod = PyImport_ImportModule("os"); if (unlikely(!osmod)) goto bad; ossep = PyObject_GetAttrString(osmod, "sep"); Py_DECREF(osmod); if (unlikely(!ossep)) goto bad; parts = PyObject_CallMethod(file_path, "rsplit", "(Oi)", ossep, 1); Py_DECREF(file_path); file_path = NULL; Py_DECREF(ossep); if (unlikely(!parts)) goto bad; package_path = Py_BuildValue("[O]", PyList_GET_ITEM(parts, 0)); Py_DECREF(parts); if (unlikely(!package_path)) goto bad; goto set_path; bad: PyErr_WriteUnraisable(module_name); Py_XDECREF(path); Py_XDECREF(file_path); // set an empty path list on failure PyErr_Clear(); package_path = PyList_New(0); if (unlikely(!package_path)) return -1; set_path: result = __Pyx_SetAttrString($module_cname, "__path__", package_path); Py_DECREF(package_path); return result; } #endif /////////////// TypeImport.proto /////////////// static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name, size_t size, int strict); /*proto*/ /////////////// TypeImport /////////////// //@requires: PyIdentifierFromString //@requires: ModuleImport #ifndef __PYX_HAVE_RT_ImportType #define __PYX_HAVE_RT_ImportType static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name, size_t size, int strict) { PyObject *py_module = 0; PyObject *result = 0; PyObject *py_name = 0; char warning[200]; Py_ssize_t basicsize; #ifdef Py_LIMITED_API PyObject *py_basicsize; #endif py_module = __Pyx_ImportModule(module_name); if (!py_module) goto bad; py_name = __Pyx_PyIdentifier_FromString(class_name); if (!py_name) goto bad; result = PyObject_GetAttr(py_module, py_name); Py_DECREF(py_name); py_name = 0; Py_DECREF(py_module); py_module = 0; if (!result) goto bad; if (!PyType_Check(result)) { PyErr_Format(PyExc_TypeError, "%.200s.%.200s is not a type object", module_name, class_name); goto bad; } #ifndef Py_LIMITED_API basicsize = ((PyTypeObject *)result)->tp_basicsize; #else py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); if (!py_basicsize) goto bad; basicsize = PyLong_AsSsize_t(py_basicsize); Py_DECREF(py_basicsize); py_basicsize = 0; if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) goto bad; #endif if (!strict && (size_t)basicsize > size) { PyOS_snprintf(warning, sizeof(warning), "%s.%s size changed, may indicate binary incompatibility", module_name, class_name); #if PY_VERSION_HEX < 0x02050000 if (PyErr_Warn(NULL, warning) < 0) goto bad; #else if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; #endif } else if ((size_t)basicsize != size) { PyErr_Format(PyExc_ValueError, "%.200s.%.200s has the wrong size, try recompiling", module_name, class_name); goto bad; } return (PyTypeObject *)result; bad: Py_XDECREF(py_module); Py_XDECREF(result); return NULL; } #endif /////////////// FunctionImport.proto /////////////// static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig); /*proto*/ /////////////// FunctionImport /////////////// //@substitute: naming #ifndef __PYX_HAVE_RT_ImportFunction #define __PYX_HAVE_RT_ImportFunction static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig) { PyObject *d = 0; PyObject *cobj = 0; union { void (*fp)(void); void *p; } tmp; d = PyObject_GetAttrString(module, (char *)"$api_name"); if (!d) goto bad; cobj = PyDict_GetItemString(d, funcname); if (!cobj) { PyErr_Format(PyExc_ImportError, "%.200s does not export expected C function %.200s", PyModule_GetName(module), funcname); goto bad; } #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3 && PY_MINOR_VERSION==0) if (!PyCapsule_IsValid(cobj, sig)) { PyErr_Format(PyExc_TypeError, "C function %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj)); goto bad; } tmp.p = PyCapsule_GetPointer(cobj, sig); #else {const char *desc, *s1, *s2; desc = (const char *)PyCObject_GetDesc(cobj); if (!desc) goto bad; s1 = desc; s2 = sig; while (*s1 != '\0' && *s1 == *s2) { s1++; s2++; } if (*s1 != *s2) { PyErr_Format(PyExc_TypeError, "C function %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", PyModule_GetName(module), funcname, sig, desc); goto bad; } tmp.p = PyCObject_AsVoidPtr(cobj);} #endif *f = tmp.fp; if (!(*f)) goto bad; Py_DECREF(d); return 0; bad: Py_XDECREF(d); return -1; } #endif /////////////// FunctionExport.proto /////////////// static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig); /*proto*/ /////////////// FunctionExport /////////////// //@substitute: naming static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig) { PyObject *d = 0; PyObject *cobj = 0; union { void (*fp)(void); void *p; } tmp; d = PyObject_GetAttrString($module_cname, (char *)"$api_name"); if (!d) { PyErr_Clear(); d = PyDict_New(); if (!d) goto bad; Py_INCREF(d); if (PyModule_AddObject($module_cname, (char *)"$api_name", d) < 0) goto bad; } tmp.fp = f; #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0) cobj = PyCapsule_New(tmp.p, sig, 0); #else cobj = PyCObject_FromVoidPtrAndDesc(tmp.p, (void *)sig, 0); #endif if (!cobj) goto bad; if (PyDict_SetItemString(d, name, cobj) < 0) goto bad; Py_DECREF(cobj); Py_DECREF(d); return 0; bad: Py_XDECREF(cobj); Py_XDECREF(d); return -1; } /////////////// VoidPtrImport.proto /////////////// static int __Pyx_ImportVoidPtr(PyObject *module, const char *name, void **p, const char *sig); /*proto*/ /////////////// VoidPtrImport /////////////// //@substitute: naming #ifndef __PYX_HAVE_RT_ImportVoidPtr #define __PYX_HAVE_RT_ImportVoidPtr static int __Pyx_ImportVoidPtr(PyObject *module, const char *name, void **p, const char *sig) { PyObject *d = 0; PyObject *cobj = 0; d = PyObject_GetAttrString(module, (char *)"$api_name"); if (!d) goto bad; cobj = PyDict_GetItemString(d, name); if (!cobj) { PyErr_Format(PyExc_ImportError, "%.200s does not export expected C variable %.200s", PyModule_GetName(module), name); goto bad; } #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3 && PY_MINOR_VERSION==0) if (!PyCapsule_IsValid(cobj, sig)) { PyErr_Format(PyExc_TypeError, "C variable %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", PyModule_GetName(module), name, sig, PyCapsule_GetName(cobj)); goto bad; } *p = PyCapsule_GetPointer(cobj, sig); #else {const char *desc, *s1, *s2; desc = (const char *)PyCObject_GetDesc(cobj); if (!desc) goto bad; s1 = desc; s2 = sig; while (*s1 != '\0' && *s1 == *s2) { s1++; s2++; } if (*s1 != *s2) { PyErr_Format(PyExc_TypeError, "C variable %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", PyModule_GetName(module), name, sig, desc); goto bad; } *p = PyCObject_AsVoidPtr(cobj);} #endif if (!(*p)) goto bad; Py_DECREF(d); return 0; bad: Py_XDECREF(d); return -1; } #endif /////////////// VoidPtrExport.proto /////////////// static int __Pyx_ExportVoidPtr(PyObject *name, void *p, const char *sig); /*proto*/ /////////////// VoidPtrExport /////////////// //@substitute: naming //@requires: ObjectHandling.c::PyObjectSetAttrStr static int __Pyx_ExportVoidPtr(PyObject *name, void *p, const char *sig) { PyObject *d; PyObject *cobj = 0; d = PyDict_GetItem($moddict_cname, PYIDENT("$api_name")); Py_XINCREF(d); if (!d) { d = PyDict_New(); if (!d) goto bad; if (__Pyx_PyObject_SetAttrStr($module_cname, PYIDENT("$api_name"), d) < 0) goto bad; } #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3 && PY_MINOR_VERSION==0) cobj = PyCapsule_New(p, sig, 0); #else cobj = PyCObject_FromVoidPtrAndDesc(p, (void *)sig, 0); #endif if (!cobj) goto bad; if (PyDict_SetItem(d, name, cobj) < 0) goto bad; Py_DECREF(cobj); Py_DECREF(d); return 0; bad: Py_XDECREF(cobj); Py_XDECREF(d); return -1; } /////////////// SetVTable.proto /////////////// static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/ /////////////// SetVTable /////////////// static int __Pyx_SetVtable(PyObject *dict, void *vtable) { #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0) PyObject *ob = PyCapsule_New(vtable, 0, 0); #else PyObject *ob = PyCObject_FromVoidPtr(vtable, 0); #endif if (!ob) goto bad; if (PyDict_SetItem(dict, PYIDENT("__pyx_vtable__"), ob) < 0) goto bad; Py_DECREF(ob); return 0; bad: Py_XDECREF(ob); return -1; } /////////////// GetVTable.proto /////////////// static void* __Pyx_GetVtable(PyObject *dict); /*proto*/ /////////////// GetVTable /////////////// static void* __Pyx_GetVtable(PyObject *dict) { void* ptr; PyObject *ob = PyObject_GetItem(dict, PYIDENT("__pyx_vtable__")); if (!ob) goto bad; #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0) ptr = PyCapsule_GetPointer(ob, 0); #else ptr = PyCObject_AsVoidPtr(ob); #endif if (!ptr && !PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type"); Py_DECREF(ob); return ptr; bad: Py_XDECREF(ob); return NULL; } cython-0.20.1+git90-g0e6e38e/Cython/Utility/MemoryView.pyx000066400000000000000000001352061231323242300230300ustar00rootroot00000000000000#################### View.MemoryView #################### # This utility provides cython.array and cython.view.memoryview import cython # from cpython cimport ... cdef extern from "Python.h": int PyIndex_Check "__Pyx_PyIndex_Check" (object) object PyLong_FromVoidPtr(void *) cdef extern from "pythread.h": ctypedef void *PyThread_type_lock PyThread_type_lock PyThread_allocate_lock() void PyThread_free_lock(PyThread_type_lock) int PyThread_acquire_lock(PyThread_type_lock, int mode) nogil void PyThread_release_lock(PyThread_type_lock) nogil cdef extern from "string.h": void *memset(void *b, int c, size_t len) cdef extern from *: int __Pyx_GetBuffer(object, Py_buffer *, int) except -1 void __Pyx_ReleaseBuffer(Py_buffer *) ctypedef struct PyObject ctypedef Py_ssize_t Py_intptr_t void Py_INCREF(PyObject *) void Py_DECREF(PyObject *) void* PyMem_Malloc(size_t n) void PyMem_Free(void *p) cdef struct __pyx_memoryview "__pyx_memoryview_obj": Py_buffer view PyObject *obj __Pyx_TypeInfo *typeinfo ctypedef struct {{memviewslice_name}}: __pyx_memoryview *memview char *data Py_ssize_t shape[{{max_dims}}] Py_ssize_t strides[{{max_dims}}] Py_ssize_t suboffsets[{{max_dims}}] void __PYX_INC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil) void __PYX_XDEC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil) ctypedef struct __pyx_buffer "Py_buffer": PyObject *obj PyObject *Py_None cdef enum: PyBUF_C_CONTIGUOUS, PyBUF_F_CONTIGUOUS, PyBUF_ANY_CONTIGUOUS PyBUF_FORMAT PyBUF_WRITABLE PyBUF_STRIDES PyBUF_INDIRECT PyBUF_RECORDS ctypedef struct __Pyx_TypeInfo: pass cdef object capsule "__pyx_capsule_create" (void *p, char *sig) cdef int __pyx_array_getbuffer(PyObject *obj, Py_buffer view, int flags) cdef int __pyx_memoryview_getbuffer(PyObject *obj, Py_buffer view, int flags) cdef extern from *: ctypedef int __pyx_atomic_int {{memviewslice_name}} slice_copy_contig "__pyx_memoryview_copy_new_contig"( __Pyx_memviewslice *from_mvs, char *mode, int ndim, size_t sizeof_dtype, int contig_flag, bint dtype_is_object) nogil except * bint slice_is_contig "__pyx_memviewslice_is_contig" ( {{memviewslice_name}} *mvs, char order, int ndim) nogil bint slices_overlap "__pyx_slices_overlap" ({{memviewslice_name}} *slice1, {{memviewslice_name}} *slice2, int ndim, size_t itemsize) nogil cdef extern from "stdlib.h": void *malloc(size_t) nogil void free(void *) nogil void *memcpy(void *dest, void *src, size_t n) nogil # ### cython.array class # @cname("__pyx_array") cdef class array: cdef: char *data Py_ssize_t len char *format int ndim Py_ssize_t *_shape Py_ssize_t *_strides Py_ssize_t itemsize unicode mode # FIXME: this should have been a simple 'char' bytes _format void (*callback_free_data)(void *data) # cdef object _memview cdef bint free_data cdef bint dtype_is_object def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, mode="c", bint allocate_buffer=True): cdef int idx cdef Py_ssize_t i, dim cdef PyObject **p self.ndim = len(shape) self.itemsize = itemsize if not self.ndim: raise ValueError("Empty shape tuple for cython.array") if itemsize <= 0: raise ValueError("itemsize <= 0 for cython.array") if isinstance(format, unicode): format = (format).encode('ASCII') self._format = format # keep a reference to the byte string self.format = self._format # use single malloc() for both shape and strides self._shape = PyMem_Malloc(sizeof(Py_ssize_t)*self.ndim*2) self._strides = self._shape + self.ndim if not self._shape: raise MemoryError("unable to allocate shape and strides.") # cdef Py_ssize_t dim, stride for idx, dim in enumerate(shape): if dim <= 0: raise ValueError("Invalid shape in axis %d: %d." % (idx, dim)) self._shape[idx] = dim cdef char order if mode == 'fortran': order = b'F' self.mode = u'fortran' elif mode == 'c': order = b'C' self.mode = u'c' else: raise ValueError("Invalid mode, expected 'c' or 'fortran', got %s" % mode) self.len = fill_contig_strides_array(self._shape, self._strides, itemsize, self.ndim, order) self.free_data = allocate_buffer self.dtype_is_object = format == b'O' if allocate_buffer: # use malloc() for backwards compatibility # in case external code wants to change the data pointer self.data = malloc(self.len) if not self.data: raise MemoryError("unable to allocate array data.") if self.dtype_is_object: p = self.data for i in range(self.len / itemsize): p[i] = Py_None Py_INCREF(Py_None) @cname('getbuffer') def __getbuffer__(self, Py_buffer *info, int flags): cdef int bufmode = -1 if self.mode == u"c": bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS elif self.mode == u"fortran": bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS if not (flags & bufmode): raise ValueError("Can only create a buffer that is contiguous in memory.") info.buf = self.data info.len = self.len info.ndim = self.ndim info.shape = self._shape info.strides = self._strides info.suboffsets = NULL info.itemsize = self.itemsize info.readonly = 0 if flags & PyBUF_FORMAT: info.format = self.format else: info.format = NULL info.obj = self __pyx_getbuffer = capsule( &__pyx_array_getbuffer, "getbuffer(obj, view, flags)") def __dealloc__(array self): if self.callback_free_data != NULL: self.callback_free_data(self.data) elif self.free_data: if self.dtype_is_object: refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, False) free(self.data) PyMem_Free(self._shape) property memview: @cname('get_memview') def __get__(self): # Make this a property as 'self.data' may be set after instantiation flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE return memoryview(self, flags, self.dtype_is_object) def __getattr__(self, attr): return getattr(self.memview, attr) def __getitem__(self, item): return self.memview[item] def __setitem__(self, item, value): self.memview[item] = value @cname("__pyx_array_new") cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *mode, char *buf): cdef array result if buf == NULL: result = array(shape, itemsize, format, mode.decode('ASCII')) else: result = array(shape, itemsize, format, mode.decode('ASCII'), allocate_buffer=False) result.data = buf return result # ### Memoryview constants and cython.view.memoryview class # # Disable generic_contiguous, as it makes trouble verifying contiguity: # - 'contiguous' or '::1' means the dimension is contiguous with dtype # - 'indirect_contiguous' means a contiguous list of pointers # - dtype contiguous must be contiguous in the first or last dimension # from the start, or from the dimension following the last indirect dimension # # e.g. # int[::indirect_contiguous, ::contiguous, :] # # is valid (list of pointers to 2d fortran-contiguous array), but # # int[::generic_contiguous, ::contiguous, :] # # would mean you'd have assert dimension 0 to be indirect (and pointer contiguous) at runtime. # So it doesn't bring any performance benefit, and it's only confusing. @cname('__pyx_MemviewEnum') cdef class Enum(object): cdef object name def __init__(self, name): self.name = name def __repr__(self): return self.name cdef generic = Enum("") cdef strided = Enum("") # default cdef indirect = Enum("") # Disable generic_contiguous, as it is a troublemaker #cdef generic_contiguous = Enum("") cdef contiguous = Enum("") cdef indirect_contiguous = Enum("") # 'follow' is implied when the first or last axis is ::1 @cname('__pyx_align_pointer') cdef void *align_pointer(void *memory, size_t alignment) nogil: "Align pointer memory on a given boundary" cdef Py_intptr_t aligned_p = memory cdef size_t offset with cython.cdivision(True): offset = aligned_p % alignment if offset > 0: aligned_p += alignment - offset return aligned_p @cname('__pyx_memoryview') cdef class memoryview(object): cdef object obj cdef object _size cdef object _array_interface cdef PyThread_type_lock lock # the following array will contain a single __pyx_atomic int with # suitable alignment cdef __pyx_atomic_int acquisition_count[2] cdef __pyx_atomic_int *acquisition_count_aligned_p cdef Py_buffer view cdef int flags cdef bint dtype_is_object cdef __Pyx_TypeInfo *typeinfo def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): self.obj = obj self.flags = flags if type(self) is memoryview or obj is not None: __Pyx_GetBuffer(obj, &self.view, flags) if self.view.obj == NULL: (<__pyx_buffer *> &self.view).obj = Py_None Py_INCREF(Py_None) self.lock = PyThread_allocate_lock() if self.lock == NULL: raise MemoryError if flags & PyBUF_FORMAT: self.dtype_is_object = self.view.format == b'O' else: self.dtype_is_object = dtype_is_object self.acquisition_count_aligned_p = <__pyx_atomic_int *> align_pointer( &self.acquisition_count[0], sizeof(__pyx_atomic_int)) self.typeinfo = NULL def __dealloc__(memoryview self): if self.obj is not None: __Pyx_ReleaseBuffer(&self.view) if self.lock != NULL: PyThread_free_lock(self.lock) cdef char *get_item_pointer(memoryview self, object index) except NULL: cdef Py_ssize_t dim cdef char *itemp = self.view.buf for dim, idx in enumerate(index): itemp = pybuffer_index(&self.view, itemp, idx, dim) return itemp #@cname('__pyx_memoryview_getitem') def __getitem__(memoryview self, object index): if index is Ellipsis: return self have_slices, indices = _unellipsify(index, self.view.ndim) cdef char *itemp if have_slices: return memview_slice(self, indices) else: itemp = self.get_item_pointer(indices) return self.convert_item_to_object(itemp) def __setitem__(memoryview self, object index, object value): have_slices, index = _unellipsify(index, self.view.ndim) if have_slices: obj = self.is_slice(value) if obj: self.setitem_slice_assignment(self[index], obj) else: self.setitem_slice_assign_scalar(self[index], value) else: self.setitem_indexed(index, value) cdef is_slice(self, obj): if not isinstance(obj, memoryview): try: obj = memoryview(obj, self.flags|PyBUF_ANY_CONTIGUOUS, self.dtype_is_object) except TypeError: return None return obj cdef setitem_slice_assignment(self, dst, src): cdef {{memviewslice_name}} dst_slice cdef {{memviewslice_name}} src_slice memoryview_copy_contents(get_slice_from_memview(src, &src_slice)[0], get_slice_from_memview(dst, &dst_slice)[0], src.ndim, dst.ndim, self.dtype_is_object) cdef setitem_slice_assign_scalar(self, memoryview dst, value): cdef int array[128] cdef void *tmp = NULL cdef void *item cdef {{memviewslice_name}} *dst_slice cdef {{memviewslice_name}} tmp_slice dst_slice = get_slice_from_memview(dst, &tmp_slice) if self.view.itemsize > sizeof(array): tmp = PyMem_Malloc(self.view.itemsize) if tmp == NULL: raise MemoryError item = tmp else: item = array try: if self.dtype_is_object: ( item)[0] = value else: self.assign_item_from_object( item, value) # It would be easy to support indirect dimensions, but it's easier # to disallow :) if self.view.suboffsets != NULL: assert_direct_dimensions(self.view.suboffsets, self.view.ndim) slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize, item, self.dtype_is_object) finally: PyMem_Free(tmp) cdef setitem_indexed(self, index, value): cdef char *itemp = self.get_item_pointer(index) self.assign_item_from_object(itemp, value) cdef convert_item_to_object(self, char *itemp): """Only used if instantiated manually by the user, or if Cython doesn't know how to convert the type""" import struct cdef bytes bytesitem # Do a manual and complete check here instead of this easy hack bytesitem = itemp[:self.view.itemsize] try: result = struct.unpack(self.view.format, bytesitem) except struct.error: raise ValueError("Unable to convert item to object") else: if len(self.view.format) == 1: return result[0] return result cdef assign_item_from_object(self, char *itemp, object value): """Only used if instantiated manually by the user, or if Cython doesn't know how to convert the type""" import struct cdef char c cdef bytes bytesvalue cdef Py_ssize_t i if isinstance(value, tuple): bytesvalue = struct.pack(self.view.format, *value) else: bytesvalue = struct.pack(self.view.format, value) for i, c in enumerate(bytesvalue): itemp[i] = c @cname('getbuffer') def __getbuffer__(self, Py_buffer *info, int flags): if flags & PyBUF_STRIDES: info.shape = self.view.shape else: info.shape = NULL if flags & PyBUF_STRIDES: info.strides = self.view.strides else: info.strides = NULL if flags & PyBUF_INDIRECT: info.suboffsets = self.view.suboffsets else: info.suboffsets = NULL if flags & PyBUF_FORMAT: info.format = self.view.format else: info.format = NULL info.buf = self.view.buf info.ndim = self.view.ndim info.itemsize = self.view.itemsize info.len = self.view.len info.readonly = 0 info.obj = self __pyx_getbuffer = capsule( &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)") # Some properties that have the same sematics as in NumPy property T: @cname('__pyx_memoryview_transpose') def __get__(self): cdef _memoryviewslice result = memoryview_copy(self) transpose_memslice(&result.from_slice) return result property base: @cname('__pyx_memoryview__get__base') def __get__(self): return self.obj property shape: @cname('__pyx_memoryview_get_shape') def __get__(self): return tuple([self.view.shape[i] for i in xrange(self.view.ndim)]) property strides: @cname('__pyx_memoryview_get_strides') def __get__(self): if self.view.strides == NULL: # Note: we always ask for strides, so if this is not set it's a bug raise ValueError("Buffer view does not expose strides") return tuple([self.view.strides[i] for i in xrange(self.view.ndim)]) property suboffsets: @cname('__pyx_memoryview_get_suboffsets') def __get__(self): if self.view.suboffsets == NULL: return [-1] * self.view.ndim return tuple([self.view.suboffsets[i] for i in xrange(self.view.ndim)]) property ndim: @cname('__pyx_memoryview_get_ndim') def __get__(self): return self.view.ndim property itemsize: @cname('__pyx_memoryview_get_itemsize') def __get__(self): return self.view.itemsize property nbytes: @cname('__pyx_memoryview_get_nbytes') def __get__(self): return self.size * self.view.itemsize property size: @cname('__pyx_memoryview_get_size') def __get__(self): if self._size is None: result = 1 for length in self.shape: result *= length self._size = result return self._size def __len__(self): if self.view.ndim >= 1: return self.view.shape[0] return 0 def __repr__(self): return "" % (self.base.__class__.__name__, id(self)) def __str__(self): return "" % (self.base.__class__.__name__,) # Support the same attributes as memoryview slices def is_c_contig(self): cdef {{memviewslice_name}} *mslice cdef {{memviewslice_name}} tmp mslice = get_slice_from_memview(self, &tmp) return slice_is_contig(mslice, 'C', self.view.ndim) def is_f_contig(self): cdef {{memviewslice_name}} *mslice cdef {{memviewslice_name}} tmp mslice = get_slice_from_memview(self, &tmp) return slice_is_contig(mslice, 'F', self.view.ndim) def copy(self): cdef {{memviewslice_name}} mslice cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS slice_copy(self, &mslice) mslice = slice_copy_contig(&mslice, "c", self.view.ndim, self.view.itemsize, flags|PyBUF_C_CONTIGUOUS, self.dtype_is_object) return memoryview_copy_from_slice(self, &mslice) def copy_fortran(self): cdef {{memviewslice_name}} src, dst cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS slice_copy(self, &src) dst = slice_copy_contig(&src, "fortran", self.view.ndim, self.view.itemsize, flags|PyBUF_F_CONTIGUOUS, self.dtype_is_object) return memoryview_copy_from_slice(self, &dst) @cname('__pyx_memoryview_new') cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo): cdef memoryview result = memoryview(o, flags, dtype_is_object) result.typeinfo = typeinfo return result @cname('__pyx_memoryview_check') cdef inline bint memoryview_check(object o): return isinstance(o, memoryview) cdef tuple _unellipsify(object index, int ndim): """ Replace all ellipses with full slices and fill incomplete indices with full slices. """ if not isinstance(index, tuple): tup = (index,) else: tup = index result = [] have_slices = False seen_ellipsis = False for idx, item in enumerate(tup): if item is Ellipsis: if not seen_ellipsis: result.extend([slice(None)] * (ndim - len(tup) + 1)) seen_ellipsis = True else: result.append(slice(None)) have_slices = True else: if not isinstance(item, slice) and not PyIndex_Check(item): raise TypeError("Cannot index with type '%s'" % type(item)) have_slices = have_slices or isinstance(item, slice) result.append(item) nslices = ndim - len(result) if nslices: result.extend([slice(None)] * nslices) return have_slices or nslices, tuple(result) cdef assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim): cdef int i for i in range(ndim): if suboffsets[i] >= 0: raise ValueError("Indirect dimensions not supported") # ### Slicing a memoryview # @cname('__pyx_memview_slice') cdef memoryview memview_slice(memoryview memview, object indices): cdef int new_ndim = 0, suboffset_dim = -1, dim cdef bint negative_step cdef {{memviewslice_name}} src, dst cdef {{memviewslice_name}} *p_src # dst is copied by value in memoryview_fromslice -- initialize it # src is never copied memset(&dst, 0, sizeof(dst)) cdef _memoryviewslice memviewsliceobj assert memview.view.ndim > 0 if isinstance(memview, _memoryviewslice): memviewsliceobj = memview p_src = &memviewsliceobj.from_slice else: slice_copy(memview, &src) p_src = &src # Note: don't use variable src at this point # SubNote: we should be able to declare variables in blocks... # memoryview_fromslice() will inc our dst slice dst.memview = p_src.memview dst.data = p_src.data # Put everything in temps to avoid this bloody warning: # "Argument evaluation order in C function call is undefined and # may not be as expected" cdef {{memviewslice_name}} *p_dst = &dst cdef int *p_suboffset_dim = &suboffset_dim cdef Py_ssize_t start, stop, step cdef bint have_start, have_stop, have_step for dim, index in enumerate(indices): if PyIndex_Check(index): slice_memviewslice( p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim], dim, new_ndim, p_suboffset_dim, index, 0, 0, # start, stop, step 0, 0, 0, # have_{start,stop,step} False) elif index is None: p_dst.shape[new_ndim] = 1 p_dst.strides[new_ndim] = 0 p_dst.suboffsets[new_ndim] = -1 new_ndim += 1 else: start = index.start or 0 stop = index.stop or 0 step = index.step or 0 have_start = index.start is not None have_stop = index.stop is not None have_step = index.step is not None slice_memviewslice( p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim], dim, new_ndim, p_suboffset_dim, start, stop, step, have_start, have_stop, have_step, True) new_ndim += 1 if isinstance(memview, _memoryviewslice): return memoryview_fromslice(dst, new_ndim, memviewsliceobj.to_object_func, memviewsliceobj.to_dtype_func, memview.dtype_is_object) else: return memoryview_fromslice(dst, new_ndim, NULL, NULL, memview.dtype_is_object) # ### Slicing in a single dimension of a memoryviewslice # cdef extern from "stdlib.h": void abort() nogil void printf(char *s, ...) nogil cdef extern from "stdio.h": ctypedef struct FILE FILE *stderr int fputs(char *s, FILE *stream) cdef extern from "pystate.h": void PyThreadState_Get() nogil # These are not actually nogil, but we check for the GIL before calling them void PyErr_SetString(PyObject *type, char *msg) nogil PyObject *PyErr_Format(PyObject *exc, char *msg, ...) nogil @cname('__pyx_memoryview_slice_memviewslice') cdef int slice_memviewslice( {{memviewslice_name}} *dst, Py_ssize_t shape, Py_ssize_t stride, Py_ssize_t suboffset, int dim, int new_ndim, int *suboffset_dim, Py_ssize_t start, Py_ssize_t stop, Py_ssize_t step, int have_start, int have_stop, int have_step, bint is_slice) nogil except -1: """ Create a new slice dst given slice src. dim - the current src dimension (indexing will make dimensions disappear) new_dim - the new dst dimension suboffset_dim - pointer to a single int initialized to -1 to keep track of where slicing offsets should be added """ cdef Py_ssize_t new_shape cdef bint negative_step if not is_slice: # index is a normal integer-like index if start < 0: start += shape if not 0 <= start < shape: _err_dim(IndexError, "Index out of bounds (axis %d)", dim) else: # index is a slice negative_step = have_step != 0 and step < 0 if have_step and step == 0: _err_dim(ValueError, "Step may not be zero (axis %d)", dim) # check our bounds and set defaults if have_start: if start < 0: start += shape if start < 0: start = 0 elif start >= shape: if negative_step: start = shape - 1 else: start = shape else: if negative_step: start = shape - 1 else: start = 0 if have_stop: if stop < 0: stop += shape if stop < 0: stop = 0 elif stop > shape: stop = shape else: if negative_step: stop = -1 else: stop = shape if not have_step: step = 1 # len = ceil( (stop - start) / step ) with cython.cdivision(True): new_shape = (stop - start) // step if (stop - start) - step * new_shape: new_shape += 1 if new_shape < 0: new_shape = 0 # shape/strides/suboffsets dst.strides[new_ndim] = stride * step dst.shape[new_ndim] = new_shape dst.suboffsets[new_ndim] = suboffset # Add the slicing or idexing offsets to the right suboffset or base data * if suboffset_dim[0] < 0: dst.data += start * stride else: dst.suboffsets[suboffset_dim[0]] += start * stride if suboffset >= 0: if not is_slice: if new_ndim == 0: dst.data = ( dst.data)[0] + suboffset else: _err_dim(IndexError, "All dimensions preceding dimension %d " "must be indexed and not sliced", dim) else: suboffset_dim[0] = new_ndim return 0 # ### Index a memoryview # @cname('__pyx_pybuffer_index') cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, Py_ssize_t dim) except NULL: cdef Py_ssize_t shape, stride, suboffset = -1 cdef Py_ssize_t itemsize = view.itemsize cdef char *resultp if view.ndim == 0: shape = view.len / itemsize stride = itemsize else: shape = view.shape[dim] stride = view.strides[dim] if view.suboffsets != NULL: suboffset = view.suboffsets[dim] if index < 0: index += view.shape[dim] if index < 0: raise IndexError("Out of bounds on buffer access (axis %d)" % dim) if index >= shape: raise IndexError("Out of bounds on buffer access (axis %d)" % dim) resultp = bufp + index * stride if suboffset >= 0: resultp = ( resultp)[0] + suboffset return resultp # ### Transposing a memoryviewslice # @cname('__pyx_memslice_transpose') cdef int transpose_memslice({{memviewslice_name}} *memslice) nogil except 0: cdef int ndim = memslice.memview.view.ndim cdef Py_ssize_t *shape = memslice.shape cdef Py_ssize_t *strides = memslice.strides # reverse strides and shape cdef int i, j for i in range(ndim / 2): j = ndim - 1 - i strides[i], strides[j] = strides[j], strides[i] shape[i], shape[j] = shape[j], shape[i] if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0: _err(ValueError, "Cannot transpose memoryview with indirect dimensions") return 1 # ### Creating new memoryview objects from slices and memoryviews # @cname('__pyx_memoryviewslice') cdef class _memoryviewslice(memoryview): "Internal class for passing memoryview slices to Python" # We need this to keep our shape/strides/suboffset pointers valid cdef {{memviewslice_name}} from_slice # We need this only to print it's class' name cdef object from_object cdef object (*to_object_func)(char *) cdef int (*to_dtype_func)(char *, object) except 0 def __dealloc__(self): __PYX_XDEC_MEMVIEW(&self.from_slice, 1) cdef convert_item_to_object(self, char *itemp): if self.to_object_func != NULL: return self.to_object_func(itemp) else: return memoryview.convert_item_to_object(self, itemp) cdef assign_item_from_object(self, char *itemp, object value): if self.to_dtype_func != NULL: self.to_dtype_func(itemp, value) else: memoryview.assign_item_from_object(self, itemp, value) property base: @cname('__pyx_memoryviewslice__get__base') def __get__(self): return self.from_object __pyx_getbuffer = capsule( &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)") @cname('__pyx_memoryview_fromslice') cdef memoryview_fromslice({{memviewslice_name}} memviewslice, int ndim, object (*to_object_func)(char *), int (*to_dtype_func)(char *, object) except 0, bint dtype_is_object): cdef _memoryviewslice result cdef int i if memviewslice.memview == Py_None: return None # assert 0 < ndim <= memviewslice.memview.view.ndim, ( # ndim, memviewslice.memview.view.ndim) result = _memoryviewslice(None, 0, dtype_is_object) result.from_slice = memviewslice __PYX_INC_MEMVIEW(&memviewslice, 1) result.from_object = ( memviewslice.memview).base result.typeinfo = memviewslice.memview.typeinfo result.view = memviewslice.memview.view result.view.buf = memviewslice.data result.view.ndim = ndim (<__pyx_buffer *> &result.view).obj = Py_None Py_INCREF(Py_None) result.flags = PyBUF_RECORDS result.view.shape = result.from_slice.shape result.view.strides = result.from_slice.strides result.view.suboffsets = result.from_slice.suboffsets result.view.len = result.view.itemsize for i in range(ndim): result.view.len *= result.view.shape[i] result.to_object_func = to_object_func result.to_dtype_func = to_dtype_func return result @cname('__pyx_memoryview_get_slice_from_memoryview') cdef {{memviewslice_name}} *get_slice_from_memview(memoryview memview, {{memviewslice_name}} *mslice): cdef _memoryviewslice obj if isinstance(memview, _memoryviewslice): obj = memview return &obj.from_slice else: slice_copy(memview, mslice) return mslice @cname('__pyx_memoryview_slice_copy') cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst): cdef int dim cdef (Py_ssize_t*) shape, strides, suboffsets shape = memview.view.shape strides = memview.view.strides suboffsets = memview.view.suboffsets dst.memview = <__pyx_memoryview *> memview dst.data = memview.view.buf for dim in range(memview.view.ndim): dst.shape[dim] = shape[dim] dst.strides[dim] = strides[dim] if suboffsets == NULL: dst.suboffsets[dim] = -1 else: dst.suboffsets[dim] = suboffsets[dim] @cname('__pyx_memoryview_copy_object') cdef memoryview_copy(memoryview memview): "Create a new memoryview object" cdef {{memviewslice_name}} memviewslice slice_copy(memview, &memviewslice) return memoryview_copy_from_slice(memview, &memviewslice) @cname('__pyx_memoryview_copy_object_from_slice') cdef memoryview_copy_from_slice(memoryview memview, {{memviewslice_name}} *memviewslice): """ Create a new memoryview object from a given memoryview object and slice. """ cdef object (*to_object_func)(char *) cdef int (*to_dtype_func)(char *, object) except 0 if isinstance(memview, _memoryviewslice): to_object_func = (<_memoryviewslice> memview).to_object_func to_dtype_func = (<_memoryviewslice> memview).to_dtype_func else: to_object_func = NULL to_dtype_func = NULL return memoryview_fromslice(memviewslice[0], memview.view.ndim, to_object_func, to_dtype_func, memview.dtype_is_object) # ### Copy the contents of a memoryview slices # cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) nogil: if arg < 0: return -arg else: return arg @cname('__pyx_get_best_slice_order') cdef char get_best_order({{memviewslice_name}} *mslice, int ndim) nogil: """ Figure out the best memory access order for a given slice. """ cdef int i cdef Py_ssize_t c_stride = 0 cdef Py_ssize_t f_stride = 0 for i in range(ndim - 1, -1, -1): if mslice.shape[i] > 1: c_stride = mslice.strides[i] break for i in range(ndim): if mslice.shape[i] > 1: f_stride = mslice.strides[i] break if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride): return 'C' else: return 'F' @cython.cdivision(True) cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides, char *dst_data, Py_ssize_t *dst_strides, Py_ssize_t *src_shape, Py_ssize_t *dst_shape, int ndim, size_t itemsize) nogil: # Note: src_extent is 1 if we're broadcasting # dst_extent always >= src_extent as we don't do reductions cdef Py_ssize_t i cdef Py_ssize_t src_extent = src_shape[0] cdef Py_ssize_t dst_extent = dst_shape[0] cdef Py_ssize_t src_stride = src_strides[0] cdef Py_ssize_t dst_stride = dst_strides[0] if ndim == 1: if (src_stride > 0 and dst_stride > 0 and src_stride == itemsize == dst_stride): memcpy(dst_data, src_data, itemsize * dst_extent) else: for i in range(dst_extent): memcpy(dst_data, src_data, itemsize) src_data += src_stride dst_data += dst_stride else: for i in range(dst_extent): _copy_strided_to_strided(src_data, src_strides + 1, dst_data, dst_strides + 1, src_shape + 1, dst_shape + 1, ndim - 1, itemsize) src_data += src_stride dst_data += dst_stride cdef void copy_strided_to_strided({{memviewslice_name}} *src, {{memviewslice_name}} *dst, int ndim, size_t itemsize) nogil: _copy_strided_to_strided(src.data, src.strides, dst.data, dst.strides, src.shape, dst.shape, ndim, itemsize) @cname('__pyx_memoryview_slice_get_size') cdef Py_ssize_t slice_get_size({{memviewslice_name}} *src, int ndim) nogil: "Return the size of the memory occupied by the slice in number of bytes" cdef int i cdef Py_ssize_t size = src.memview.view.itemsize for i in range(ndim): size *= src.shape[i] return size @cname('__pyx_fill_contig_strides_array') cdef Py_ssize_t fill_contig_strides_array( Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t stride, int ndim, char order) nogil: """ Fill the strides array for a slice with C or F contiguous strides. This is like PyBuffer_FillContiguousStrides, but compatible with py < 2.6 """ cdef int idx if order == 'F': for idx in range(ndim): strides[idx] = stride stride = stride * shape[idx] else: for idx in range(ndim - 1, -1, -1): strides[idx] = stride stride = stride * shape[idx] return stride @cname('__pyx_memoryview_copy_data_to_temp') cdef void *copy_data_to_temp({{memviewslice_name}} *src, {{memviewslice_name}} *tmpslice, char order, int ndim) nogil except NULL: """ Copy a direct slice to temporary contiguous memory. The caller should free the result when done. """ cdef int i cdef void *result cdef size_t itemsize = src.memview.view.itemsize cdef size_t size = slice_get_size(src, ndim) result = malloc(size) if not result: _err(MemoryError, NULL) # tmpslice[0] = src tmpslice.data = result tmpslice.memview = src.memview for i in range(ndim): tmpslice.shape[i] = src.shape[i] tmpslice.suboffsets[i] = -1 fill_contig_strides_array(&tmpslice.shape[0], &tmpslice.strides[0], itemsize, ndim, order) # We need to broadcast strides again for i in range(ndim): if tmpslice.shape[i] == 1: tmpslice.strides[i] = 0 if slice_is_contig(src, order, ndim): memcpy(result, src.data, size) else: copy_strided_to_strided(src, tmpslice, ndim, itemsize) return result # Use 'with gil' functions and avoid 'with gil' blocks, as the code within the blocks # has temporaries that need the GIL to clean up @cname('__pyx_memoryview_err_extents') cdef int _err_extents(int i, Py_ssize_t extent1, Py_ssize_t extent2) except -1 with gil: raise ValueError("got differing extents in dimension %d (got %d and %d)" % (i, extent1, extent2)) @cname('__pyx_memoryview_err_dim') cdef int _err_dim(object error, char *msg, int dim) except -1 with gil: raise error(msg.decode('ascii') % dim) @cname('__pyx_memoryview_err') cdef int _err(object error, char *msg) except -1 with gil: if msg != NULL: raise error(msg.decode('ascii')) else: raise error @cname('__pyx_memoryview_copy_contents') cdef int memoryview_copy_contents({{memviewslice_name}} src, {{memviewslice_name}} dst, int src_ndim, int dst_ndim, bint dtype_is_object) nogil except -1: """ Copy memory from slice src to slice dst. Check for overlapping memory and verify the shapes. """ cdef void *tmpdata = NULL cdef size_t itemsize = src.memview.view.itemsize cdef int i cdef char order = get_best_order(&src, src_ndim) cdef bint broadcasting = False cdef bint direct_copy = False cdef {{memviewslice_name}} tmp if src_ndim < dst_ndim: broadcast_leading(&src, src_ndim, dst_ndim) elif dst_ndim < src_ndim: broadcast_leading(&dst, dst_ndim, src_ndim) cdef int ndim = max(src_ndim, dst_ndim) for i in range(ndim): if src.shape[i] != dst.shape[i]: if src.shape[i] == 1: broadcasting = True src.strides[i] = 0 else: _err_extents(i, dst.shape[i], src.shape[i]) if src.suboffsets[i] >= 0: _err_dim(ValueError, "Dimension %d is not direct", i) if slices_overlap(&src, &dst, ndim, itemsize): # slices overlap, copy to temp, copy temp to dst if not slice_is_contig(&src, order, ndim): order = get_best_order(&dst, ndim) tmpdata = copy_data_to_temp(&src, &tmp, order, ndim) src = tmp if not broadcasting: # See if both slices have equal contiguity, in that case perform a # direct copy. This only works when we are not broadcasting. if slice_is_contig(&src, 'C', ndim): direct_copy = slice_is_contig(&dst, 'C', ndim) elif slice_is_contig(&src, 'F', ndim): direct_copy = slice_is_contig(&dst, 'F', ndim) if direct_copy: # Contiguous slices with same order refcount_copying(&dst, dtype_is_object, ndim, False) memcpy(dst.data, src.data, slice_get_size(&src, ndim)) refcount_copying(&dst, dtype_is_object, ndim, True) free(tmpdata) return 0 if order == 'F' == get_best_order(&dst, ndim): # see if both slices have Fortran order, transpose them to match our # C-style indexing order transpose_memslice(&src) transpose_memslice(&dst) refcount_copying(&dst, dtype_is_object, ndim, False) copy_strided_to_strided(&src, &dst, ndim, itemsize) refcount_copying(&dst, dtype_is_object, ndim, True) free(tmpdata) return 0 @cname('__pyx_memoryview_broadcast_leading') cdef void broadcast_leading({{memviewslice_name}} *slice, int ndim, int ndim_other) nogil: cdef int i cdef int offset = ndim_other - ndim for i in range(ndim - 1, -1, -1): slice.shape[i + offset] = slice.shape[i] slice.strides[i + offset] = slice.strides[i] slice.suboffsets[i + offset] = slice.suboffsets[i] for i in range(offset): slice.shape[i] = 1 slice.strides[i] = slice.strides[0] slice.suboffsets[i] = -1 # ### Take care of refcounting the objects in slices. Do this seperately from any copying, ### to minimize acquiring the GIL # @cname('__pyx_memoryview_refcount_copying') cdef void refcount_copying({{memviewslice_name}} *dst, bint dtype_is_object, int ndim, bint inc) nogil: # incref or decref the objects in the destination slice if the dtype is # object if dtype_is_object: refcount_objects_in_slice_with_gil(dst.data, dst.shape, dst.strides, ndim, inc) @cname('__pyx_memoryview_refcount_objects_in_slice_with_gil') cdef void refcount_objects_in_slice_with_gil(char *data, Py_ssize_t *shape, Py_ssize_t *strides, int ndim, bint inc) with gil: refcount_objects_in_slice(data, shape, strides, ndim, inc) @cname('__pyx_memoryview_refcount_objects_in_slice') cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape, Py_ssize_t *strides, int ndim, bint inc): cdef Py_ssize_t i for i in range(shape[0]): if ndim == 1: if inc: Py_INCREF(( data)[0]) else: Py_DECREF(( data)[0]) else: refcount_objects_in_slice(data, shape + 1, strides + 1, ndim - 1, inc) data += strides[0] # ### Scalar to slice assignment # @cname('__pyx_memoryview_slice_assign_scalar') cdef void slice_assign_scalar({{memviewslice_name}} *dst, int ndim, size_t itemsize, void *item, bint dtype_is_object) nogil: refcount_copying(dst, dtype_is_object, ndim, False) _slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, itemsize, item) refcount_copying(dst, dtype_is_object, ndim, True) @cname('__pyx_memoryview__slice_assign_scalar') cdef void _slice_assign_scalar(char *data, Py_ssize_t *shape, Py_ssize_t *strides, int ndim, size_t itemsize, void *item) nogil: cdef Py_ssize_t i cdef Py_ssize_t stride = strides[0] cdef Py_ssize_t extent = shape[0] if ndim == 1: for i in range(extent): memcpy(data, item, itemsize) data += stride else: for i in range(extent): _slice_assign_scalar(data, shape + 1, strides + 1, ndim - 1, itemsize, item) data += stride ############### BufferFormatFromTypeInfo ############### cdef extern from *: ctypedef struct __Pyx_StructField cdef enum: __PYX_BUF_FLAGS_PACKED_STRUCT __PYX_BUF_FLAGS_INTEGER_COMPLEX ctypedef struct __Pyx_TypeInfo: char* name __Pyx_StructField* fields size_t size size_t arraysize[8] int ndim char typegroup char is_unsigned int flags ctypedef struct __Pyx_StructField: __Pyx_TypeInfo* type char* name size_t offset ctypedef struct __Pyx_BufFmt_StackElem: __Pyx_StructField* field size_t parent_offset #ctypedef struct __Pyx_BufFmt_Context: # __Pyx_StructField root __Pyx_BufFmt_StackElem* head struct __pyx_typeinfo_string: char string[3] __pyx_typeinfo_string __Pyx_TypeInfoToFormat(__Pyx_TypeInfo *) @cname('__pyx_format_from_typeinfo') cdef bytes format_from_typeinfo(__Pyx_TypeInfo *type): cdef __Pyx_StructField *field cdef __pyx_typeinfo_string fmt cdef bytes part, result if type.typegroup == 'S': assert type.fields != NULL and type.fields.type != NULL if type.flags & __PYX_BUF_FLAGS_PACKED_STRUCT: alignment = b'^' else: alignment = b'' parts = [b"T{"] field = type.fields while field.type: part = format_from_typeinfo(field.type) parts.append(part + b':' + field.name + b':') field += 1 result = alignment.join(parts) + b'}' else: fmt = __Pyx_TypeInfoToFormat(type) if type.arraysize[0]: extents = [unicode(type.arraysize[i]) for i in range(type.ndim)] result = (u"(%s)" % u','.join(extents)).encode('ascii') + fmt.string else: result = fmt.string return result cython-0.20.1+git90-g0e6e38e/Cython/Utility/MemoryView_C.c000066400000000000000000000675061231323242300227030ustar00rootroot00000000000000////////// MemviewSliceStruct.proto ////////// /* memoryview slice struct */ struct {{memview_struct_name}}; typedef struct { struct {{memview_struct_name}} *memview; char *data; Py_ssize_t shape[{{max_dims}}]; Py_ssize_t strides[{{max_dims}}]; Py_ssize_t suboffsets[{{max_dims}}]; } {{memviewslice_name}}; /////////// Atomics.proto ///////////// #include #ifndef CYTHON_ATOMICS #define CYTHON_ATOMICS 1 #endif #define __pyx_atomic_int_type int // todo: Portland pgcc, maybe OS X's OSAtomicIncrement32, // libatomic + autotools-like distutils support? Such a pain... #if CYTHON_ATOMICS && __GNUC__ >= 4 && (__GNUC_MINOR__ > 1 || \ (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL >= 2)) && \ !defined(__i386__) /* gcc >= 4.1.2 */ #define __pyx_atomic_incr_aligned(value, lock) __sync_fetch_and_add(value, 1) #define __pyx_atomic_decr_aligned(value, lock) __sync_fetch_and_sub(value, 1) #ifdef __PYX_DEBUG_ATOMICS #warning "Using GNU atomics" #endif #elif CYTHON_ATOMICS && MSC_VER /* msvc */ #include #define __pyx_atomic_int_type LONG #define __pyx_atomic_incr_aligned(value, lock) InterlockedIncrement(value) #define __pyx_atomic_decr_aligned(value, lock) InterlockedDecrement(value) #ifdef __PYX_DEBUG_ATOMICS #warning "Using MSVC atomics" #endif #elif CYTHON_ATOMICS && (defined(__ICC) || defined(__INTEL_COMPILER)) && 0 #define __pyx_atomic_incr_aligned(value, lock) _InterlockedIncrement(value) #define __pyx_atomic_decr_aligned(value, lock) _InterlockedDecrement(value) #ifdef __PYX_DEBUG_ATOMICS #warning "Using Intel atomics" #endif #else #undef CYTHON_ATOMICS #define CYTHON_ATOMICS 0 #ifdef __PYX_DEBUG_ATOMICS #warning "Not using atomics" #endif #endif typedef volatile __pyx_atomic_int_type __pyx_atomic_int; #if CYTHON_ATOMICS #define __pyx_add_acquisition_count(memview) \ __pyx_atomic_incr_aligned(__pyx_get_slice_count_pointer(memview), memview->lock) #define __pyx_sub_acquisition_count(memview) \ __pyx_atomic_decr_aligned(__pyx_get_slice_count_pointer(memview), memview->lock) #else #define __pyx_add_acquisition_count(memview) \ __pyx_add_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) #define __pyx_sub_acquisition_count(memview) \ __pyx_sub_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) #endif /////////////// ObjectToMemviewSlice.proto /////////////// static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *); ////////// MemviewSliceInit.proto ////////// #define __Pyx_BUF_MAX_NDIMS %(BUF_MAX_NDIMS)d #define __Pyx_MEMVIEW_DIRECT 1 #define __Pyx_MEMVIEW_PTR 2 #define __Pyx_MEMVIEW_FULL 4 #define __Pyx_MEMVIEW_CONTIG 8 #define __Pyx_MEMVIEW_STRIDED 16 #define __Pyx_MEMVIEW_FOLLOW 32 #define __Pyx_IS_C_CONTIG 1 #define __Pyx_IS_F_CONTIG 2 static int __Pyx_init_memviewslice( struct __pyx_memoryview_obj *memview, int ndim, __Pyx_memviewslice *memviewslice, int memview_is_new_reference); static CYTHON_INLINE int __pyx_add_acquisition_count_locked( __pyx_atomic_int *acquisition_count, PyThread_type_lock lock); static CYTHON_INLINE int __pyx_sub_acquisition_count_locked( __pyx_atomic_int *acquisition_count, PyThread_type_lock lock); #define __pyx_get_slice_count_pointer(memview) (memview->acquisition_count_aligned_p) #define __pyx_get_slice_count(memview) (*__pyx_get_slice_count_pointer(memview)) #define __PYX_INC_MEMVIEW(slice, have_gil) __Pyx_INC_MEMVIEW(slice, have_gil, __LINE__) #define __PYX_XDEC_MEMVIEW(slice, have_gil) __Pyx_XDEC_MEMVIEW(slice, have_gil, __LINE__) static CYTHON_INLINE void __Pyx_INC_MEMVIEW({{memviewslice_name}} *, int, int); static CYTHON_INLINE void __Pyx_XDEC_MEMVIEW({{memviewslice_name}} *, int, int); /////////////// MemviewSliceIndex.proto /////////////// static CYTHON_INLINE char *__pyx_memviewslice_index_full( const char *bufp, Py_ssize_t idx, Py_ssize_t stride, Py_ssize_t suboffset); /////////////// ObjectToMemviewSlice /////////////// //@requires: MemviewSliceValidateAndInit static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *obj) { {{memviewslice_name}} result = {{memslice_init}}; __Pyx_BufFmt_StackElem stack[{{struct_nesting_depth}}]; int axes_specs[] = { {{axes_specs}} }; int retcode; if (obj == Py_None) { /* We don't bother to refcount None */ result.memview = (struct __pyx_memoryview_obj *) Py_None; return result; } retcode = __Pyx_ValidateAndInit_memviewslice(axes_specs, {{c_or_f_flag}}, {{buf_flag}}, {{ndim}}, &{{dtype_typeinfo}}, stack, &result, obj); if (unlikely(retcode == -1)) goto __pyx_fail; return result; __pyx_fail: result.memview = NULL; result.data = NULL; return result; } /////////////// MemviewSliceValidateAndInit.proto /////////////// static int __Pyx_ValidateAndInit_memviewslice( int *axes_specs, int c_or_f_flag, int buf_flags, int ndim, __Pyx_TypeInfo *dtype, __Pyx_BufFmt_StackElem stack[], __Pyx_memviewslice *memviewslice, PyObject *original_obj); /////////////// MemviewSliceValidateAndInit /////////////// //@requires: Buffer.c::TypeInfoCompare static int __pyx_check_strides(Py_buffer *buf, int dim, int ndim, int spec) { if (buf->shape[dim] <= 1) return 1; if (buf->strides) { if (spec & __Pyx_MEMVIEW_CONTIG) { if (spec & (__Pyx_MEMVIEW_PTR|__Pyx_MEMVIEW_FULL)) { if (buf->strides[dim] != sizeof(void *)) { PyErr_Format(PyExc_ValueError, "Buffer is not indirectly contiguous " "in dimension %d.", dim); goto fail; } } else if (buf->strides[dim] != buf->itemsize) { PyErr_SetString(PyExc_ValueError, "Buffer and memoryview are not contiguous " "in the same dimension."); goto fail; } } if (spec & __Pyx_MEMVIEW_FOLLOW) { Py_ssize_t stride = buf->strides[dim]; if (stride < 0) stride = -stride; if (stride < buf->itemsize) { PyErr_SetString(PyExc_ValueError, "Buffer and memoryview are not contiguous " "in the same dimension."); goto fail; } } } else { if (spec & __Pyx_MEMVIEW_CONTIG && dim != ndim - 1) { PyErr_Format(PyExc_ValueError, "C-contiguous buffer is not contiguous in " "dimension %d", dim); goto fail; } else if (spec & (__Pyx_MEMVIEW_PTR)) { PyErr_Format(PyExc_ValueError, "C-contiguous buffer is not indirect in " "dimension %d", dim); goto fail; } else if (buf->suboffsets) { PyErr_SetString(PyExc_ValueError, "Buffer exposes suboffsets but no strides"); goto fail; } } return 1; fail: return 0; } static int __pyx_check_suboffsets(Py_buffer *buf, int dim, CYTHON_UNUSED int ndim, int spec) { // Todo: without PyBUF_INDIRECT we may not have suboffset information, i.e., the // ptr may not be set to NULL but may be uninitialized? if (spec & __Pyx_MEMVIEW_DIRECT) { if (buf->suboffsets && buf->suboffsets[dim] >= 0) { PyErr_Format(PyExc_ValueError, "Buffer not compatible with direct access " "in dimension %d.", dim); goto fail; } } if (spec & __Pyx_MEMVIEW_PTR) { if (!buf->suboffsets || (buf->suboffsets && buf->suboffsets[dim] < 0)) { PyErr_Format(PyExc_ValueError, "Buffer is not indirectly accessible " "in dimension %d.", dim); goto fail; } } return 1; fail: return 0; } static int __pyx_verify_contig(Py_buffer *buf, int ndim, int c_or_f_flag) { int i; if (c_or_f_flag & __Pyx_IS_F_CONTIG) { Py_ssize_t stride = 1; for (i = 0; i < ndim; i++) { if (stride * buf->itemsize != buf->strides[i] && buf->shape[i] > 1) { PyErr_SetString(PyExc_ValueError, "Buffer not fortran contiguous."); goto fail; } stride = stride * buf->shape[i]; } } else if (c_or_f_flag & __Pyx_IS_C_CONTIG) { Py_ssize_t stride = 1; for (i = ndim - 1; i >- 1; i--) { if (stride * buf->itemsize != buf->strides[i] && buf->shape[i] > 1) { PyErr_SetString(PyExc_ValueError, "Buffer not C contiguous."); goto fail; } stride = stride * buf->shape[i]; } } return 1; fail: return 0; } static int __Pyx_ValidateAndInit_memviewslice( int *axes_specs, int c_or_f_flag, int buf_flags, int ndim, __Pyx_TypeInfo *dtype, __Pyx_BufFmt_StackElem stack[], __Pyx_memviewslice *memviewslice, PyObject *original_obj) { struct __pyx_memoryview_obj *memview, *new_memview; __Pyx_RefNannyDeclarations Py_buffer *buf; int i, spec = 0, retval = -1; __Pyx_BufFmt_Context ctx; int from_memoryview = __pyx_memoryview_check(original_obj); __Pyx_RefNannySetupContext("ValidateAndInit_memviewslice", 0); if (from_memoryview && __pyx_typeinfo_cmp(dtype, ((struct __pyx_memoryview_obj *) original_obj)->typeinfo)) { /* We have a matching dtype, skip format parsing */ memview = (struct __pyx_memoryview_obj *) original_obj; new_memview = NULL; } else { memview = (struct __pyx_memoryview_obj *) __pyx_memoryview_new( original_obj, buf_flags, 0, dtype); new_memview = memview; if (unlikely(!memview)) goto fail; } buf = &memview->view; if (buf->ndim != ndim) { PyErr_Format(PyExc_ValueError, "Buffer has wrong number of dimensions (expected %d, got %d)", ndim, buf->ndim); goto fail; } if (new_memview) { __Pyx_BufFmt_Init(&ctx, stack, dtype); if (!__Pyx_BufFmt_CheckString(&ctx, buf->format)) goto fail; } if ((unsigned) buf->itemsize != dtype->size) { PyErr_Format(PyExc_ValueError, "Item size of buffer (%" CYTHON_FORMAT_SSIZE_T "u byte%s) " "does not match size of '%s' (%" CYTHON_FORMAT_SSIZE_T "u byte%s)", buf->itemsize, (buf->itemsize > 1) ? "s" : "", dtype->name, dtype->size, (dtype->size > 1) ? "s" : ""); goto fail; } /* Check axes */ for (i = 0; i < ndim; i++) { spec = axes_specs[i]; if (!__pyx_check_strides(buf, i, ndim, spec)) goto fail; if (!__pyx_check_suboffsets(buf, i, ndim, spec)) goto fail; } /* Check contiguity */ if (buf->strides && !__pyx_verify_contig(buf, ndim, c_or_f_flag)) goto fail; /* Initialize */ if (unlikely(__Pyx_init_memviewslice(memview, ndim, memviewslice, new_memview != NULL) == -1)) { goto fail; } retval = 0; goto no_fail; fail: Py_XDECREF(new_memview); retval = -1; no_fail: __Pyx_RefNannyFinishContext(); return retval; } ////////// MemviewSliceInit ////////// static int __Pyx_init_memviewslice(struct __pyx_memoryview_obj *memview, int ndim, {{memviewslice_name}} *memviewslice, int memview_is_new_reference) { __Pyx_RefNannyDeclarations int i, retval=-1; Py_buffer *buf = &memview->view; __Pyx_RefNannySetupContext("init_memviewslice", 0); if (!buf) { PyErr_SetString(PyExc_ValueError, "buf is NULL."); goto fail; } else if (memviewslice->memview || memviewslice->data) { PyErr_SetString(PyExc_ValueError, "memviewslice is already initialized!"); goto fail; } if (buf->strides) { for (i = 0; i < ndim; i++) { memviewslice->strides[i] = buf->strides[i]; } } else { Py_ssize_t stride = buf->itemsize; for (i = ndim - 1; i >= 0; i--) { memviewslice->strides[i] = stride; stride *= buf->shape[i]; } } for (i = 0; i < ndim; i++) { memviewslice->shape[i] = buf->shape[i]; if (buf->suboffsets) { memviewslice->suboffsets[i] = buf->suboffsets[i]; } else { memviewslice->suboffsets[i] = -1; } } memviewslice->memview = memview; memviewslice->data = (char *)buf->buf; if (__pyx_add_acquisition_count(memview) == 0 && !memview_is_new_reference) { Py_INCREF(memview); } retval = 0; goto no_fail; fail: /* Don't decref, the memoryview may be borrowed. Let the caller do the cleanup */ /* __Pyx_XDECREF(memviewslice->memview); */ memviewslice->memview = 0; memviewslice->data = 0; retval = -1; no_fail: __Pyx_RefNannyFinishContext(); return retval; } static CYTHON_INLINE void __pyx_fatalerror(const char *fmt, ...) { va_list vargs; char msg[200]; va_start(vargs, fmt); #ifdef HAVE_STDARG_PROTOTYPES va_start(vargs, fmt); #else va_start(vargs); #endif vsnprintf(msg, 200, fmt, vargs); Py_FatalError(msg); va_end(vargs); } static CYTHON_INLINE int __pyx_add_acquisition_count_locked(__pyx_atomic_int *acquisition_count, PyThread_type_lock lock) { int result; PyThread_acquire_lock(lock, 1); result = (*acquisition_count)++; PyThread_release_lock(lock); return result; } static CYTHON_INLINE int __pyx_sub_acquisition_count_locked(__pyx_atomic_int *acquisition_count, PyThread_type_lock lock) { int result; PyThread_acquire_lock(lock, 1); result = (*acquisition_count)--; PyThread_release_lock(lock); return result; } static CYTHON_INLINE void __Pyx_INC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil, int lineno) { int first_time; struct {{memview_struct_name}} *memview = memslice->memview; if (!memview || (PyObject *) memview == Py_None) return; /* allow uninitialized memoryview assignment */ if (__pyx_get_slice_count(memview) < 0) __pyx_fatalerror("Acquisition count is %d (line %d)", __pyx_get_slice_count(memview), lineno); first_time = __pyx_add_acquisition_count(memview) == 0; if (first_time) { if (have_gil) { Py_INCREF((PyObject *) memview); } else { PyGILState_STATE _gilstate = PyGILState_Ensure(); Py_INCREF((PyObject *) memview); PyGILState_Release(_gilstate); } } } static CYTHON_INLINE void __Pyx_XDEC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil, int lineno) { int last_time; struct {{memview_struct_name}} *memview = memslice->memview; if (!memview ) { return; } else if ((PyObject *) memview == Py_None) { memslice->memview = NULL; return; } if (__pyx_get_slice_count(memview) <= 0) __pyx_fatalerror("Acquisition count is %d (line %d)", __pyx_get_slice_count(memview), lineno); last_time = __pyx_sub_acquisition_count(memview) == 1; memslice->data = NULL; if (last_time) { if (have_gil) { Py_CLEAR(memslice->memview); } else { PyGILState_STATE _gilstate = PyGILState_Ensure(); Py_CLEAR(memslice->memview); PyGILState_Release(_gilstate); } } else { memslice->memview = NULL; } } ////////// MemviewSliceCopyTemplate.proto ////////// static {{memviewslice_name}} __pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs, const char *mode, int ndim, size_t sizeof_dtype, int contig_flag, int dtype_is_object); ////////// MemviewSliceCopyTemplate ////////// static {{memviewslice_name}} __pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs, const char *mode, int ndim, size_t sizeof_dtype, int contig_flag, int dtype_is_object) { __Pyx_RefNannyDeclarations int i; __Pyx_memviewslice new_mvs = {{memslice_init}}; struct __pyx_memoryview_obj *from_memview = from_mvs->memview; Py_buffer *buf = &from_memview->view; PyObject *shape_tuple = NULL; PyObject *temp_int = NULL; struct __pyx_array_obj *array_obj = NULL; struct __pyx_memoryview_obj *memview_obj = NULL; __Pyx_RefNannySetupContext("__pyx_memoryview_copy_new_contig", 0); for (i = 0; i < ndim; i++) { if (from_mvs->suboffsets[i] >= 0) { PyErr_Format(PyExc_ValueError, "Cannot copy memoryview slice with " "indirect dimensions (axis %d)", i); goto fail; } } shape_tuple = PyTuple_New(ndim); if (unlikely(!shape_tuple)) { goto fail; } __Pyx_GOTREF(shape_tuple); for(i = 0; i < ndim; i++) { temp_int = PyInt_FromSsize_t(from_mvs->shape[i]); if(unlikely(!temp_int)) { goto fail; } else { PyTuple_SET_ITEM(shape_tuple, i, temp_int); temp_int = NULL; } } array_obj = __pyx_array_new(shape_tuple, sizeof_dtype, buf->format, (char *) mode, NULL); if (unlikely(!array_obj)) { goto fail; } __Pyx_GOTREF(array_obj); memview_obj = (struct __pyx_memoryview_obj *) __pyx_memoryview_new( (PyObject *) array_obj, contig_flag, dtype_is_object, from_mvs->memview->typeinfo); if (unlikely(!memview_obj)) goto fail; /* initialize new_mvs */ if (unlikely(__Pyx_init_memviewslice(memview_obj, ndim, &new_mvs, 1) < 0)) goto fail; if (unlikely(__pyx_memoryview_copy_contents(*from_mvs, new_mvs, ndim, ndim, dtype_is_object) < 0)) goto fail; goto no_fail; fail: __Pyx_XDECREF(new_mvs.memview); new_mvs.memview = NULL; new_mvs.data = NULL; no_fail: __Pyx_XDECREF(shape_tuple); __Pyx_XDECREF(temp_int); __Pyx_XDECREF(array_obj); __Pyx_RefNannyFinishContext(); return new_mvs; } ////////// CopyContentsUtility.proto ///////// #define {{func_cname}}(slice) \ __pyx_memoryview_copy_new_contig(&slice, "{{mode}}", {{ndim}}, \ sizeof({{dtype_decl}}), {{contig_flag}}, \ {{dtype_is_object}}) ////////// OverlappingSlices.proto ////////// static int __pyx_slices_overlap({{memviewslice_name}} *slice1, {{memviewslice_name}} *slice2, int ndim, size_t itemsize); ////////// OverlappingSlices ////////// /* Based on numpy's core/src/multiarray/array_assign.c */ /* Gets a half-open range [start, end) which contains the array data */ static void __pyx_get_array_memory_extents({{memviewslice_name}} *slice, void **out_start, void **out_end, int ndim, size_t itemsize) { char *start, *end; int i; start = end = slice->data; for (i = 0; i < ndim; i++) { Py_ssize_t stride = slice->strides[i]; Py_ssize_t extent = slice->shape[i]; if (extent == 0) { *out_start = *out_end = start; return; } else { if (stride > 0) end += stride * (extent - 1); else start += stride * (extent - 1); } } /* Return a half-open range */ *out_start = start; *out_end = end + itemsize; } /* Returns 1 if the arrays have overlapping data, 0 otherwise */ static int __pyx_slices_overlap({{memviewslice_name}} *slice1, {{memviewslice_name}} *slice2, int ndim, size_t itemsize) { void *start1, *end1, *start2, *end2; __pyx_get_array_memory_extents(slice1, &start1, &end1, ndim, itemsize); __pyx_get_array_memory_extents(slice2, &start2, &end2, ndim, itemsize); return (start1 < end2) && (start2 < end1); } ////////// MemviewSliceIsCContig.proto ////////// #define __pyx_memviewslice_is_c_contig{{ndim}}(slice) \ __pyx_memviewslice_is_contig(&slice, 'C', {{ndim}}) ////////// MemviewSliceIsFContig.proto ////////// #define __pyx_memviewslice_is_f_contig{{ndim}}(slice) \ __pyx_memviewslice_is_contig(&slice, 'F', {{ndim}}) ////////// MemviewSliceIsContig.proto ////////// static int __pyx_memviewslice_is_contig(const {{memviewslice_name}} *mvs, char order, int ndim); ////////// MemviewSliceIsContig ////////// static int __pyx_memviewslice_is_contig(const {{memviewslice_name}} *mvs, char order, int ndim) { int i, index, step, start; Py_ssize_t itemsize = mvs->memview->view.itemsize; if (order == 'F') { step = 1; start = 0; } else { step = -1; start = ndim - 1; } for (i = 0; i < ndim; i++) { index = start + step * i; if (mvs->suboffsets[index] >= 0 || mvs->strides[index] != itemsize) return 0; itemsize *= mvs->shape[index]; } return 1; } /////////////// MemviewSliceIndex /////////////// static CYTHON_INLINE char * __pyx_memviewslice_index_full(const char *bufp, Py_ssize_t idx, Py_ssize_t stride, Py_ssize_t suboffset) { bufp = bufp + idx * stride; if (suboffset >= 0) { bufp = *((char **) bufp) + suboffset; } return (char *) bufp; } /////////////// MemviewDtypeToObject.proto /////////////// {{if to_py_function}} static PyObject *{{get_function}}(const char *itemp); /* proto */ {{endif}} {{if from_py_function}} static int {{set_function}}(const char *itemp, PyObject *obj); /* proto */ {{endif}} /////////////// MemviewDtypeToObject /////////////// {{#__pyx_memview__to_object}} /* Convert a dtype to or from a Python object */ {{if to_py_function}} static PyObject *{{get_function}}(const char *itemp) { return (PyObject *) {{to_py_function}}(*({{dtype}} *) itemp); } {{endif}} {{if from_py_function}} static int {{set_function}}(const char *itemp, PyObject *obj) { {{dtype}} value = {{from_py_function}}(obj); if ({{error_condition}}) return 0; *({{dtype}} *) itemp = value; return 1; } {{endif}} /////////////// MemviewObjectToObject.proto /////////////// /* Function callbacks (for memoryview object) for dtype object */ static PyObject *{{get_function}}(const char *itemp); /* proto */ static int {{set_function}}(const char *itemp, PyObject *obj); /* proto */ /////////////// MemviewObjectToObject /////////////// static PyObject *{{get_function}}(const char *itemp) { PyObject *result = *(PyObject **) itemp; Py_INCREF(result); return result; } static int {{set_function}}(const char *itemp, PyObject *obj) { Py_INCREF(obj); Py_DECREF(*(PyObject **) itemp); *(PyObject **) itemp = obj; return 1; } /////////// ToughSlice ////////// /* Dimension is indexed with 'start:stop:step' */ if (unlikely(__pyx_memoryview_slice_memviewslice( &{{dst}}, {{src}}.shape[{{dim}}], {{src}}.strides[{{dim}}], {{src}}.suboffsets[{{dim}}], {{dim}}, {{new_ndim}}, &{{suboffset_dim}}, {{start}}, {{stop}}, {{step}}, {{int(have_start)}}, {{int(have_stop)}}, {{int(have_step)}}, 1) < 0)) { {{error_goto}} } ////////// SimpleSlice ////////// /* Dimension is indexed with ':' only */ {{dst}}.shape[{{new_ndim}}] = {{src}}.shape[{{dim}}]; {{dst}}.strides[{{new_ndim}}] = {{src}}.strides[{{dim}}]; {{if access == 'direct'}} {{dst}}.suboffsets[{{new_ndim}}] = -1; {{else}} {{dst}}.suboffsets[{{new_ndim}}] = {{src}}.suboffsets[{{dim}}]; if ({{src}}.suboffsets[{{dim}}] >= 0) {{suboffset_dim}} = {{new_ndim}}; {{endif}} ////////// SliceIndex ////////// // Dimension is indexed with an integer, we could use the ToughSlice // approach, but this is faster { Py_ssize_t __pyx_tmp_idx = {{idx}}; Py_ssize_t __pyx_tmp_shape = {{src}}.shape[{{dim}}]; Py_ssize_t __pyx_tmp_stride = {{src}}.strides[{{dim}}]; if ({{wraparound}} && (__pyx_tmp_idx < 0)) __pyx_tmp_idx += __pyx_tmp_shape; if ({{boundscheck}} && (__pyx_tmp_idx < 0 || __pyx_tmp_idx >= __pyx_tmp_shape)) { {{if not have_gil}} #ifdef WITH_THREAD PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure(); #endif {{endif}} PyErr_SetString(PyExc_IndexError, "Index out of bounds (axis {{dim}})"); {{if not have_gil}} #ifdef WITH_THREAD PyGILState_Release(__pyx_gilstate_save); #endif {{endif}} {{error_goto}} } {{if all_dimensions_direct}} {{dst}}.data += __pyx_tmp_idx * __pyx_tmp_stride; {{else}} if ({{suboffset_dim}} < 0) { {{dst}}.data += __pyx_tmp_idx * __pyx_tmp_stride; /* This dimension is the first dimension, or is preceded by */ /* direct or indirect dimensions that are indexed away. */ /* Hence suboffset_dim must be less than zero, and we can have */ /* our data pointer refer to another block by dereferencing. */ /* slice.data -> B -> C becomes slice.data -> C */ {{if indirect}} { Py_ssize_t __pyx_tmp_suboffset = {{src}}.suboffsets[{{dim}}]; {{if generic}} if (__pyx_tmp_suboffset >= 0) {{endif}} {{dst}}.data = *((char **) {{dst}}.data) + __pyx_tmp_suboffset; } {{endif}} } else { {{dst}}.suboffsets[{{suboffset_dim}}] += __pyx_tmp_idx * __pyx_tmp_stride; /* Note: dimension can not be indirect, the compiler will have */ /* issued an error */ } {{endif}} } ////////// FillStrided1DScalar.proto ////////// static void __pyx_fill_slice_{{dtype_name}}({{type_decl}} *p, Py_ssize_t extent, Py_ssize_t stride, size_t itemsize, void *itemp); ////////// FillStrided1DScalar ////////// /* Fill a slice with a scalar value. The dimension is direct and strided or contiguous */ /* This can be used as a callback for the memoryview object to efficienty assign a scalar */ /* Currently unused */ static void __pyx_fill_slice_{{dtype_name}}({{type_decl}} *p, Py_ssize_t extent, Py_ssize_t stride, size_t itemsize, void *itemp) { Py_ssize_t i; {{type_decl}} item = *(({{type_decl}} *) itemp); {{type_decl}} *endp; stride /= sizeof({{type_decl}}); endp = p + stride * extent; while (p < endp) { *p = item; p += stride; } } cython-0.20.1+git90-g0e6e38e/Cython/Utility/ModuleSetupCode.c000066400000000000000000000611751231323242300233730ustar00rootroot00000000000000/////////////// CModulePreamble /////////////// #include /* For offsetof */ #ifndef offsetof #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) #endif #if !defined(WIN32) && !defined(MS_WINDOWS) #ifndef __stdcall #define __stdcall #endif #ifndef __cdecl #define __cdecl #endif #ifndef __fastcall #define __fastcall #endif #endif #ifndef DL_IMPORT #define DL_IMPORT(t) t #endif #ifndef DL_EXPORT #define DL_EXPORT(t) t #endif #ifndef PY_LONG_LONG #define PY_LONG_LONG LONG_LONG #endif #ifndef Py_HUGE_VAL #define Py_HUGE_VAL HUGE_VAL #endif #ifdef PYPY_VERSION #define CYTHON_COMPILING_IN_PYPY 1 #define CYTHON_COMPILING_IN_CPYTHON 0 #else #define CYTHON_COMPILING_IN_PYPY 0 #define CYTHON_COMPILING_IN_CPYTHON 1 #endif #if CYTHON_COMPILING_IN_PYPY #define Py_OptimizeFlag 0 #endif #if PY_VERSION_HEX < 0x02050000 typedef int Py_ssize_t; #define PY_SSIZE_T_MAX INT_MAX #define PY_SSIZE_T_MIN INT_MIN #define PY_FORMAT_SIZE_T "" #define CYTHON_FORMAT_SSIZE_T "" #define PyInt_FromSsize_t(z) PyInt_FromLong(z) #define PyInt_AsSsize_t(o) __Pyx_PyInt_As_int(o) #define PyNumber_Index(o) ((PyNumber_Check(o) && !PyFloat_Check(o)) ? PyNumber_Int(o) : \ (PyErr_Format(PyExc_TypeError, \ "expected index value, got %.200s", Py_TYPE(o)->tp_name), \ (PyObject*)0)) #define __Pyx_PyIndex_Check(o) (PyNumber_Check(o) && !PyFloat_Check(o) && \ !PyComplex_Check(o)) #define PyIndex_Check __Pyx_PyIndex_Check #define PyErr_WarnEx(category, message, stacklevel) PyErr_Warn(category, message) #define __PYX_BUILD_PY_SSIZE_T "i" #else #define __PYX_BUILD_PY_SSIZE_T "n" #define CYTHON_FORMAT_SSIZE_T "z" #define __Pyx_PyIndex_Check PyIndex_Check #endif #if PY_VERSION_HEX < 0x02060000 #define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) #define PyVarObject_HEAD_INIT(type, size) \ PyObject_HEAD_INIT(type) size, #define PyType_Modified(t) typedef struct { void *buf; PyObject *obj; Py_ssize_t len; Py_ssize_t itemsize; int readonly; int ndim; char *format; Py_ssize_t *shape; Py_ssize_t *strides; Py_ssize_t *suboffsets; void *internal; } Py_buffer; #define PyBUF_SIMPLE 0 #define PyBUF_WRITABLE 0x0001 #define PyBUF_FORMAT 0x0004 #define PyBUF_ND 0x0008 #define PyBUF_STRIDES (0x0010 | PyBUF_ND) #define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) #define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) #define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) #define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) #define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_FORMAT | PyBUF_WRITABLE) #define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_FORMAT | PyBUF_WRITABLE) typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); typedef void (*releasebufferproc)(PyObject *, Py_buffer *); #endif #if PY_MAJOR_VERSION < 3 #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \ PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) #define __Pyx_DefaultClassType PyClass_Type #else #define __Pyx_BUILTIN_MODULE_NAME "builtins" #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \ PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) #define __Pyx_DefaultClassType PyType_Type #endif #if PY_VERSION_HEX < 0x02060000 #define PyUnicode_FromString(s) PyUnicode_Decode(s, strlen(s), "UTF-8", "strict") #endif #if PY_MAJOR_VERSION >= 3 #define Py_TPFLAGS_CHECKTYPES 0 #define Py_TPFLAGS_HAVE_INDEX 0 #endif #if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3) #define Py_TPFLAGS_HAVE_NEWBUFFER 0 #endif #if PY_VERSION_HEX < 0x02060000 #define Py_TPFLAGS_HAVE_VERSION_TAG 0 #endif #if PY_VERSION_HEX < 0x02060000 && !defined(Py_TPFLAGS_IS_ABSTRACT) #define Py_TPFLAGS_IS_ABSTRACT 0 #endif #if PY_VERSION_HEX < 0x030400a1 && !defined(Py_TPFLAGS_HAVE_FINALIZE) #define Py_TPFLAGS_HAVE_FINALIZE 0 #endif /* new Py3.3 unicode type (PEP 393) */ #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) #define CYTHON_PEP393_ENABLED 1 #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ? \ 0 : _PyUnicode_Ready((PyObject *)(op))) #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) #define __Pyx_PyUnicode_KIND(u) PyUnicode_KIND(u) #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) #else #define CYTHON_PEP393_ENABLED 0 #define __Pyx_PyUnicode_READY(op) (0) #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) #define __Pyx_PyUnicode_KIND(u) (sizeof(Py_UNICODE)) #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) /* (void)(k) => avoid unused variable warning due to macro: */ #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) #endif #if CYTHON_COMPILING_IN_PYPY #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) #else #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ? \ PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) #endif #define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) #define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) #if PY_MAJOR_VERSION >= 3 #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) #else #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) #endif #if PY_MAJOR_VERSION >= 3 #define PyBaseString_Type PyUnicode_Type #define PyStringObject PyUnicodeObject #define PyString_Type PyUnicode_Type #define PyString_Check PyUnicode_Check #define PyString_CheckExact PyUnicode_CheckExact #endif #if PY_VERSION_HEX < 0x02060000 #define PyBytesObject PyStringObject #define PyBytes_Type PyString_Type #define PyBytes_Check PyString_Check #define PyBytes_CheckExact PyString_CheckExact #define PyBytes_FromString PyString_FromString #define PyBytes_FromStringAndSize PyString_FromStringAndSize #define PyBytes_FromFormat PyString_FromFormat #define PyBytes_DecodeEscape PyString_DecodeEscape #define PyBytes_AsString PyString_AsString #define PyBytes_AsStringAndSize PyString_AsStringAndSize #define PyBytes_Size PyString_Size #define PyBytes_AS_STRING PyString_AS_STRING #define PyBytes_GET_SIZE PyString_GET_SIZE #define PyBytes_Repr PyString_Repr #define PyBytes_Concat PyString_Concat #define PyBytes_ConcatAndDel PyString_ConcatAndDel #endif #if PY_MAJOR_VERSION >= 3 #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) #else #define __Pyx_PyBaseString_Check(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj) || \ PyString_Check(obj) || PyUnicode_Check(obj)) #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) #endif #if PY_VERSION_HEX < 0x02060000 #define PySet_Check(obj) PyObject_TypeCheck(obj, &PySet_Type) #define PyFrozenSet_Check(obj) PyObject_TypeCheck(obj, &PyFrozenSet_Type) #endif #ifndef PySet_CheckExact #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) #endif #define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) #if PY_MAJOR_VERSION >= 3 #define PyIntObject PyLongObject #define PyInt_Type PyLong_Type #define PyInt_Check(op) PyLong_Check(op) #define PyInt_CheckExact(op) PyLong_CheckExact(op) #define PyInt_FromString PyLong_FromString #define PyInt_FromUnicode PyLong_FromUnicode #define PyInt_FromLong PyLong_FromLong #define PyInt_FromSize_t PyLong_FromSize_t #define PyInt_FromSsize_t PyLong_FromSsize_t #define PyInt_AsLong PyLong_AsLong #define PyInt_AS_LONG PyLong_AS_LONG #define PyInt_AsSsize_t PyLong_AsSsize_t #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask #define PyNumber_Int PyNumber_Long #endif #if PY_MAJOR_VERSION >= 3 #define PyBoolObject PyLongObject #endif #if PY_VERSION_HEX < 0x030200A4 typedef long Py_hash_t; #define __Pyx_PyInt_FromHash_t PyInt_FromLong #define __Pyx_PyInt_AsHash_t PyInt_AsLong #else #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t #endif #if (PY_MAJOR_VERSION < 3) || (PY_VERSION_HEX >= 0x03010300) #define __Pyx_PySequence_GetSlice(obj, a, b) PySequence_GetSlice(obj, a, b) #define __Pyx_PySequence_SetSlice(obj, a, b, value) PySequence_SetSlice(obj, a, b, value) #define __Pyx_PySequence_DelSlice(obj, a, b) PySequence_DelSlice(obj, a, b) #else #define __Pyx_PySequence_GetSlice(obj, a, b) (unlikely(!(obj)) ? \ (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), (PyObject*)0) : \ (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_GetSlice(obj, a, b)) : \ (PyErr_Format(PyExc_TypeError, "'%.200s' object is unsliceable", (obj)->ob_type->tp_name), (PyObject*)0))) #define __Pyx_PySequence_SetSlice(obj, a, b, value) (unlikely(!(obj)) ? \ (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), -1) : \ (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_SetSlice(obj, a, b, value)) : \ (PyErr_Format(PyExc_TypeError, "'%.200s' object doesn't support slice assignment", (obj)->ob_type->tp_name), -1))) #define __Pyx_PySequence_DelSlice(obj, a, b) (unlikely(!(obj)) ? \ (PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), -1) : \ (likely((obj)->ob_type->tp_as_mapping) ? (PySequence_DelSlice(obj, a, b)) : \ (PyErr_Format(PyExc_TypeError, "'%.200s' object doesn't support slice deletion", (obj)->ob_type->tp_name), -1))) #endif #if PY_MAJOR_VERSION >= 3 #define PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : PyInstanceMethod_New(func)) #endif #if PY_VERSION_HEX < 0x02050000 #define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),((char *)(n))) #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),((char *)(n)),(a)) #define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),((char *)(n))) #else #define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),(n)) #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),(n),(a)) #define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),(n)) #endif #if PY_VERSION_HEX < 0x02050000 #define __Pyx_NAMESTR(n) ((char *)(n)) #define __Pyx_DOCSTR(n) ((char *)(n)) #else #define __Pyx_NAMESTR(n) (n) #define __Pyx_DOCSTR(n) (n) #endif /* inline attribute */ #ifndef CYTHON_INLINE #if defined(__GNUC__) #define CYTHON_INLINE __inline__ #elif defined(_MSC_VER) #define CYTHON_INLINE __inline #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #define CYTHON_INLINE inline #else #define CYTHON_INLINE #endif #endif /* restrict */ #ifndef CYTHON_RESTRICT #if defined(__GNUC__) #define CYTHON_RESTRICT __restrict__ #elif defined(_MSC_VER) && _MSC_VER >= 1400 #define CYTHON_RESTRICT __restrict #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #define CYTHON_RESTRICT restrict #else #define CYTHON_RESTRICT #endif #endif #ifdef NAN #define __PYX_NAN() ((float) NAN) #else static CYTHON_INLINE float __PYX_NAN() { /* Initialize NaN. The sign is irrelevant, an exponent with all bits 1 and a nonzero mantissa means NaN. If the first bit in the mantissa is 1, it is a quiet NaN. */ float value; memset(&value, 0xFF, sizeof(value)); return value; } #endif // Work around clang bug http://stackoverflow.com/questions/21847816/c-invoke-nested-template-class-destructor #ifdef __cplusplus template void __Pyx_call_destructor(T* x) { x->~T(); } #endif /////////////// UtilityFunctionPredeclarations.proto /////////////// /* unused attribute */ #ifndef CYTHON_UNUSED # if defined(__GNUC__) # if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) # define CYTHON_UNUSED __attribute__ ((__unused__)) # else # define CYTHON_UNUSED # endif # elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) # define CYTHON_UNUSED __attribute__ ((__unused__)) # else # define CYTHON_UNUSED # endif #endif typedef struct {PyObject **p; char *s; const Py_ssize_t n; const char* encoding; const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; /*proto*/ /////////////// ForceInitThreads.proto /////////////// #ifndef __PYX_FORCE_INIT_THREADS #define __PYX_FORCE_INIT_THREADS 0 #endif /////////////// InitThreads.init /////////////// #ifdef WITH_THREAD PyEval_InitThreads(); #endif /////////////// CodeObjectCache.proto /////////////// typedef struct { int code_line; PyCodeObject* code_object; } __Pyx_CodeObjectCacheEntry; struct __Pyx_CodeObjectCache { int count; int max_count; __Pyx_CodeObjectCacheEntry* entries; }; static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); static PyCodeObject *__pyx_find_code_object(int code_line); static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); /////////////// CodeObjectCache /////////////// // Note that errors are simply ignored in the code below. // This is just a cache, if a lookup or insertion fails - so what? static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { int start = 0, mid = 0, end = count - 1; if (end >= 0 && code_line > entries[end].code_line) { return count; } while (start < end) { mid = (start + end) / 2; if (code_line < entries[mid].code_line) { end = mid; } else if (code_line > entries[mid].code_line) { start = mid + 1; } else { return mid; } } if (code_line <= entries[mid].code_line) { return mid; } else { return mid + 1; } } static PyCodeObject *__pyx_find_code_object(int code_line) { PyCodeObject* code_object; int pos; if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { return NULL; } pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { return NULL; } code_object = __pyx_code_cache.entries[pos].code_object; Py_INCREF(code_object); return code_object; } static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { int pos, i; __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; if (unlikely(!code_line)) { return; } if (unlikely(!entries)) { entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); if (likely(entries)) { __pyx_code_cache.entries = entries; __pyx_code_cache.max_count = 64; __pyx_code_cache.count = 1; entries[0].code_line = code_line; entries[0].code_object = code_object; Py_INCREF(code_object); } return; } pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { PyCodeObject* tmp = entries[pos].code_object; entries[pos].code_object = code_object; Py_DECREF(tmp); return; } if (__pyx_code_cache.count == __pyx_code_cache.max_count) { int new_max = __pyx_code_cache.max_count + 64; entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( __pyx_code_cache.entries, new_max*sizeof(__Pyx_CodeObjectCacheEntry)); if (unlikely(!entries)) { return; } __pyx_code_cache.entries = entries; __pyx_code_cache.max_count = new_max; } for (i=__pyx_code_cache.count; i>pos; i--) { entries[i] = entries[i-1]; } entries[pos].code_line = code_line; entries[pos].code_object = code_object; __pyx_code_cache.count++; Py_INCREF(code_object); } /////////////// CodeObjectCache.cleanup /////////////// if (__pyx_code_cache.entries) { __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; int i, count = __pyx_code_cache.count; __pyx_code_cache.count = 0; __pyx_code_cache.max_count = 0; __pyx_code_cache.entries = NULL; for (i=0; iSetupContext((name), __LINE__, __FILE__); \ PyGILState_Release(__pyx_gilstate_save); \ } else { \ __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__); \ } #else #define __Pyx_RefNannySetupContext(name, acquire_gil) \ __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) #endif #define __Pyx_RefNannyFinishContext() \ __Pyx_RefNanny->FinishContext(&__pyx_refnanny) #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0) #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0) #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0) #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0) #else #define __Pyx_RefNannyDeclarations #define __Pyx_RefNannySetupContext(name, acquire_gil) #define __Pyx_RefNannyFinishContext() #define __Pyx_INCREF(r) Py_INCREF(r) #define __Pyx_DECREF(r) Py_DECREF(r) #define __Pyx_GOTREF(r) #define __Pyx_GIVEREF(r) #define __Pyx_XINCREF(r) Py_XINCREF(r) #define __Pyx_XDECREF(r) Py_XDECREF(r) #define __Pyx_XGOTREF(r) #define __Pyx_XGIVEREF(r) #endif /* CYTHON_REFNANNY */ #define __Pyx_XDECREF_SET(r, v) do { \ PyObject *tmp = (PyObject *) r; \ r = v; __Pyx_XDECREF(tmp); \ } while (0) #define __Pyx_DECREF_SET(r, v) do { \ PyObject *tmp = (PyObject *) r; \ r = v; __Pyx_DECREF(tmp); \ } while (0) #define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) #define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) /////////////// Refnanny /////////////// #if CYTHON_REFNANNY static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { PyObject *m = NULL, *p = NULL; void *r = NULL; m = PyImport_ImportModule((char *)modname); if (!m) goto end; p = PyObject_GetAttrString(m, (char *)"RefNannyAPI"); if (!p) goto end; r = PyLong_AsVoidPtr(p); end: Py_XDECREF(p); Py_XDECREF(m); return (__Pyx_RefNannyAPIStruct *)r; } #endif /* CYTHON_REFNANNY */ /////////////// RegisterModuleCleanup.proto /////////////// //@substitute: naming static void ${cleanup_cname}(PyObject *self); /*proto*/ static int __Pyx_RegisterCleanup(void); /*proto*/ /////////////// RegisterModuleCleanup /////////////// //@substitute: naming //@requires: ImportExport.c::ModuleImport #if PY_MAJOR_VERSION < 3 static PyObject* ${cleanup_cname}_atexit(PyObject *module, CYTHON_UNUSED PyObject *unused) { ${cleanup_cname}(module); Py_INCREF(Py_None); return Py_None; } static int __Pyx_RegisterCleanup(void) { // Don't use Py_AtExit because that has a 32-call limit and is called // after python finalization. // Also, we try to prepend the cleanup function to "atexit._exithandlers" // in Py2 because CPython runs them last-to-first. Being run last allows // user exit code to run before us that may depend on the globals // and cached objects that we are about to clean up. static PyMethodDef cleanup_def = { __Pyx_NAMESTR("__cleanup"), (PyCFunction)${cleanup_cname}_atexit, METH_NOARGS, 0}; PyObject *cleanup_func = 0; PyObject *atexit = 0; PyObject *reg = 0; PyObject *args = 0; PyObject *res = 0; int ret = -1; cleanup_func = PyCFunction_New(&cleanup_def, 0); if (!cleanup_func) goto bad; atexit = __Pyx_ImportModule("atexit"); if (!atexit) goto bad; reg = __Pyx_GetAttrString(atexit, "_exithandlers"); if (reg && PyList_Check(reg)) { PyObject *a, *kw; a = PyTuple_New(0); kw = PyDict_New(); if (!a || !kw) { Py_XDECREF(a); Py_XDECREF(kw); goto bad; } args = PyTuple_Pack(3, cleanup_func, a, kw); Py_DECREF(a); Py_DECREF(kw); if (!args) goto bad; ret = PyList_Insert(reg, 0, args); } else { if (!reg) PyErr_Clear(); Py_XDECREF(reg); reg = __Pyx_GetAttrString(atexit, "register"); if (!reg) goto bad; args = PyTuple_Pack(1, cleanup_func); if (!args) goto bad; res = PyObject_CallObject(reg, args); if (!res) goto bad; ret = 0; } bad: Py_XDECREF(cleanup_func); Py_XDECREF(atexit); Py_XDECREF(reg); Py_XDECREF(args); Py_XDECREF(res); return ret; } #else // fake call purely to work around "unused function" warning for __Pyx_ImportModule() static int __Pyx_RegisterCleanup(void) { if (0) __Pyx_ImportModule(NULL); return 0; } #endif cython-0.20.1+git90-g0e6e38e/Cython/Utility/ObjectHandling.c000066400000000000000000001170411231323242300231770ustar00rootroot00000000000000/* * General object operations and protocol implementations, * including their specialisations for certain builtins. * * Optional optimisations for builtins are in Optimize.c. * * Required replacements of builtins are in Builtins.c. */ /////////////// RaiseNoneIterError.proto /////////////// static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); /////////////// RaiseNoneIterError /////////////// static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); } /////////////// RaiseTooManyValuesToUnpack.proto /////////////// static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); /////////////// RaiseTooManyValuesToUnpack /////////////// static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { PyErr_Format(PyExc_ValueError, "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); } /////////////// RaiseNeedMoreValuesToUnpack.proto /////////////// static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); /////////////// RaiseNeedMoreValuesToUnpack /////////////// static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { PyErr_Format(PyExc_ValueError, "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", index, (index == 1) ? "" : "s"); } /////////////// UnpackTupleError.proto /////////////// static void __Pyx_UnpackTupleError(PyObject *, Py_ssize_t index); /*proto*/ /////////////// UnpackTupleError /////////////// //@requires: RaiseNoneIterError //@requires: RaiseNeedMoreValuesToUnpack //@requires: RaiseTooManyValuesToUnpack static void __Pyx_UnpackTupleError(PyObject *t, Py_ssize_t index) { if (t == Py_None) { __Pyx_RaiseNoneNotIterableError(); } else if (PyTuple_GET_SIZE(t) < index) { __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(t)); } else { __Pyx_RaiseTooManyValuesError(index); } } /////////////// UnpackItemEndCheck.proto /////////////// static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected); /*proto*/ /////////////// UnpackItemEndCheck /////////////// //@requires: RaiseTooManyValuesToUnpack //@requires: IterFinish static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) { if (unlikely(retval)) { Py_DECREF(retval); __Pyx_RaiseTooManyValuesError(expected); return -1; } else { return __Pyx_IterFinish(); } return 0; } /////////////// UnpackTuple2.proto /////////////// static CYTHON_INLINE int __Pyx_unpack_tuple2(PyObject* tuple, PyObject** value1, PyObject** value2, int is_tuple, int has_known_size, int decref_tuple); /////////////// UnpackTuple2 /////////////// //@requires: UnpackItemEndCheck //@requires: UnpackTupleError //@requires: RaiseNeedMoreValuesToUnpack static CYTHON_INLINE int __Pyx_unpack_tuple2(PyObject* tuple, PyObject** pvalue1, PyObject** pvalue2, int is_tuple, int has_known_size, int decref_tuple) { Py_ssize_t index; PyObject *value1 = NULL, *value2 = NULL, *iter = NULL; if (!is_tuple && unlikely(!PyTuple_Check(tuple))) { iternextfunc iternext; iter = PyObject_GetIter(tuple); if (unlikely(!iter)) goto bad; if (decref_tuple) { Py_DECREF(tuple); tuple = NULL; } iternext = Py_TYPE(iter)->tp_iternext; value1 = iternext(iter); if (unlikely(!value1)) { index = 0; goto unpacking_failed; } value2 = iternext(iter); if (unlikely(!value2)) { index = 1; goto unpacking_failed; } if (!has_known_size && unlikely(__Pyx_IternextUnpackEndCheck(iternext(iter), 2))) goto bad; Py_DECREF(iter); } else { if (!has_known_size && unlikely(PyTuple_GET_SIZE(tuple) != 2)) { __Pyx_UnpackTupleError(tuple, 2); goto bad; } #if CYTHON_COMPILING_IN_PYPY value1 = PySequence_ITEM(tuple, 0); if (unlikely(!value1)) goto bad; value2 = PySequence_ITEM(tuple, 1); if (unlikely(!value2)) goto bad; #else value1 = PyTuple_GET_ITEM(tuple, 0); value2 = PyTuple_GET_ITEM(tuple, 1); Py_INCREF(value1); Py_INCREF(value2); #endif if (decref_tuple) { Py_DECREF(tuple); } } *pvalue1 = value1; *pvalue2 = value2; return 0; unpacking_failed: if (!has_known_size && __Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); bad: Py_XDECREF(iter); Py_XDECREF(value1); Py_XDECREF(value2); if (decref_tuple) { Py_XDECREF(tuple); } return -1; } /////////////// IterNext.proto /////////////// #define __Pyx_PyIter_Next(obj) __Pyx_PyIter_Next2(obj, NULL) static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject *, PyObject *); /*proto*/ /////////////// IterNext /////////////// // originally copied from Py3's builtin_next() static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject* iterator, PyObject* defval) { PyObject* next; iternextfunc iternext = Py_TYPE(iterator)->tp_iternext; #if CYTHON_COMPILING_IN_CPYTHON if (unlikely(!iternext)) { #else if (unlikely(!iternext) || unlikely(!PyIter_Check(iterator))) { #endif PyErr_Format(PyExc_TypeError, "%.200s object is not an iterator", Py_TYPE(iterator)->tp_name); return NULL; } next = iternext(iterator); if (likely(next)) return next; #if CYTHON_COMPILING_IN_CPYTHON #if PY_VERSION_HEX >= 0x03010000 || (PY_MAJOR_VERSION < 3 && PY_VERSION_HEX >= 0x02070000) if (unlikely(iternext == &_PyObject_NextNotImplemented)) return NULL; #endif #endif if (defval) { PyObject* exc_type = PyErr_Occurred(); if (exc_type) { if (unlikely(exc_type != PyExc_StopIteration) && !PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration)) return NULL; PyErr_Clear(); } Py_INCREF(defval); return defval; } if (!PyErr_Occurred()) PyErr_SetNone(PyExc_StopIteration); return NULL; } /////////////// IterFinish.proto /////////////// static CYTHON_INLINE int __Pyx_IterFinish(void); /*proto*/ /////////////// IterFinish /////////////// // When PyIter_Next(iter) has returned NULL in order to signal termination, // this function does the right cleanup and returns 0 on success. If it // detects an error that occurred in the iterator, it returns -1. static CYTHON_INLINE int __Pyx_IterFinish(void) { #if CYTHON_COMPILING_IN_CPYTHON PyThreadState *tstate = PyThreadState_GET(); PyObject* exc_type = tstate->curexc_type; if (unlikely(exc_type)) { if (likely(exc_type == PyExc_StopIteration) || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration)) { PyObject *exc_value, *exc_tb; exc_value = tstate->curexc_value; exc_tb = tstate->curexc_traceback; tstate->curexc_type = 0; tstate->curexc_value = 0; tstate->curexc_traceback = 0; Py_DECREF(exc_type); Py_XDECREF(exc_value); Py_XDECREF(exc_tb); return 0; } else { return -1; } } return 0; #else if (unlikely(PyErr_Occurred())) { if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) { PyErr_Clear(); return 0; } else { return -1; } } return 0; #endif } /////////////// DictGetItem.proto /////////////// #if PY_MAJOR_VERSION >= 3 static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { PyObject *value; value = PyDict_GetItemWithError(d, key); if (unlikely(!value)) { if (!PyErr_Occurred()) { PyObject* args = PyTuple_Pack(1, key); if (likely(args)) PyErr_SetObject(PyExc_KeyError, args); Py_XDECREF(args); } return NULL; } Py_INCREF(value); return value; } #else #define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) #endif /////////////// GetItemInt.proto /////////////// #define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \ __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) : \ (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) : \ __Pyx_GetItemInt_Generic(o, to_py_func(i)))) {{for type in ['List', 'Tuple']}} #define __Pyx_GetItemInt_{{type}}(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \ __Pyx_GetItemInt_{{type}}_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) : \ (PyErr_SetString(PyExc_IndexError, "{{ type.lower() }} index out of range"), (PyObject*)NULL)) static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ssize_t i, int wraparound, int boundscheck); {{endfor}} static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, int wraparound, int boundscheck); /////////////// GetItemInt /////////////// static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { PyObject *r; if (!j) return NULL; r = PyObject_GetItem(o, j); Py_DECREF(j); return r; } {{for type in ['List', 'Tuple']}} static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ssize_t i, int wraparound, int boundscheck) { #if CYTHON_COMPILING_IN_CPYTHON if (wraparound & unlikely(i < 0)) i += Py{{type}}_GET_SIZE(o); if ((!boundscheck) || likely((0 <= i) & (i < Py{{type}}_GET_SIZE(o)))) { PyObject *r = Py{{type}}_GET_ITEM(o, i); Py_INCREF(r); return r; } return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); #else return PySequence_GetItem(o, i); #endif } {{endfor}} static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, int wraparound, int boundscheck) { #if CYTHON_COMPILING_IN_CPYTHON if (is_list || PyList_CheckExact(o)) { Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); if ((!boundscheck) || (likely((n >= 0) & (n < PyList_GET_SIZE(o))))) { PyObject *r = PyList_GET_ITEM(o, n); Py_INCREF(r); return r; } } else if (PyTuple_CheckExact(o)) { Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); if ((!boundscheck) || likely((n >= 0) & (n < PyTuple_GET_SIZE(o)))) { PyObject *r = PyTuple_GET_ITEM(o, n); Py_INCREF(r); return r; } } else { // inlined PySequence_GetItem() + special cased length overflow PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; if (likely(m && m->sq_item)) { if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { Py_ssize_t l = m->sq_length(o); if (likely(l >= 0)) { i += l; } else { // if length > max(Py_ssize_t), maybe the object can wrap around itself? if (PyErr_ExceptionMatches(PyExc_OverflowError)) PyErr_Clear(); else return NULL; } } return m->sq_item(o, i); } } #else if (is_list || PySequence_Check(o)) { return PySequence_GetItem(o, i); } #endif return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); } /////////////// SetItemInt.proto /////////////// #define __Pyx_SetItemInt(o, i, v, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \ __Pyx_SetItemInt_Fast(o, (Py_ssize_t)i, v, is_list, wraparound, boundscheck) : \ (is_list ? (PyErr_SetString(PyExc_IndexError, "list assignment index out of range"), -1) : \ __Pyx_SetItemInt_Generic(o, to_py_func(i), v))) static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v); static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int is_list, int wraparound, int boundscheck); /////////////// SetItemInt /////////////// static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) { int r; if (!j) return -1; r = PyObject_SetItem(o, j, v); Py_DECREF(j); return r; } static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int is_list, int wraparound, int boundscheck) { #if CYTHON_COMPILING_IN_CPYTHON if (is_list || PyList_CheckExact(o)) { Py_ssize_t n = (!wraparound) ? i : ((likely(i >= 0)) ? i : i + PyList_GET_SIZE(o)); if ((!boundscheck) || likely((n >= 0) & (n < PyList_GET_SIZE(o)))) { PyObject* old = PyList_GET_ITEM(o, n); Py_INCREF(v); PyList_SET_ITEM(o, n, v); Py_DECREF(old); return 1; } } else { // inlined PySequence_SetItem() + special cased length overflow PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; if (likely(m && m->sq_ass_item)) { if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { Py_ssize_t l = m->sq_length(o); if (likely(l >= 0)) { i += l; } else { // if length > max(Py_ssize_t), maybe the object can wrap around itself? if (PyErr_ExceptionMatches(PyExc_OverflowError)) PyErr_Clear(); else return -1; } } return m->sq_ass_item(o, i, v); } } #else #if CYTHON_COMPILING_IN_PYPY if (is_list || (PySequence_Check(o) && !PyDict_Check(o))) { #else if (is_list || PySequence_Check(o)) { #endif return PySequence_SetItem(o, i, v); } #endif return __Pyx_SetItemInt_Generic(o, PyInt_FromSsize_t(i), v); } /////////////// DelItemInt.proto /////////////// #define __Pyx_DelItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \ __Pyx_DelItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound) : \ (is_list ? (PyErr_SetString(PyExc_IndexError, "list assignment index out of range"), -1) : \ __Pyx_DelItem_Generic(o, to_py_func(i)))) static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j); static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i, CYTHON_UNUSED int is_list, int wraparound); /////////////// DelItemInt /////////////// static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) { int r; if (!j) return -1; r = PyObject_DelItem(o, j); Py_DECREF(j); return r; } static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i, CYTHON_UNUSED int is_list, int wraparound) { #if CYTHON_COMPILING_IN_PYPY if (is_list || PySequence_Check(o)) { return PySequence_DelItem(o, i); } #else // inlined PySequence_DelItem() + special cased length overflow PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; if (likely(m && m->sq_ass_item)) { if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { Py_ssize_t l = m->sq_length(o); if (likely(l >= 0)) { i += l; } else { // if length > max(Py_ssize_t), maybe the object can wrap around itself? if (PyErr_ExceptionMatches(PyExc_OverflowError)) PyErr_Clear(); else return -1; } } return m->sq_ass_item(o, i, (PyObject *)NULL); } #endif return __Pyx_DelItem_Generic(o, PyInt_FromSsize_t(i)); } /////////////// SliceObject.proto /////////////// // we pass pointer addresses to show the C compiler what is NULL and what isn't {{if access == 'Get'}} static CYTHON_INLINE PyObject* __Pyx_PyObject_GetSlice( PyObject* obj, Py_ssize_t cstart, Py_ssize_t cstop, PyObject** py_start, PyObject** py_stop, PyObject** py_slice, int has_cstart, int has_cstop, int wraparound); {{else}} #define __Pyx_PyObject_DelSlice(obj, cstart, cstop, py_start, py_stop, py_slice, has_cstart, has_cstop, wraparound) \ __Pyx_PyObject_SetSlice(obj, (PyObject*)NULL, cstart, cstop, py_start, py_stop, py_slice, has_cstart, has_cstop, wraparound) // we pass pointer addresses to show the C compiler what is NULL and what isn't static CYTHON_INLINE int __Pyx_PyObject_SetSlice( PyObject* obj, PyObject* value, Py_ssize_t cstart, Py_ssize_t cstop, PyObject** py_start, PyObject** py_stop, PyObject** py_slice, int has_cstart, int has_cstop, int wraparound); {{endif}} /////////////// SliceObject /////////////// {{if access == 'Get'}} static CYTHON_INLINE PyObject* __Pyx_PyObject_GetSlice( PyObject* obj, Py_ssize_t cstart, Py_ssize_t cstop, {{else}} static CYTHON_INLINE int __Pyx_PyObject_SetSlice( PyObject* obj, PyObject* value, Py_ssize_t cstart, Py_ssize_t cstop, {{endif}} PyObject** _py_start, PyObject** _py_stop, PyObject** _py_slice, int has_cstart, int has_cstop, CYTHON_UNUSED int wraparound) { #if CYTHON_COMPILING_IN_CPYTHON PyMappingMethods* mp; #if PY_MAJOR_VERSION < 3 PySequenceMethods* ms = Py_TYPE(obj)->tp_as_sequence; if (likely(ms && ms->sq_{{if access == 'Set'}}ass_{{endif}}slice)) { if (!has_cstart) { if (_py_start && (*_py_start != Py_None)) { cstart = __Pyx_PyIndex_AsSsize_t(*_py_start); if ((cstart == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; } else cstart = 0; } if (!has_cstop) { if (_py_stop && (*_py_stop != Py_None)) { cstop = __Pyx_PyIndex_AsSsize_t(*_py_stop); if ((cstop == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; } else cstop = PY_SSIZE_T_MAX; } if (wraparound && unlikely((cstart < 0) | (cstop < 0)) && likely(ms->sq_length)) { Py_ssize_t l = ms->sq_length(obj); if (likely(l >= 0)) { if (cstop < 0) { cstop += l; if (cstop < 0) cstop = 0; } if (cstart < 0) { cstart += l; if (cstart < 0) cstart = 0; } } else { // if length > max(Py_ssize_t), maybe the object can wrap around itself? if (PyErr_ExceptionMatches(PyExc_OverflowError)) PyErr_Clear(); else goto bad; } } {{if access == 'Get'}} return ms->sq_slice(obj, cstart, cstop); {{else}} return ms->sq_ass_slice(obj, cstart, cstop, value); {{endif}} } #endif mp = Py_TYPE(obj)->tp_as_mapping; {{if access == 'Get'}} if (likely(mp && mp->mp_subscript)) {{else}} if (likely(mp && mp->mp_ass_subscript)) {{endif}} #endif { {{if access == 'Get'}}PyObject*{{else}}int{{endif}} result; PyObject *py_slice, *py_start, *py_stop; if (_py_slice) { py_slice = *_py_slice; } else { PyObject* owned_start = NULL; PyObject* owned_stop = NULL; if (_py_start) { py_start = *_py_start; } else { if (has_cstart) { owned_start = py_start = PyInt_FromSsize_t(cstart); if (unlikely(!py_start)) goto bad; } else py_start = Py_None; } if (_py_stop) { py_stop = *_py_stop; } else { if (has_cstop) { owned_stop = py_stop = PyInt_FromSsize_t(cstop); if (unlikely(!py_stop)) { Py_XDECREF(owned_start); goto bad; } } else py_stop = Py_None; } py_slice = PySlice_New(py_start, py_stop, Py_None); Py_XDECREF(owned_start); Py_XDECREF(owned_stop); if (unlikely(!py_slice)) goto bad; } #if CYTHON_COMPILING_IN_CPYTHON {{if access == 'Get'}} result = mp->mp_subscript(obj, py_slice); #else result = PyObject_GetItem(obj, py_slice); {{else}} result = mp->mp_ass_subscript(obj, py_slice, value); #else result = value ? PyObject_SetItem(obj, py_slice, value) : PyObject_DelItem(obj, py_slice); {{endif}} #endif if (!_py_slice) { Py_DECREF(py_slice); } return result; } PyErr_Format(PyExc_TypeError, {{if access == 'Get'}} "'%.200s' object is unsliceable", Py_TYPE(obj)->tp_name); {{else}} "'%.200s' object does not support slice %.10s", Py_TYPE(obj)->tp_name, value ? "assignment" : "deletion"); {{endif}} bad: return {{if access == 'Get'}}NULL{{else}}-1{{endif}}; } /////////////// SliceTupleAndList.proto /////////////// #if CYTHON_COMPILING_IN_CPYTHON static CYTHON_INLINE PyObject* __Pyx_PyList_GetSlice(PyObject* src, Py_ssize_t start, Py_ssize_t stop); static CYTHON_INLINE PyObject* __Pyx_PyTuple_GetSlice(PyObject* src, Py_ssize_t start, Py_ssize_t stop); #else #define __Pyx_PyList_GetSlice(seq, start, stop) PySequence_GetSlice(seq, start, stop) #define __Pyx_PyTuple_GetSlice(seq, start, stop) PySequence_GetSlice(seq, start, stop) #endif /////////////// SliceTupleAndList /////////////// #if CYTHON_COMPILING_IN_CPYTHON static CYTHON_INLINE void __Pyx_crop_slice(Py_ssize_t* _start, Py_ssize_t* _stop, Py_ssize_t* _length) { Py_ssize_t start = *_start, stop = *_stop, length = *_length; if (start < 0) { start += length; if (start < 0) start = 0; } if (stop < 0) stop += length; else if (stop > length) stop = length; *_length = stop - start; *_start = start; *_stop = stop; } static CYTHON_INLINE void __Pyx_copy_object_array(PyObject** CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { PyObject *v; Py_ssize_t i; for (i = 0; i < length; i++) { v = dest[i] = src[i]; Py_INCREF(v); } } {{for type in ['List', 'Tuple']}} static CYTHON_INLINE PyObject* __Pyx_Py{{type}}_GetSlice( PyObject* src, Py_ssize_t start, Py_ssize_t stop) { PyObject* dest; Py_ssize_t length = Py{{type}}_GET_SIZE(src); __Pyx_crop_slice(&start, &stop, &length); if (unlikely(length <= 0)) return Py{{type}}_New(0); dest = Py{{type}}_New(length); if (unlikely(!dest)) return NULL; __Pyx_copy_object_array( ((Py{{type}}Object*)src)->ob_item + start, ((Py{{type}}Object*)dest)->ob_item, length); return dest; } {{endfor}} #endif /////////////// CalculateMetaclass.proto /////////////// static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases); /////////////// CalculateMetaclass /////////////// static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases) { Py_ssize_t i, nbases = PyTuple_GET_SIZE(bases); for (i=0; i < nbases; i++) { PyTypeObject *tmptype; PyObject *tmp = PyTuple_GET_ITEM(bases, i); tmptype = Py_TYPE(tmp); #if PY_MAJOR_VERSION < 3 if (tmptype == &PyClass_Type) continue; #endif if (!metaclass) { metaclass = tmptype; continue; } if (PyType_IsSubtype(metaclass, tmptype)) continue; if (PyType_IsSubtype(tmptype, metaclass)) { metaclass = tmptype; continue; } // else: PyErr_SetString(PyExc_TypeError, "metaclass conflict: " "the metaclass of a derived class " "must be a (non-strict) subclass " "of the metaclasses of all its bases"); return NULL; } if (!metaclass) { #if PY_MAJOR_VERSION < 3 metaclass = &PyClass_Type; #else metaclass = &PyType_Type; #endif } // make owned reference Py_INCREF((PyObject*) metaclass); return (PyObject*) metaclass; } /////////////// FindInheritedMetaclass.proto /////////////// static PyObject *__Pyx_FindInheritedMetaclass(PyObject *bases); /*proto*/ /////////////// FindInheritedMetaclass /////////////// //@requires: PyObjectGetAttrStr //@requires: CalculateMetaclass static PyObject *__Pyx_FindInheritedMetaclass(PyObject *bases) { PyObject *metaclass; if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) { PyTypeObject *metatype; PyObject *base = PyTuple_GET_ITEM(bases, 0); #if PY_MAJOR_VERSION < 3 PyObject* basetype = __Pyx_PyObject_GetAttrStr(base, PYIDENT("__class__")); if (basetype) { metatype = (PyType_Check(basetype)) ? ((PyTypeObject*) basetype) : NULL; } else { PyErr_Clear(); metatype = Py_TYPE(base); basetype = (PyObject*) metatype; Py_INCREF(basetype); } #else metatype = Py_TYPE(base); #endif metaclass = __Pyx_CalculateMetaclass(metatype, bases); #if PY_MAJOR_VERSION < 3 Py_DECREF(basetype); #endif } else { // no bases => use default metaclass #if PY_MAJOR_VERSION < 3 metaclass = (PyObject *) &PyClass_Type; #else metaclass = (PyObject *) &PyType_Type; #endif Py_INCREF(metaclass); } return metaclass; } /////////////// Py3MetaclassGet.proto /////////////// static PyObject *__Pyx_Py3MetaclassGet(PyObject *bases, PyObject *mkw); /*proto*/ /////////////// Py3MetaclassGet /////////////// //@requires: FindInheritedMetaclass //@requires: CalculateMetaclass static PyObject *__Pyx_Py3MetaclassGet(PyObject *bases, PyObject *mkw) { PyObject *metaclass = PyDict_GetItem(mkw, PYIDENT("metaclass")); if (metaclass) { Py_INCREF(metaclass); if (PyDict_DelItem(mkw, PYIDENT("metaclass")) < 0) { Py_DECREF(metaclass); return NULL; } if (PyType_Check(metaclass)) { PyObject* orig = metaclass; metaclass = __Pyx_CalculateMetaclass((PyTypeObject*) metaclass, bases); Py_DECREF(orig); } return metaclass; } return __Pyx_FindInheritedMetaclass(bases); } /////////////// CreateClass.proto /////////////// static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, PyObject *qualname, PyObject *modname); /*proto*/ /////////////// CreateClass /////////////// //@requires: FindInheritedMetaclass //@requires: CalculateMetaclass static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, PyObject *qualname, PyObject *modname) { PyObject *result; PyObject *metaclass; if (PyDict_SetItem(dict, PYIDENT("__module__"), modname) < 0) return NULL; if (PyDict_SetItem(dict, PYIDENT("__qualname__"), qualname) < 0) return NULL; /* Python2 __metaclass__ */ metaclass = PyDict_GetItem(dict, PYIDENT("__metaclass__")); if (metaclass) { Py_INCREF(metaclass); if (PyType_Check(metaclass)) { PyObject* orig = metaclass; metaclass = __Pyx_CalculateMetaclass((PyTypeObject*) metaclass, bases); Py_DECREF(orig); } } else { metaclass = __Pyx_FindInheritedMetaclass(bases); } if (unlikely(!metaclass)) return NULL; result = PyObject_CallFunctionObjArgs(metaclass, name, bases, dict, NULL); Py_DECREF(metaclass); return result; } /////////////// Py3ClassCreate.proto /////////////// static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc); /*proto*/ static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, PyObject *mkw, int calculate_metaclass, int allow_py2_metaclass); /*proto*/ /////////////// Py3ClassCreate /////////////// //@requires: PyObjectGetAttrStr //@requires: CalculateMetaclass static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc) { PyObject *ns; if (metaclass) { PyObject *prep = __Pyx_PyObject_GetAttrStr(metaclass, PYIDENT("__prepare__")); if (prep) { PyObject *pargs = PyTuple_Pack(2, name, bases); if (unlikely(!pargs)) { Py_DECREF(prep); return NULL; } ns = PyObject_Call(prep, pargs, mkw); Py_DECREF(prep); Py_DECREF(pargs); } else { if (unlikely(!PyErr_ExceptionMatches(PyExc_AttributeError))) return NULL; PyErr_Clear(); ns = PyDict_New(); } } else { ns = PyDict_New(); } if (unlikely(!ns)) return NULL; /* Required here to emulate assignment order */ if (unlikely(PyObject_SetItem(ns, PYIDENT("__module__"), modname) < 0)) goto bad; if (unlikely(PyObject_SetItem(ns, PYIDENT("__qualname__"), qualname) < 0)) goto bad; if (unlikely(doc && PyObject_SetItem(ns, PYIDENT("__doc__"), doc) < 0)) goto bad; return ns; bad: Py_DECREF(ns); return NULL; } static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, PyObject *mkw, int calculate_metaclass, int allow_py2_metaclass) { PyObject *result, *margs; PyObject *owned_metaclass = NULL; if (allow_py2_metaclass) { /* honour Python2 __metaclass__ for backward compatibility */ owned_metaclass = PyObject_GetItem(dict, PYIDENT("__metaclass__")); if (owned_metaclass) { metaclass = owned_metaclass; } else if (likely(PyErr_ExceptionMatches(PyExc_KeyError))) { PyErr_Clear(); } else { return NULL; } } if (calculate_metaclass && (!metaclass || PyType_Check(metaclass))) { metaclass = __Pyx_CalculateMetaclass((PyTypeObject*) metaclass, bases); Py_XDECREF(owned_metaclass); if (unlikely(!metaclass)) return NULL; owned_metaclass = metaclass; } margs = PyTuple_Pack(3, name, bases, dict); if (unlikely(!margs)) { result = NULL; } else { result = PyObject_Call(metaclass, margs, mkw); Py_DECREF(margs); } Py_XDECREF(owned_metaclass); return result; } /////////////// ExtTypeTest.proto /////////////// static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/ /////////////// ExtTypeTest /////////////// static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { if (unlikely(!type)) { PyErr_SetString(PyExc_SystemError, "Missing type object"); return 0; } if (likely(PyObject_TypeCheck(obj, type))) return 1; PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", Py_TYPE(obj)->tp_name, type->tp_name); return 0; } /////////////// CallableCheck.proto /////////////// #if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 #define __Pyx_PyCallable_Check(obj) ((obj)->ob_type->tp_call != NULL) #else #define __Pyx_PyCallable_Check(obj) PyCallable_Check(obj) #endif /////////////// PyDictContains.proto /////////////// static CYTHON_INLINE int __Pyx_PyDict_Contains(PyObject* item, PyObject* dict, int eq) { int result = PyDict_Contains(dict, item); return unlikely(result < 0) ? result : (result == (eq == Py_EQ)); } /////////////// PySequenceContains.proto /////////////// static CYTHON_INLINE int __Pyx_PySequence_Contains(PyObject* item, PyObject* seq, int eq) { int result = PySequence_Contains(seq, item); return unlikely(result < 0) ? result : (result == (eq == Py_EQ)); } /////////////// PyBoolOrNullFromLong.proto /////////////// static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) { return unlikely(b < 0) ? NULL : __Pyx_PyBool_FromLong(b); } /////////////// GetBuiltinName.proto /////////////// static PyObject *__Pyx_GetBuiltinName(PyObject *name); /*proto*/ /////////////// GetBuiltinName /////////////// //@requires: PyObjectGetAttrStr //@substitute: naming static PyObject *__Pyx_GetBuiltinName(PyObject *name) { PyObject* result = __Pyx_PyObject_GetAttrStr($builtins_cname, name); if (unlikely(!result)) { PyErr_Format(PyExc_NameError, #if PY_MAJOR_VERSION >= 3 "name '%U' is not defined", name); #else "name '%.200s' is not defined", PyString_AS_STRING(name)); #endif } return result; } /////////////// GetNameInClass.proto /////////////// static PyObject *__Pyx_GetNameInClass(PyObject *nmspace, PyObject *name); /*proto*/ /////////////// GetNameInClass /////////////// //@requires: PyObjectGetAttrStr //@requires: GetModuleGlobalName static PyObject *__Pyx_GetNameInClass(PyObject *nmspace, PyObject *name) { PyObject *result; result = __Pyx_PyObject_GetAttrStr(nmspace, name); if (!result) result = __Pyx_GetModuleGlobalName(name); return result; } /////////////// GetModuleGlobalName.proto /////////////// static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name); /*proto*/ /////////////// GetModuleGlobalName /////////////// //@requires: GetBuiltinName //@substitute: naming static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) { PyObject *result; #if CYTHON_COMPILING_IN_CPYTHON result = PyDict_GetItem($moddict_cname, name); if (result) { Py_INCREF(result); } else { #else result = PyObject_GetItem($moddict_cname, name); if (!result) { PyErr_Clear(); #endif result = __Pyx_GetBuiltinName(name); } return result; } //////////////////// GetAttr.proto //////////////////// static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *, PyObject *); /*proto*/ //////////////////// GetAttr //////////////////// //@requires: PyObjectGetAttrStr static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *o, PyObject *n) { #if CYTHON_COMPILING_IN_CPYTHON #if PY_MAJOR_VERSION >= 3 if (likely(PyUnicode_Check(n))) #else if (likely(PyString_Check(n))) #endif return __Pyx_PyObject_GetAttrStr(o, n); #endif return PyObject_GetAttr(o, n); } /////////////// PyObjectLookupSpecial.proto /////////////// //@requires: PyObjectGetAttrStr #if CYTHON_COMPILING_IN_CPYTHON && (PY_VERSION_HEX >= 0x03020000 || PY_MAJOR_VERSION < 3 && PY_VERSION_HEX >= 0x02070000) // looks like calling _PyType_Lookup() isn't safe in Py<=2.6/3.1 static CYTHON_INLINE PyObject* __Pyx_PyObject_LookupSpecial(PyObject* obj, PyObject* attr_name) { PyObject *res; PyTypeObject *tp = Py_TYPE(obj); #if PY_MAJOR_VERSION < 3 if (unlikely(PyInstance_Check(obj))) return __Pyx_PyObject_GetAttrStr(obj, attr_name); #endif // adapted from CPython's special_lookup() in ceval.c res = _PyType_Lookup(tp, attr_name); if (likely(res)) { descrgetfunc f = Py_TYPE(res)->tp_descr_get; if (!f) { Py_INCREF(res); } else { res = f(res, obj, (PyObject *)tp); } } else { PyErr_SetObject(PyExc_AttributeError, attr_name); } return res; } #else #define __Pyx_PyObject_LookupSpecial(o,n) __Pyx_PyObject_GetAttrStr(o,n) #endif /////////////// PyObjectGetAttrStr.proto /////////////// #if CYTHON_COMPILING_IN_CPYTHON static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { PyTypeObject* tp = Py_TYPE(obj); if (likely(tp->tp_getattro)) return tp->tp_getattro(obj, attr_name); #if PY_MAJOR_VERSION < 3 if (likely(tp->tp_getattr)) return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); #endif return PyObject_GetAttr(obj, attr_name); } #else #define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) #endif /////////////// PyObjectSetAttrStr.proto /////////////// #if CYTHON_COMPILING_IN_CPYTHON #define __Pyx_PyObject_DelAttrStr(o,n) __Pyx_PyObject_SetAttrStr(o,n,NULL) static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value) { PyTypeObject* tp = Py_TYPE(obj); if (likely(tp->tp_setattro)) return tp->tp_setattro(obj, attr_name, value); #if PY_MAJOR_VERSION < 3 if (likely(tp->tp_setattr)) return tp->tp_setattr(obj, PyString_AS_STRING(attr_name), value); #endif return PyObject_SetAttr(obj, attr_name, value); } #else #define __Pyx_PyObject_DelAttrStr(o,n) PyObject_DelAttr(o,n) #define __Pyx_PyObject_SetAttrStr(o,n,v) PyObject_SetAttr(o,n,v) #endif /////////////// PyObjectCallMethod.proto /////////////// //@requires: PyObjectGetAttrStr //@requires: PyObjectCall //@substitute: naming static PyObject* __Pyx_PyObject_CallMethodTuple(PyObject* obj, PyObject* method_name, PyObject* args) { PyObject *method, *result = NULL; if (unlikely(!args)) return NULL; method = __Pyx_PyObject_GetAttrStr(obj, method_name); if (unlikely(!method)) goto bad; result = __Pyx_PyObject_Call(method, args, NULL); Py_DECREF(method); bad: Py_DECREF(args); return result; } #define __Pyx_PyObject_CallMethod3(obj, name, arg1, arg2, arg3) \ __Pyx_PyObject_CallMethodTuple(obj, name, PyTuple_Pack(3, arg1, arg2, arg3)) #define __Pyx_PyObject_CallMethod2(obj, name, arg1, arg2) \ __Pyx_PyObject_CallMethodTuple(obj, name, PyTuple_Pack(2, arg1, arg2)) #define __Pyx_PyObject_CallMethod1(obj, name, arg1) \ __Pyx_PyObject_CallMethodTuple(obj, name, PyTuple_Pack(1, arg1)) #define __Pyx_PyObject_CallMethod0(obj, name) \ __Pyx_PyObject_CallMethodTuple(obj, name, (Py_INCREF($empty_tuple), $empty_tuple)) /////////////// tp_new.proto /////////////// #define __Pyx_tp_new(type_obj, args) __Pyx_tp_new_kwargs(type_obj, args, NULL) static CYTHON_INLINE PyObject* __Pyx_tp_new_kwargs(PyObject* type_obj, PyObject* args, PyObject* kwargs) { return (PyObject*) (((PyTypeObject*)type_obj)->tp_new((PyTypeObject*)type_obj, args, kwargs)); } /////////////// PyObjectCall.proto /////////////// #if CYTHON_COMPILING_IN_CPYTHON static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); /*proto*/ #else #define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) #endif /////////////// PyObjectCall /////////////// #if CYTHON_COMPILING_IN_CPYTHON static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { PyObject *result; ternaryfunc call = func->ob_type->tp_call; if (unlikely(!call)) return PyObject_Call(func, arg, kw); #if PY_VERSION_HEX >= 0x02060000 if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) return NULL; #endif result = (*call)(func, arg, kw); #if PY_VERSION_HEX >= 0x02060000 Py_LeaveRecursiveCall(); #endif if (unlikely(!result) && unlikely(!PyErr_Occurred())) { PyErr_SetString( PyExc_SystemError, "NULL result without error in PyObject_Call"); } return result; } #endif cython-0.20.1+git90-g0e6e38e/Cython/Utility/Optimize.c000066400000000000000000000333321231323242300221240ustar00rootroot00000000000000/* * Optional optimisations of built-in functions and methods. * * Required replacements of builtins are in Builtins.c. * * General object operations and protocols are in ObjectHandling.c. */ /////////////// append.proto /////////////// static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x); /*proto*/ /////////////// append /////////////// //@requires: ListAppend //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x) { if (likely(PyList_CheckExact(L))) { if (unlikely(__Pyx_PyList_Append(L, x) < 0)) return -1; } else { PyObject* retval = __Pyx_PyObject_CallMethod1(L, PYIDENT("append"), x); if (unlikely(!retval)) return -1; Py_DECREF(retval); } return 0; } /////////////// ListAppend.proto /////////////// #if CYTHON_COMPILING_IN_CPYTHON static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { PyListObject* L = (PyListObject*) list; Py_ssize_t len = Py_SIZE(list); if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { Py_INCREF(x); PyList_SET_ITEM(list, len, x); Py_SIZE(list) = len+1; return 0; } return PyList_Append(list, x); } #else #define __Pyx_PyList_Append(L,x) PyList_Append(L,x) #endif /////////////// ListCompAppend.proto /////////////// #if CYTHON_COMPILING_IN_CPYTHON static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) { PyListObject* L = (PyListObject*) list; Py_ssize_t len = Py_SIZE(list); if (likely(L->allocated > len)) { Py_INCREF(x); PyList_SET_ITEM(list, len, x); Py_SIZE(list) = len+1; return 0; } return PyList_Append(list, x); } #else #define __Pyx_ListComp_Append(L,x) PyList_Append(L,x) #endif //////////////////// ListExtend.proto //////////////////// static CYTHON_INLINE int __Pyx_PyList_Extend(PyObject* L, PyObject* v) { #if CYTHON_COMPILING_IN_CPYTHON PyObject* none = _PyList_Extend((PyListObject*)L, v); if (unlikely(!none)) return -1; Py_DECREF(none); return 0; #else return PyList_SetSlice(L, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, v); #endif } /////////////// pop.proto /////////////// #define __Pyx_PyObject_Pop(L) (PyList_CheckExact(L) ? \ __Pyx_PyList_Pop(L) : __Pyx__PyObject_Pop(L)) static CYTHON_INLINE PyObject* __Pyx_PyList_Pop(PyObject* L); /*proto*/ static CYTHON_INLINE PyObject* __Pyx__PyObject_Pop(PyObject* L); /*proto*/ /////////////// pop /////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx__PyObject_Pop(PyObject* L) { #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02050000 if (Py_TYPE(L) == &PySet_Type) { return PySet_Pop(L); } #endif return __Pyx_PyObject_CallMethod0(L, PYIDENT("pop")); } static CYTHON_INLINE PyObject* __Pyx_PyList_Pop(PyObject* L) { #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02040000 /* Check that both the size is positive and no reallocation shrinking needs to be done. */ if (likely(PyList_GET_SIZE(L) > (((PyListObject*)L)->allocated >> 1))) { Py_SIZE(L) -= 1; return PyList_GET_ITEM(L, PyList_GET_SIZE(L)); } #endif return __Pyx_PyObject_CallMethod0(L, PYIDENT("pop")); } /////////////// pop_index.proto /////////////// #define __Pyx_PyObject_PopIndex(L, ix) (PyList_CheckExact(L) ? \ __Pyx_PyList_PopIndex(L, ix) : __Pyx__PyObject_PopIndex(L, ix)) static PyObject* __Pyx_PyList_PopIndex(PyObject* L, Py_ssize_t ix); /*proto*/ static PyObject* __Pyx__PyObject_PopIndex(PyObject* L, Py_ssize_t ix); /*proto*/ /////////////// pop_index /////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static PyObject* __Pyx__PyObject_PopIndex(PyObject* L, Py_ssize_t ix) { PyObject *r, *py_ix; py_ix = PyInt_FromSsize_t(ix); if (!py_ix) return NULL; r = __Pyx_PyObject_CallMethod1(L, PYIDENT("pop"), py_ix); Py_DECREF(py_ix); return r; } static PyObject* __Pyx_PyList_PopIndex(PyObject* L, Py_ssize_t ix) { #if CYTHON_COMPILING_IN_CPYTHON Py_ssize_t size = PyList_GET_SIZE(L); if (likely(size > (((PyListObject*)L)->allocated >> 1))) { Py_ssize_t cix = ix; if (cix < 0) { cix += size; } if (likely(0 <= cix && cix < size)) { PyObject* v = PyList_GET_ITEM(L, cix); Py_SIZE(L) -= 1; size -= 1; memmove(&PyList_GET_ITEM(L, cix), &PyList_GET_ITEM(L, cix+1), (size-cix)*sizeof(PyObject*)); return v; } } #endif return __Pyx__PyObject_PopIndex(L, ix); } /////////////// dict_getitem_default.proto /////////////// static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObject* default_value); /*proto*/ /////////////// dict_getitem_default /////////////// static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObject* default_value) { PyObject* value; #if PY_MAJOR_VERSION >= 3 value = PyDict_GetItemWithError(d, key); if (unlikely(!value)) { if (unlikely(PyErr_Occurred())) return NULL; value = default_value; } Py_INCREF(value); #else if (PyString_CheckExact(key) || PyUnicode_CheckExact(key) || PyInt_CheckExact(key)) { /* these presumably have safe hash functions */ value = PyDict_GetItem(d, key); if (unlikely(!value)) { value = default_value; } Py_INCREF(value); } else { if (default_value == Py_None) default_value = NULL; value = PyObject_CallMethodObjArgs( d, PYIDENT("get"), key, default_value, NULL); } #endif return value; } /////////////// dict_setdefault.proto /////////////// static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value, int is_safe_type); /*proto*/ /////////////// dict_setdefault /////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value, CYTHON_UNUSED int is_safe_type) { PyObject* value; #if PY_VERSION_HEX >= 0x030400A0 // we keep the method call at the end to avoid "unused" C compiler warnings if (1) { value = PyDict_SetDefault(d, key, default_value); if (unlikely(!value)) return NULL; Py_INCREF(value); #else if (is_safe_type == 1 || (is_safe_type == -1 && /* the following builtins presumably have repeatably safe and fast hash functions */ #if PY_MAJOR_VERSION >= 3 (PyUnicode_CheckExact(key) || PyString_CheckExact(key) || PyLong_CheckExact(key)))) { value = PyDict_GetItemWithError(d, key); if (unlikely(!value)) { if (unlikely(PyErr_Occurred())) return NULL; if (unlikely(PyDict_SetItem(d, key, default_value) == -1)) return NULL; value = default_value; } Py_INCREF(value); #else (PyString_CheckExact(key) || PyUnicode_CheckExact(key) || PyInt_CheckExact(key) || PyLong_CheckExact(key)))) { value = PyDict_GetItem(d, key); if (unlikely(!value)) { if (unlikely(PyDict_SetItem(d, key, default_value) == -1)) return NULL; value = default_value; } Py_INCREF(value); #endif #endif } else { value = __Pyx_PyObject_CallMethod2(d, PYIDENT("setdefault"), key, default_value); } return value; } /////////////// py_dict_clear.proto /////////////// #define __Pyx_PyDict_Clear(d) (PyDict_Clear(d), 0) /////////////// dict_iter.proto /////////////// static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* dict, int is_dict, PyObject* method_name, Py_ssize_t* p_orig_length, int* p_is_dict); static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t orig_length, Py_ssize_t* ppos, PyObject** pkey, PyObject** pvalue, PyObject** pitem, int is_dict); /////////////// dict_iter /////////////// //@requires: ObjectHandling.c::UnpackTuple2 //@requires: ObjectHandling.c::IterFinish //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* iterable, int is_dict, PyObject* method_name, Py_ssize_t* p_orig_length, int* p_source_is_dict) { is_dict = is_dict || likely(PyDict_CheckExact(iterable)); *p_source_is_dict = is_dict; #if !CYTHON_COMPILING_IN_PYPY if (is_dict) { *p_orig_length = PyDict_Size(iterable); Py_INCREF(iterable); return iterable; } #endif *p_orig_length = 0; if (method_name) { PyObject* iter; iterable = __Pyx_PyObject_CallMethod0(iterable, method_name); if (!iterable) return NULL; #if !CYTHON_COMPILING_IN_PYPY if (PyTuple_CheckExact(iterable) || PyList_CheckExact(iterable)) return iterable; #endif iter = PyObject_GetIter(iterable); Py_DECREF(iterable); return iter; } return PyObject_GetIter(iterable); } static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* iter_obj, Py_ssize_t orig_length, Py_ssize_t* ppos, PyObject** pkey, PyObject** pvalue, PyObject** pitem, int source_is_dict) { PyObject* next_item; #if !CYTHON_COMPILING_IN_PYPY if (source_is_dict) { PyObject *key, *value; if (unlikely(orig_length != PyDict_Size(iter_obj))) { PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration"); return -1; } if (unlikely(!PyDict_Next(iter_obj, ppos, &key, &value))) { return 0; } if (pitem) { PyObject* tuple = PyTuple_New(2); if (unlikely(!tuple)) { return -1; } Py_INCREF(key); Py_INCREF(value); PyTuple_SET_ITEM(tuple, 0, key); PyTuple_SET_ITEM(tuple, 1, value); *pitem = tuple; } else { if (pkey) { Py_INCREF(key); *pkey = key; } if (pvalue) { Py_INCREF(value); *pvalue = value; } } return 1; } else if (PyTuple_CheckExact(iter_obj)) { Py_ssize_t pos = *ppos; if (unlikely(pos >= PyTuple_GET_SIZE(iter_obj))) return 0; *ppos = pos + 1; next_item = PyTuple_GET_ITEM(iter_obj, pos); Py_INCREF(next_item); } else if (PyList_CheckExact(iter_obj)) { Py_ssize_t pos = *ppos; if (unlikely(pos >= PyList_GET_SIZE(iter_obj))) return 0; *ppos = pos + 1; next_item = PyList_GET_ITEM(iter_obj, pos); Py_INCREF(next_item); } else #endif { next_item = PyIter_Next(iter_obj); if (unlikely(!next_item)) { return __Pyx_IterFinish(); } } if (pitem) { *pitem = next_item; } else if (pkey && pvalue) { if (__Pyx_unpack_tuple2(next_item, pkey, pvalue, source_is_dict, source_is_dict, 1)) return -1; } else if (pkey) { *pkey = next_item; } else { *pvalue = next_item; } return 1; } /////////////// unicode_iter.proto /////////////// static CYTHON_INLINE int __Pyx_init_unicode_iteration( PyObject* ustring, Py_ssize_t *length, void** data, int *kind); /* proto */ /////////////// unicode_iter /////////////// static CYTHON_INLINE int __Pyx_init_unicode_iteration( PyObject* ustring, Py_ssize_t *length, void** data, int *kind) { #if CYTHON_PEP393_ENABLED if (unlikely(__Pyx_PyUnicode_READY(ustring) < 0)) return -1; *kind = PyUnicode_KIND(ustring); *length = PyUnicode_GET_LENGTH(ustring); *data = PyUnicode_DATA(ustring); #else *kind = 0; *length = PyUnicode_GET_SIZE(ustring); *data = (void*)PyUnicode_AS_UNICODE(ustring); #endif return 0; } /////////////// pyobject_as_double.proto /////////////// static double __Pyx__PyObject_AsDouble(PyObject* obj); /* proto */ #if CYTHON_COMPILING_IN_PYPY #define __Pyx_PyObject_AsDouble(obj) \ (likely(PyFloat_CheckExact(obj)) ? PyFloat_AS_DOUBLE(obj) : \ likely(PyInt_CheckExact(obj)) ? \ PyFloat_AsDouble(obj) : __Pyx__PyObject_AsDouble(obj)) #else #define __Pyx_PyObject_AsDouble(obj) \ ((likely(PyFloat_CheckExact(obj))) ? \ PyFloat_AS_DOUBLE(obj) : __Pyx__PyObject_AsDouble(obj)) #endif /////////////// pyobject_as_double /////////////// static double __Pyx__PyObject_AsDouble(PyObject* obj) { PyObject* float_value; #if CYTHON_COMPILING_IN_PYPY float_value = PyNumber_Float(obj); #else PyNumberMethods *nb = Py_TYPE(obj)->tp_as_number; if (likely(nb) && likely(nb->nb_float)) { float_value = nb->nb_float(obj); if (likely(float_value) && unlikely(!PyFloat_Check(float_value))) { PyErr_Format(PyExc_TypeError, "__float__ returned non-float (type %.200s)", Py_TYPE(float_value)->tp_name); Py_DECREF(float_value); goto bad; } } else if (PyUnicode_CheckExact(obj) || PyBytes_CheckExact(obj)) { #if PY_MAJOR_VERSION >= 3 float_value = PyFloat_FromString(obj); #else float_value = PyFloat_FromString(obj, 0); #endif } else { PyObject* args = PyTuple_New(1); if (unlikely(!args)) goto bad; PyTuple_SET_ITEM(args, 0, obj); float_value = PyObject_Call((PyObject*)&PyFloat_Type, args, 0); PyTuple_SET_ITEM(args, 0, 0); Py_DECREF(args); } #endif if (likely(float_value)) { double value = PyFloat_AS_DOUBLE(float_value); Py_DECREF(float_value); return value; } bad: return (double)-1; } cython-0.20.1+git90-g0e6e38e/Cython/Utility/Overflow.c000066400000000000000000000263721231323242300221350ustar00rootroot00000000000000/* These functions provide integer arithmetic with integer checking. They do not actually raise an exception when an overflow is detected, but rather set a bit in the overflow parameter. (This parameter may be re-used accross several arithmetic operations, so should be or-ed rather than assigned to.) The implementation is divided into two parts, the signed and unsigned basecases, which is where the magic happens, and a generic template matching a specific type to an implementation based on its (c-compile-time) size and signedness. When possible, branching is avoided, and preference is given to speed over accuracy (a low rate of falsely "detected" overflows are acceptable, undetected overflows are not). TODO: Hook up checking. TODO: Conditionally support 128-bit with intmax_t? */ /////////////// Common.proto /////////////// static int __Pyx_check_twos_complement(void) { if (-1 != ~0) { PyErr_SetString(PyExc_RuntimeError, "Two's complement required for overflow checks."); return 1; } else if (sizeof(short) == sizeof(int)) { PyErr_SetString(PyExc_RuntimeError, "sizeof(short) < sizeof(int) required for overflow checks."); return 1; } else { return 0; } } #define __PYX_IS_UNSIGNED(type) (((type) -1) > 0) #define __PYX_SIGN_BIT(type) (((unsigned type) 1) << (sizeof(type) * 8 - 1)) #define __PYX_HALF_MAX(type) (((type) 1) << (sizeof(type) * 8 - 2)) #define __PYX_MIN(type) (__PYX_IS_UNSIGNED(type) ? (type) 0 : 0 - __PYX_HALF_MAX(type) - __PYX_HALF_MAX(type)) #define __PYX_MAX(type) (~__PYX_MIN(type)) #define __Pyx_add_no_overflow(a, b, overflow) ((a) + (b)) #define __Pyx_add_const_no_overflow(a, b, overflow) ((a) + (b)) #define __Pyx_sub_no_overflow(a, b, overflow) ((a) - (b)) #define __Pyx_sub_const_no_overflow(a, b, overflow) ((a) - (b)) #define __Pyx_mul_no_overflow(a, b, overflow) ((a) * (b)) #define __Pyx_mul_const_no_overflow(a, b, overflow) ((a) * (b)) #define __Pyx_div_no_overflow(a, b, overflow) ((a) / (b)) #define __Pyx_div_const_no_overflow(a, b, overflow) ((a) / (b)) /////////////// Common.init /////////////// __Pyx_check_twos_complement(); /////////////// BaseCaseUnsigned.proto /////////////// static CYTHON_INLINE {{UINT}} __Pyx_add_{{NAME}}_checking_overflow({{UINT}} a, {{UINT}} b, int *overflow); static CYTHON_INLINE {{UINT}} __Pyx_sub_{{NAME}}_checking_overflow({{UINT}} a, {{UINT}} b, int *overflow); static CYTHON_INLINE {{UINT}} __Pyx_mul_{{NAME}}_checking_overflow({{UINT}} a, {{UINT}} b, int *overflow); static CYTHON_INLINE {{UINT}} __Pyx_div_{{NAME}}_checking_overflow({{UINT}} a, {{UINT}} b, int *overflow); // Use these when b is known at compile time. #define __Pyx_add_const_{{NAME}}_checking_overflow __Pyx_add_{{NAME}}_checking_overflow #define __Pyx_sub_const_{{NAME}}_checking_overflow __Pyx_sub_{{NAME}}_checking_overflow static CYTHON_INLINE {{UINT}} __Pyx_mul_const_{{NAME}}_checking_overflow({{UINT}} a, {{UINT}} constant, int *overflow); #define __Pyx_div_const_{{NAME}}_checking_overflow __Pyx_div_{{NAME}}_checking_overflow /////////////// BaseCaseUnsigned /////////////// static CYTHON_INLINE {{UINT}} __Pyx_add_{{NAME}}_checking_overflow({{UINT}} a, {{UINT}} b, int *overflow) { {{UINT}} r = a + b; *overflow |= r < a; return r; } static CYTHON_INLINE {{UINT}} __Pyx_sub_{{NAME}}_checking_overflow({{UINT}} a, {{UINT}} b, int *overflow) { {{UINT}} r = a - b; *overflow |= r > a; return r; } static CYTHON_INLINE {{UINT}} __Pyx_mul_{{NAME}}_checking_overflow({{UINT}} a, {{UINT}} b, int *overflow) { if (sizeof({{UINT}}) < sizeof(unsigned long)) { unsigned long big_r = ((unsigned long) a) * ((unsigned long) b); {{UINT}} r = ({{UINT}}) big_r; *overflow |= big_r != r; return r; } else if (sizeof({{UINT}}) < sizeof(unsigned long long)) { unsigned long long big_r = ((unsigned long long) a) * ((unsigned long long) b); {{UINT}} r = ({{UINT}}) big_r; *overflow |= big_r != r; return r; } else { {{UINT}} prod = a * b; double dprod = ((double) a) * ((double) b); // Overflow results in an error of at least 2^sizeof(UINT), // whereas rounding represents an error on the order of 2^(sizeof(UINT)-53). *overflow |= fabs(dprod - prod) > (__PYX_MAX({{UINT}}) / 2); return prod; } } static CYTHON_INLINE {{UINT}} __Pyx_mul_const_{{NAME}}_checking_overflow({{UINT}} a, {{UINT}} b, int *overflow) { if (b > 1) { *overflow |= a > __PYX_MAX({{UINT}}) / b; } return a * b; } static CYTHON_INLINE {{UINT}} __Pyx_div_{{NAME}}_checking_overflow({{UINT}} a, {{UINT}} b, int *overflow) { if (b == 0) { *overflow |= 1; return 0; } return a / b; } /////////////// BaseCaseSigned.proto /////////////// static CYTHON_INLINE {{INT}} __Pyx_add_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow); static CYTHON_INLINE {{INT}} __Pyx_sub_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow); static CYTHON_INLINE {{INT}} __Pyx_mul_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow); static CYTHON_INLINE {{INT}} __Pyx_div_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow); // Use when b is known at compile time. static CYTHON_INLINE {{INT}} __Pyx_add_const_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow); static CYTHON_INLINE {{INT}} __Pyx_sub_const_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow); static CYTHON_INLINE {{INT}} __Pyx_mul_const_{{NAME}}_checking_overflow({{INT}} a, {{INT}} constant, int *overflow); #define __Pyx_div_const_{{NAME}}_checking_overflow __Pyx_div_{{NAME}}_checking_overflow /////////////// BaseCaseSigned /////////////// static CYTHON_INLINE {{INT}} __Pyx_add_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow) { if (sizeof({{INT}}) < sizeof(long)) { long big_r = ((long) a) + ((long) b); {{INT}} r = ({{INT}}) big_r; *overflow |= big_r != r; return r; } else if (sizeof({{INT}}) < sizeof(long long)) { long long big_r = ((long long) a) + ((long long) b); {{INT}} r = ({{INT}}) big_r; *overflow |= big_r != r; return r; } else { // Signed overflow undefined, but unsigned overflow is well defined. {{INT}} r = ({{INT}}) ((unsigned {{INT}}) a + (unsigned {{INT}}) b); // Overflow happened if the operands have the same sign, but the result // has opposite sign. // sign(a) == sign(b) != sign(r) {{INT}} sign_a = __PYX_SIGN_BIT({{INT}}) & a; {{INT}} sign_b = __PYX_SIGN_BIT({{INT}}) & b; {{INT}} sign_r = __PYX_SIGN_BIT({{INT}}) & r; *overflow |= (sign_a == sign_b) & (sign_a != sign_r); return r; } } static CYTHON_INLINE {{INT}} __Pyx_add_const_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow) { if (b > 0) { *overflow |= a > __PYX_MAX({{INT}}) - b; } else if (b < 0) { *overflow |= a < __PYX_MIN({{INT}}) - b; } return a + b; } static CYTHON_INLINE {{INT}} __Pyx_sub_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow) { *overflow |= b == __PYX_MIN({{INT}}); return __Pyx_add_{{NAME}}_checking_overflow(a, -b, overflow); } static CYTHON_INLINE {{INT}} __Pyx_sub_const_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow) { *overflow |= b == __PYX_MIN({{INT}}); return __Pyx_add_const_{{NAME}}_checking_overflow(a, -b, overflow); } static CYTHON_INLINE {{INT}} __Pyx_mul_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow) { if (sizeof({{INT}}) < sizeof(long)) { long big_r = ((long) a) * ((long) b); {{INT}} r = ({{INT}}) big_r; *overflow |= big_r != r; return ({{INT}}) r; } else if (sizeof({{INT}}) < sizeof(long long)) { long long big_r = ((long long) a) * ((long long) b); {{INT}} r = ({{INT}}) big_r; *overflow |= big_r != r; return ({{INT}}) r; } else { {{INT}} prod = a * b; double dprod = ((double) a) * ((double) b); // Overflow results in an error of at least 2^sizeof(INT), // whereas rounding represents an error on the order of 2^(sizeof(INT)-53). *overflow |= fabs(dprod - prod) > (__PYX_MAX({{INT}}) / 2); return prod; } } static CYTHON_INLINE {{INT}} __Pyx_mul_const_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow) { if (b > 1) { *overflow |= a > __PYX_MAX({{INT}}) / b; *overflow |= a < __PYX_MIN({{INT}}) / b; } else if (b == -1) { *overflow |= a == __PYX_MIN({{INT}}); } else if (b < -1) { *overflow |= a > __PYX_MIN({{INT}}) / b; *overflow |= a < __PYX_MAX({{INT}}) / b; } return a * b; } static CYTHON_INLINE {{INT}} __Pyx_div_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow) { if (b == 0) { *overflow |= 1; return 0; } *overflow |= (a == __PYX_MIN({{INT}})) & (b == -1); return a / b; } /////////////// SizeCheck.init /////////////// __Pyx_check_sane_{{NAME}}(); /////////////// SizeCheck.proto /////////////// static int __Pyx_check_sane_{{NAME}}(void) { if (sizeof({{TYPE}}) <= sizeof(int) || sizeof({{TYPE}}) == sizeof(long) || sizeof({{TYPE}}) == sizeof(long long)) { return 0; } else { PyErr_Format(PyExc_RuntimeError, \ "Bad size for int type %.{{max(60, len(TYPE))}}s: %d", "{{TYPE}}", (int) sizeof({{TYPE}})); return 1; } } /////////////// Binop.proto /////////////// static CYTHON_INLINE {{TYPE}} __Pyx_{{BINOP}}_{{NAME}}_checking_overflow({{TYPE}} a, {{TYPE}} b, int *overflow); /////////////// Binop /////////////// static CYTHON_INLINE {{TYPE}} __Pyx_{{BINOP}}_{{NAME}}_checking_overflow({{TYPE}} a, {{TYPE}} b, int *overflow) { if (sizeof({{TYPE}}) < sizeof(int)) { return __Pyx_{{BINOP}}_no_overflow(a, b, overflow); } else if (__PYX_IS_UNSIGNED({{TYPE}})) { if (sizeof({{TYPE}}) == sizeof(unsigned int)) { return __Pyx_{{BINOP}}_unsigned_int_checking_overflow(a, b, overflow); } else if (sizeof({{TYPE}}) == sizeof(unsigned long)) { return __Pyx_{{BINOP}}_unsigned_long_checking_overflow(a, b, overflow); } else if (sizeof({{TYPE}}) == sizeof(unsigned long long)) { return __Pyx_{{BINOP}}_unsigned_long_long_checking_overflow(a, b, overflow); } else { abort(); return 0; // handled elsewhere } } else { if (sizeof({{TYPE}}) == sizeof(int)) { return __Pyx_{{BINOP}}_int_checking_overflow(a, b, overflow); } else if (sizeof({{TYPE}}) == sizeof(long)) { return __Pyx_{{BINOP}}_long_checking_overflow(a, b, overflow); } else if (sizeof({{TYPE}}) == sizeof(long long)) { return __Pyx_{{BINOP}}_long_long_checking_overflow(a, b, overflow); } else { abort(); return 0; // handled elsewhere } } } /////////////// LeftShift.proto /////////////// static CYTHON_INLINE {{TYPE}} __Pyx_lshift_{{NAME}}_checking_overflow({{TYPE}} a, {{TYPE}} b, int *overflow) { *overflow |= #if {{SIGNED}} (b < 0) | #endif (b > ({{TYPE}}) (8 * sizeof({{TYPE}}))) | (a > (__PYX_MAX({{TYPE}}) >> b)); return a << b; } #define __Pyx_lshift_const_{{NAME}}_checking_overflow __Pyx_lshift_{{NAME}}_checking_overflow cython-0.20.1+git90-g0e6e38e/Cython/Utility/Printing.c000066400000000000000000000117571231323242300221250ustar00rootroot00000000000000////////////////////// Print.proto ////////////////////// //@substitute: naming static int __Pyx_Print(PyObject*, PyObject *, int); /*proto*/ #if CYTHON_COMPILING_IN_PYPY || PY_MAJOR_VERSION >= 3 static PyObject* $print_function = 0; static PyObject* $print_function_kwargs = 0; #endif ////////////////////// Print.cleanup ////////////////////// //@substitute: naming #if CYTHON_COMPILING_IN_PYPY || PY_MAJOR_VERSION >= 3 Py_CLEAR($print_function); Py_CLEAR($print_function_kwargs); #endif ////////////////////// Print ////////////////////// //@substitute: naming #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION < 3 static PyObject *__Pyx_GetStdout(void) { PyObject *f = PySys_GetObject((char *)"stdout"); if (!f) { PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout"); } return f; } static int __Pyx_Print(PyObject* f, PyObject *arg_tuple, int newline) { int i; if (!f) { if (!(f = __Pyx_GetStdout())) return -1; } Py_INCREF(f); for (i=0; i < PyTuple_GET_SIZE(arg_tuple); i++) { PyObject* v; if (PyFile_SoftSpace(f, 1)) { if (PyFile_WriteString(" ", f) < 0) goto error; } v = PyTuple_GET_ITEM(arg_tuple, i); if (PyFile_WriteObject(v, f, Py_PRINT_RAW) < 0) goto error; if (PyString_Check(v)) { char *s = PyString_AsString(v); Py_ssize_t len = PyString_Size(v); if (len > 0) { // append soft-space if necessary (not using isspace() due to C/C++ problem on MacOS-X) switch (s[len-1]) { case ' ': break; case '\f': case '\r': case '\n': case '\t': case '\v': PyFile_SoftSpace(f, 0); break; default: break; } } } } if (newline) { if (PyFile_WriteString("\n", f) < 0) goto error; PyFile_SoftSpace(f, 0); } Py_DECREF(f); return 0; error: Py_DECREF(f); return -1; } #else /* Python 3 has a print function */ static int __Pyx_Print(PyObject* stream, PyObject *arg_tuple, int newline) { PyObject* kwargs = 0; PyObject* result = 0; PyObject* end_string; if (unlikely(!$print_function)) { $print_function = PyObject_GetAttr($builtins_cname, PYIDENT("print")); if (!$print_function) return -1; } if (stream) { kwargs = PyDict_New(); if (unlikely(!kwargs)) return -1; if (unlikely(PyDict_SetItem(kwargs, PYIDENT("file"), stream) < 0)) goto bad; if (!newline) { end_string = PyUnicode_FromStringAndSize(" ", 1); if (unlikely(!end_string)) goto bad; if (PyDict_SetItem(kwargs, PYIDENT("end"), end_string) < 0) { Py_DECREF(end_string); goto bad; } Py_DECREF(end_string); } } else if (!newline) { if (unlikely(!$print_function_kwargs)) { $print_function_kwargs = PyDict_New(); if (unlikely(!$print_function_kwargs)) return -1; end_string = PyUnicode_FromStringAndSize(" ", 1); if (unlikely(!end_string)) return -1; if (PyDict_SetItem($print_function_kwargs, PYIDENT("end"), end_string) < 0) { Py_DECREF(end_string); return -1; } Py_DECREF(end_string); } kwargs = $print_function_kwargs; } result = PyObject_Call($print_function, arg_tuple, kwargs); if (unlikely(kwargs) && (kwargs != $print_function_kwargs)) Py_DECREF(kwargs); if (!result) return -1; Py_DECREF(result); return 0; bad: if (kwargs != $print_function_kwargs) Py_XDECREF(kwargs); return -1; } #endif ////////////////////// PrintOne.proto ////////////////////// //@requires: Print static int __Pyx_PrintOne(PyObject* stream, PyObject *o); /*proto*/ ////////////////////// PrintOne ////////////////////// #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION < 3 static int __Pyx_PrintOne(PyObject* f, PyObject *o) { if (!f) { if (!(f = __Pyx_GetStdout())) return -1; } Py_INCREF(f); if (PyFile_SoftSpace(f, 0)) { if (PyFile_WriteString(" ", f) < 0) goto error; } if (PyFile_WriteObject(o, f, Py_PRINT_RAW) < 0) goto error; if (PyFile_WriteString("\n", f) < 0) goto error; Py_DECREF(f); return 0; error: Py_DECREF(f); return -1; /* the line below is just to avoid C compiler * warnings about unused functions */ return __Pyx_Print(f, NULL, 0); } #else /* Python 3 has a print function */ static int __Pyx_PrintOne(PyObject* stream, PyObject *o) { int res; PyObject* arg_tuple = PyTuple_Pack(1, o); if (unlikely(!arg_tuple)) return -1; res = __Pyx_Print(stream, arg_tuple, 1); Py_DECREF(arg_tuple); return res; } #endif cython-0.20.1+git90-g0e6e38e/Cython/Utility/Profile.c000066400000000000000000000201621231323242300217210ustar00rootroot00000000000000/////////////// Profile.proto /////////////// //@substitute: naming // Note that cPython ignores PyTrace_EXCEPTION, // but maybe some other profilers don't. #ifndef CYTHON_PROFILE #define CYTHON_PROFILE 1 #endif #ifndef CYTHON_TRACE #define CYTHON_TRACE 0 #endif #if CYTHON_TRACE #undef CYTHON_PROFILE_REUSE_FRAME #endif #ifndef CYTHON_PROFILE_REUSE_FRAME #define CYTHON_PROFILE_REUSE_FRAME 0 #endif #if CYTHON_PROFILE || CYTHON_TRACE #include "compile.h" #include "frameobject.h" #include "traceback.h" #if CYTHON_PROFILE_REUSE_FRAME #define CYTHON_FRAME_MODIFIER static #define CYTHON_FRAME_DEL #else #define CYTHON_FRAME_MODIFIER #define CYTHON_FRAME_DEL Py_CLEAR($frame_cname) #endif #define __Pyx_TraceDeclarations \ static PyCodeObject *$frame_code_cname = NULL; \ CYTHON_FRAME_MODIFIER PyFrameObject *$frame_cname = NULL; \ int __Pyx_use_tracing = 0; #define __Pyx_TraceCall(funcname, srcfile, firstlineno) \ if (unlikely(PyThreadState_GET()->use_tracing && \ (PyThreadState_GET()->c_profilefunc || (CYTHON_TRACE && PyThreadState_GET()->c_tracefunc)))) { \ __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&$frame_code_cname, &$frame_cname, funcname, srcfile, firstlineno); \ } #define __Pyx_TraceException() \ if (unlikely(__Pyx_use_tracing) && PyThreadState_GET()->use_tracing && \ (PyThreadState_GET()->c_profilefunc || (CYTHON_TRACE && PyThreadState_GET()->c_tracefunc))) { \ PyThreadState* tstate = PyThreadState_GET(); \ tstate->use_tracing = 0; \ PyObject *exc_info = __Pyx_GetExceptionTuple(); \ if (exc_info) { \ if (CYTHON_TRACE && tstate->c_tracefunc) \ tstate->c_tracefunc( \ tstate->c_traceobj, $frame_cname, PyTrace_EXCEPTION, exc_info); \ tstate->c_profilefunc( \ tstate->c_profileobj, $frame_cname, PyTrace_EXCEPTION, exc_info); \ Py_DECREF(exc_info); \ } \ tstate->use_tracing = 1; \ } #define __Pyx_TraceReturn(result) \ if (unlikely(__Pyx_use_tracing) && PyThreadState_GET()->use_tracing) { \ PyThreadState* tstate = PyThreadState_GET(); \ tstate->use_tracing = 0; \ if (CYTHON_TRACE && tstate->c_tracefunc) \ tstate->c_tracefunc( \ tstate->c_traceobj, $frame_cname, PyTrace_RETURN, (PyObject*)result); \ if (tstate->c_profilefunc) \ tstate->c_profilefunc( \ tstate->c_profileobj, $frame_cname, PyTrace_RETURN, (PyObject*)result); \ CYTHON_FRAME_DEL; \ tstate->use_tracing = 1; \ } static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno); /*proto*/ static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, const char *funcname, const char *srcfile, int firstlineno); /*proto*/ #else #define __Pyx_TraceDeclarations #define __Pyx_TraceCall(funcname, srcfile, firstlineno) #define __Pyx_TraceException() #define __Pyx_TraceReturn(result) #endif /* CYTHON_PROFILE */ #if CYTHON_TRACE #define __Pyx_TraceLine(lineno) \ if (unlikely(__Pyx_use_tracing) && unlikely(PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_tracefunc)) { \ PyThreadState* tstate = PyThreadState_GET(); \ $frame_cname->f_lineno = lineno; \ tstate->use_tracing = 0; \ tstate->c_tracefunc(tstate->c_traceobj, $frame_cname, PyTrace_LINE, NULL); \ tstate->use_tracing = 1; \ } #else #define __Pyx_TraceLine(lineno) #endif /////////////// Profile /////////////// //@substitute: naming #if CYTHON_PROFILE static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, const char *funcname, const char *srcfile, int firstlineno) { int retval; PyThreadState* tstate = PyThreadState_GET(); if (*frame == NULL || !CYTHON_PROFILE_REUSE_FRAME) { if (*code == NULL) { *code = __Pyx_createFrameCodeObject(funcname, srcfile, firstlineno); if (*code == NULL) return 0; } *frame = PyFrame_New( tstate, /*PyThreadState *tstate*/ *code, /*PyCodeObject *code*/ $moddict_cname, /*PyObject *globals*/ 0 /*PyObject *locals*/ ); if (*frame == NULL) return 0; if (CYTHON_TRACE && (*frame)->f_trace == NULL) { // this enables "f_lineno" lookup, at least in CPython ... Py_INCREF(Py_None); (*frame)->f_trace = Py_None; } #if PY_VERSION_HEX < 0x030400B1 } else { (*frame)->f_tstate = tstate; #endif } (*frame)->f_lineno = firstlineno; tstate->use_tracing = 0; #if CYTHON_TRACE if (tstate->c_tracefunc) tstate->c_tracefunc(tstate->c_traceobj, *frame, PyTrace_CALL, NULL); if (!tstate->c_profilefunc) retval = 1; else #endif retval = tstate->c_profilefunc(tstate->c_profileobj, *frame, PyTrace_CALL, NULL) == 0; tstate->use_tracing = (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc)); return tstate->use_tracing && retval; } static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno) { PyObject *py_srcfile = 0; PyObject *py_funcname = 0; PyCodeObject *py_code = 0; #if PY_MAJOR_VERSION < 3 py_funcname = PyString_FromString(funcname); py_srcfile = PyString_FromString(srcfile); #else py_funcname = PyUnicode_FromString(funcname); py_srcfile = PyUnicode_FromString(srcfile); #endif if (!py_funcname | !py_srcfile) goto bad; py_code = PyCode_New( 0, /*int argcount,*/ #if PY_MAJOR_VERSION >= 3 0, /*int kwonlyargcount,*/ #endif 0, /*int nlocals,*/ 0, /*int stacksize,*/ 0, /*int flags,*/ $empty_bytes, /*PyObject *code,*/ $empty_tuple, /*PyObject *consts,*/ $empty_tuple, /*PyObject *names,*/ $empty_tuple, /*PyObject *varnames,*/ $empty_tuple, /*PyObject *freevars,*/ $empty_tuple, /*PyObject *cellvars,*/ py_srcfile, /*PyObject *filename,*/ py_funcname, /*PyObject *name,*/ firstlineno, /*int firstlineno,*/ $empty_bytes /*PyObject *lnotab*/ ); bad: Py_XDECREF(py_srcfile); Py_XDECREF(py_funcname); return py_code; } #endif /* CYTHON_PROFILE */ cython-0.20.1+git90-g0e6e38e/Cython/Utility/StringTools.c000066400000000000000000000650321231323242300226150ustar00rootroot00000000000000 //////////////////// IncludeStringH.proto //////////////////// #include //////////////////// IncludeCppStringH.proto //////////////////// #include //////////////////// InitStrings.proto //////////////////// static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ //////////////////// InitStrings //////////////////// static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { while (t->p) { #if PY_MAJOR_VERSION < 3 if (t->is_unicode) { *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); } else if (t->intern) { *t->p = PyString_InternFromString(t->s); } else { *t->p = PyString_FromStringAndSize(t->s, t->n - 1); } #else /* Python 3+ has unicode identifiers */ if (t->is_unicode | t->is_str) { if (t->intern) { *t->p = PyUnicode_InternFromString(t->s); } else if (t->encoding) { *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); } else { *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); } } else { *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); } #endif if (!*t->p) return -1; ++t; } return 0; } //////////////////// BytesContains.proto //////////////////// static CYTHON_INLINE int __Pyx_BytesContains(PyObject* bytes, char character); /*proto*/ //////////////////// BytesContains //////////////////// static CYTHON_INLINE int __Pyx_BytesContains(PyObject* bytes, char character) { const Py_ssize_t length = PyBytes_GET_SIZE(bytes); char* char_start = PyBytes_AS_STRING(bytes); char* pos; for (pos=char_start; pos < char_start+length; pos++) { if (character == pos[0]) return 1; } return 0; } //////////////////// PyUCS4InUnicode.proto //////////////////// static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 character); /*proto*/ static CYTHON_INLINE int __Pyx_PyUnicodeBufferContainsUCS4(Py_UNICODE* buffer, Py_ssize_t length, Py_UCS4 character); /*proto*/ //////////////////// PyUCS4InUnicode //////////////////// static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 character) { #if CYTHON_PEP393_ENABLED const int kind = PyUnicode_KIND(unicode); if (likely(kind != PyUnicode_WCHAR_KIND)) { Py_ssize_t i; const void* udata = PyUnicode_DATA(unicode); const Py_ssize_t length = PyUnicode_GET_LENGTH(unicode); for (i=0; i < length; i++) { if (unlikely(character == PyUnicode_READ(kind, udata, i))) return 1; } return 0; } #endif return __Pyx_PyUnicodeBufferContainsUCS4( PyUnicode_AS_UNICODE(unicode), PyUnicode_GET_SIZE(unicode), character); } static CYTHON_INLINE int __Pyx_PyUnicodeBufferContainsUCS4(Py_UNICODE* buffer, Py_ssize_t length, Py_UCS4 character) { Py_UNICODE uchar; Py_UNICODE* pos; #if Py_UNICODE_SIZE == 2 if (character > 65535) { /* handle surrogate pairs for Py_UNICODE buffers in 16bit Unicode builds */ Py_UNICODE high_val, low_val; high_val = (Py_UNICODE) (0xD800 | (((character - 0x10000) >> 10) & ((1<<10)-1))); low_val = (Py_UNICODE) (0xDC00 | ( (character - 0x10000) & ((1<<10)-1))); for (pos=buffer; pos < buffer+length-1; pos++) { if (unlikely(high_val == pos[0]) & unlikely(low_val == pos[1])) return 1; } return 0; } #endif uchar = (Py_UNICODE) character; for (pos=buffer; pos < buffer+length; pos++) { if (unlikely(uchar == pos[0])) return 1; } return 0; } //////////////////// PyUnicodeContains.proto //////////////////// static CYTHON_INLINE int __Pyx_PyUnicode_Contains(PyObject* substring, PyObject* text, int eq) { int result = PyUnicode_Contains(text, substring); return unlikely(result < 0) ? result : (result == (eq == Py_EQ)); } //////////////////// StrEquals.proto //////////////////// //@requires: BytesEquals //@requires: UnicodeEquals #if PY_MAJOR_VERSION >= 3 #define __Pyx_PyString_Equals __Pyx_PyUnicode_Equals #else #define __Pyx_PyString_Equals __Pyx_PyBytes_Equals #endif //////////////////// UnicodeEquals.proto //////////////////// static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); /*proto*/ //////////////////// UnicodeEquals //////////////////// //@requires: BytesEquals static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { #if CYTHON_COMPILING_IN_PYPY return PyObject_RichCompareBool(s1, s2, equals); #else #if PY_MAJOR_VERSION < 3 PyObject* owned_ref = NULL; #endif int s1_is_unicode, s2_is_unicode; if (s1 == s2) { /* as done by PyObject_RichCompareBool(); also catches the (interned) empty string */ goto return_eq; } s1_is_unicode = PyUnicode_CheckExact(s1); s2_is_unicode = PyUnicode_CheckExact(s2); #if PY_MAJOR_VERSION < 3 if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { owned_ref = PyUnicode_FromObject(s2); if (unlikely(!owned_ref)) return -1; s2 = owned_ref; s2_is_unicode = 1; } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { owned_ref = PyUnicode_FromObject(s1); if (unlikely(!owned_ref)) return -1; s1 = owned_ref; s1_is_unicode = 1; } else if (((!s2_is_unicode) & (!s1_is_unicode))) { return __Pyx_PyBytes_Equals(s1, s2, equals); } #endif if (s1_is_unicode & s2_is_unicode) { Py_ssize_t length; int kind; void *data1, *data2; #if CYTHON_PEP393_ENABLED if (unlikely(PyUnicode_READY(s1) < 0) || unlikely(PyUnicode_READY(s2) < 0)) return -1; #endif length = __Pyx_PyUnicode_GET_LENGTH(s1); if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { goto return_ne; } // len(s1) == len(s2) >= 1 (empty string is interned, and "s1 is not s2") kind = __Pyx_PyUnicode_KIND(s1); if (kind != __Pyx_PyUnicode_KIND(s2)) { goto return_ne; } data1 = __Pyx_PyUnicode_DATA(s1); data2 = __Pyx_PyUnicode_DATA(s2); if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { goto return_ne; } else if (length == 1) { goto return_eq; } else { int result = memcmp(data1, data2, length * kind); #if PY_MAJOR_VERSION < 3 Py_XDECREF(owned_ref); #endif return (equals == Py_EQ) ? (result == 0) : (result != 0); } } else if ((s1 == Py_None) & s2_is_unicode) { goto return_ne; } else if ((s2 == Py_None) & s1_is_unicode) { goto return_ne; } else { int result; PyObject* py_result = PyObject_RichCompare(s1, s2, equals); if (!py_result) return -1; result = __Pyx_PyObject_IsTrue(py_result); Py_DECREF(py_result); return result; } return_eq: #if PY_MAJOR_VERSION < 3 Py_XDECREF(owned_ref); #endif return (equals == Py_EQ); return_ne: #if PY_MAJOR_VERSION < 3 Py_XDECREF(owned_ref); #endif return (equals == Py_NE); #endif } //////////////////// BytesEquals.proto //////////////////// static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); /*proto*/ //////////////////// BytesEquals //////////////////// //@requires: IncludeStringH static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { #if CYTHON_COMPILING_IN_PYPY return PyObject_RichCompareBool(s1, s2, equals); #else if (s1 == s2) { /* as done by PyObject_RichCompareBool(); also catches the (interned) empty string */ return (equals == Py_EQ); } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { const char *ps1, *ps2; Py_ssize_t length = PyBytes_GET_SIZE(s1); if (length != PyBytes_GET_SIZE(s2)) return (equals == Py_NE); // len(s1) == len(s2) >= 1 (empty string is interned, and "s1 is not s2") ps1 = PyBytes_AS_STRING(s1); ps2 = PyBytes_AS_STRING(s2); if (ps1[0] != ps2[0]) { return (equals == Py_NE); } else if (length == 1) { return (equals == Py_EQ); } else { int result = memcmp(ps1, ps2, (size_t)length); return (equals == Py_EQ) ? (result == 0) : (result != 0); } } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { return (equals == Py_NE); } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { return (equals == Py_NE); } else { int result; PyObject* py_result = PyObject_RichCompare(s1, s2, equals); if (!py_result) return -1; result = __Pyx_PyObject_IsTrue(py_result); Py_DECREF(py_result); return result; } #endif } //////////////////// GetItemIntByteArray.proto //////////////////// #define __Pyx_GetItemInt_ByteArray(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \ __Pyx_GetItemInt_ByteArray_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) : \ (PyErr_SetString(PyExc_IndexError, "bytearray index out of range"), -1)) static CYTHON_INLINE int __Pyx_GetItemInt_ByteArray_Fast(PyObject* string, Py_ssize_t i, int wraparound, int boundscheck); //////////////////// GetItemIntByteArray //////////////////// static CYTHON_INLINE int __Pyx_GetItemInt_ByteArray_Fast(PyObject* string, Py_ssize_t i, int wraparound, int boundscheck) { Py_ssize_t length; if (wraparound | boundscheck) { length = PyByteArray_GET_SIZE(string); if (wraparound & unlikely(i < 0)) i += length; if ((!boundscheck) || likely((0 <= i) & (i < length))) { return (unsigned char) (PyByteArray_AS_STRING(string)[i]); } else { PyErr_SetString(PyExc_IndexError, "bytearray index out of range"); return -1; } } else { return (unsigned char) (PyByteArray_AS_STRING(string)[i]); } } //////////////////// SetItemIntByteArray.proto //////////////////// #define __Pyx_SetItemInt_ByteArray(o, i, v, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \ __Pyx_SetItemInt_ByteArray_Fast(o, (Py_ssize_t)i, v, wraparound, boundscheck) : \ (PyErr_SetString(PyExc_IndexError, "bytearray index out of range"), -1)) static CYTHON_INLINE int __Pyx_SetItemInt_ByteArray_Fast(PyObject* string, Py_ssize_t i, unsigned char v, int wraparound, int boundscheck); //////////////////// SetItemIntByteArray //////////////////// static CYTHON_INLINE int __Pyx_SetItemInt_ByteArray_Fast(PyObject* string, Py_ssize_t i, unsigned char v, int wraparound, int boundscheck) { Py_ssize_t length; if (wraparound | boundscheck) { length = PyByteArray_GET_SIZE(string); if (wraparound & unlikely(i < 0)) i += length; if ((!boundscheck) || likely((0 <= i) & (i < length))) { PyByteArray_AS_STRING(string)[i] = (char) v; return 0; } else { PyErr_SetString(PyExc_IndexError, "bytearray index out of range"); return -1; } } else { PyByteArray_AS_STRING(string)[i] = (char) v; return 0; } } //////////////////// GetItemIntUnicode.proto //////////////////// #define __Pyx_GetItemInt_Unicode(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \ __Pyx_GetItemInt_Unicode_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) : \ (PyErr_SetString(PyExc_IndexError, "string index out of range"), (Py_UCS4)-1)) static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i, int wraparound, int boundscheck); //////////////////// GetItemIntUnicode //////////////////// static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i, int wraparound, int boundscheck) { Py_ssize_t length; #if CYTHON_PEP393_ENABLED if (unlikely(__Pyx_PyUnicode_READY(ustring) < 0)) return (Py_UCS4)-1; #endif if (wraparound | boundscheck) { length = __Pyx_PyUnicode_GET_LENGTH(ustring); if (wraparound & unlikely(i < 0)) i += length; if ((!boundscheck) || likely((0 <= i) & (i < length))) { return __Pyx_PyUnicode_READ_CHAR(ustring, i); } else { PyErr_SetString(PyExc_IndexError, "string index out of range"); return (Py_UCS4)-1; } } else { return __Pyx_PyUnicode_READ_CHAR(ustring, i); } } /////////////// decode_cpp_string.proto /////////////// //@requires: IncludeCppStringH //@requires: decode_c_bytes static CYTHON_INLINE PyObject* __Pyx_decode_cpp_string( std::string cppstring, Py_ssize_t start, Py_ssize_t stop, const char* encoding, const char* errors, PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) { return __Pyx_decode_c_bytes( cppstring.data(), cppstring.size(), start, stop, encoding, errors, decode_func); } /////////////// decode_c_string.proto /////////////// static CYTHON_INLINE PyObject* __Pyx_decode_c_string( const char* cstring, Py_ssize_t start, Py_ssize_t stop, const char* encoding, const char* errors, PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)); /////////////// decode_c_string /////////////// //@requires: IncludeStringH /* duplicate code to avoid calling strlen() if start >= 0 and stop >= 0 */ static CYTHON_INLINE PyObject* __Pyx_decode_c_string( const char* cstring, Py_ssize_t start, Py_ssize_t stop, const char* encoding, const char* errors, PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) { Py_ssize_t length; if (unlikely((start < 0) | (stop < 0))) { length = strlen(cstring); if (start < 0) { start += length; if (start < 0) start = 0; } if (stop < 0) stop += length; } length = stop - start; if (unlikely(length <= 0)) return PyUnicode_FromUnicode(NULL, 0); cstring += start; if (decode_func) { return decode_func(cstring, length, errors); } else { return PyUnicode_Decode(cstring, length, encoding, errors); } } /////////////// decode_c_bytes.proto /////////////// static CYTHON_INLINE PyObject* __Pyx_decode_c_bytes( const char* cstring, Py_ssize_t length, Py_ssize_t start, Py_ssize_t stop, const char* encoding, const char* errors, PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)); /////////////// decode_c_bytes /////////////// static CYTHON_INLINE PyObject* __Pyx_decode_c_bytes( const char* cstring, Py_ssize_t length, Py_ssize_t start, Py_ssize_t stop, const char* encoding, const char* errors, PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) { if (unlikely((start < 0) | (stop < 0))) { if (start < 0) { start += length; if (start < 0) start = 0; } if (stop < 0) stop += length; } if (stop > length) stop = length; length = stop - start; if (unlikely(length <= 0)) return PyUnicode_FromUnicode(NULL, 0); cstring += start; if (decode_func) { return decode_func(cstring, length, errors); } else { return PyUnicode_Decode(cstring, length, encoding, errors); } } /////////////// decode_bytes.proto /////////////// //@requires: decode_c_bytes static CYTHON_INLINE PyObject* __Pyx_decode_bytes( PyObject* string, Py_ssize_t start, Py_ssize_t stop, const char* encoding, const char* errors, PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) { return __Pyx_decode_c_bytes( PyBytes_AS_STRING(string), PyBytes_GET_SIZE(string), start, stop, encoding, errors, decode_func); } /////////////// decode_bytearray.proto /////////////// //@requires: decode_c_bytes static CYTHON_INLINE PyObject* __Pyx_decode_bytearray( PyObject* string, Py_ssize_t start, Py_ssize_t stop, const char* encoding, const char* errors, PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) { return __Pyx_decode_c_bytes( PyByteArray_AS_STRING(string), PyByteArray_GET_SIZE(string), start, stop, encoding, errors, decode_func); } /////////////// PyUnicode_Substring.proto /////////////// static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring( PyObject* text, Py_ssize_t start, Py_ssize_t stop); /////////////// PyUnicode_Substring /////////////// static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring( PyObject* text, Py_ssize_t start, Py_ssize_t stop) { Py_ssize_t length; #if CYTHON_PEP393_ENABLED if (unlikely(PyUnicode_READY(text) == -1)) return NULL; length = PyUnicode_GET_LENGTH(text); #else length = PyUnicode_GET_SIZE(text); #endif if (start < 0) { start += length; if (start < 0) start = 0; } if (stop < 0) stop += length; else if (stop > length) stop = length; length = stop - start; if (length <= 0) return PyUnicode_FromUnicode(NULL, 0); #if CYTHON_PEP393_ENABLED return PyUnicode_FromKindAndData(PyUnicode_KIND(text), PyUnicode_1BYTE_DATA(text) + start*PyUnicode_KIND(text), stop-start); #else return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(text)+start, stop-start); #endif } /////////////// py_unicode_istitle.proto /////////////// // Py_UNICODE_ISTITLE() doesn't match unicode.istitle() as the latter // additionally allows character that comply with Py_UNICODE_ISUPPER() #if PY_VERSION_HEX < 0x030200A2 static CYTHON_INLINE int __Pyx_Py_UNICODE_ISTITLE(Py_UNICODE uchar) #else static CYTHON_INLINE int __Pyx_Py_UNICODE_ISTITLE(Py_UCS4 uchar) #endif { return Py_UNICODE_ISTITLE(uchar) || Py_UNICODE_ISUPPER(uchar); } /////////////// unicode_tailmatch.proto /////////////// // Python's unicode.startswith() and unicode.endswith() support a // tuple of prefixes/suffixes, whereas it's much more common to // test for a single unicode string. static int __Pyx_PyUnicode_Tailmatch(PyObject* s, PyObject* substr, Py_ssize_t start, Py_ssize_t end, int direction) { if (unlikely(PyTuple_Check(substr))) { Py_ssize_t i, count = PyTuple_GET_SIZE(substr); for (i = 0; i < count; i++) { int result; #if CYTHON_COMPILING_IN_CPYTHON result = PyUnicode_Tailmatch(s, PyTuple_GET_ITEM(substr, i), start, end, direction); #else PyObject* sub = PySequence_GetItem(substr, i); if (unlikely(!sub)) return -1; result = PyUnicode_Tailmatch(s, sub, start, end, direction); Py_DECREF(sub); #endif if (result) { return result; } } return 0; } return PyUnicode_Tailmatch(s, substr, start, end, direction); } /////////////// bytes_tailmatch.proto /////////////// static int __Pyx_PyBytes_SingleTailmatch(PyObject* self, PyObject* arg, Py_ssize_t start, Py_ssize_t end, int direction) { const char* self_ptr = PyBytes_AS_STRING(self); Py_ssize_t self_len = PyBytes_GET_SIZE(self); const char* sub_ptr; Py_ssize_t sub_len; int retval; #if PY_VERSION_HEX >= 0x02060000 Py_buffer view; view.obj = NULL; #endif if ( PyBytes_Check(arg) ) { sub_ptr = PyBytes_AS_STRING(arg); sub_len = PyBytes_GET_SIZE(arg); } #if PY_MAJOR_VERSION < 3 // Python 2.x allows mixing unicode and str else if ( PyUnicode_Check(arg) ) { return PyUnicode_Tailmatch(self, arg, start, end, direction); } #endif else { #if PY_VERSION_HEX < 0x02060000 if (unlikely(PyObject_AsCharBuffer(arg, &sub_ptr, &sub_len))) return -1; #else if (unlikely(PyObject_GetBuffer(self, &view, PyBUF_SIMPLE) == -1)) return -1; sub_ptr = (const char*) view.buf; sub_len = view.len; #endif } if (end > self_len) end = self_len; else if (end < 0) end += self_len; if (end < 0) end = 0; if (start < 0) start += self_len; if (start < 0) start = 0; if (direction > 0) { /* endswith */ if (end-sub_len > start) start = end - sub_len; } if (start + sub_len <= end) retval = !memcmp(self_ptr+start, sub_ptr, sub_len); else retval = 0; #if PY_VERSION_HEX >= 0x02060000 if (view.obj) PyBuffer_Release(&view); #endif return retval; } static int __Pyx_PyBytes_Tailmatch(PyObject* self, PyObject* substr, Py_ssize_t start, Py_ssize_t end, int direction) { if (unlikely(PyTuple_Check(substr))) { Py_ssize_t i, count = PyTuple_GET_SIZE(substr); for (i = 0; i < count; i++) { int result; #if CYTHON_COMPILING_IN_CPYTHON result = __Pyx_PyBytes_SingleTailmatch(self, PyTuple_GET_ITEM(substr, i), start, end, direction); #else PyObject* sub = PySequence_GetItem(substr, i); if (unlikely(!sub)) return -1; result = __Pyx_PyBytes_SingleTailmatch(self, sub, start, end, direction); Py_DECREF(sub); #endif if (result) { return result; } } return 0; } return __Pyx_PyBytes_SingleTailmatch(self, substr, start, end, direction); } /////////////// str_tailmatch.proto /////////////// static CYTHON_INLINE int __Pyx_PyStr_Tailmatch(PyObject* self, PyObject* arg, Py_ssize_t start, Py_ssize_t end, int direction); /////////////// str_tailmatch /////////////// //@requires: bytes_tailmatch //@requires: unicode_tailmatch static CYTHON_INLINE int __Pyx_PyStr_Tailmatch(PyObject* self, PyObject* arg, Py_ssize_t start, Py_ssize_t end, int direction) { // We do not use a C compiler macro here to avoid "unused function" // warnings for the *_Tailmatch() function that is not being used in // the specific CPython version. The C compiler will generate the same // code anyway, and will usually just remove the unused function. if (PY_MAJOR_VERSION < 3) return __Pyx_PyBytes_Tailmatch(self, arg, start, end, direction); else return __Pyx_PyUnicode_Tailmatch(self, arg, start, end, direction); } /////////////// bytes_index.proto /////////////// static CYTHON_INLINE char __Pyx_PyBytes_GetItemInt(PyObject* bytes, Py_ssize_t index, int check_bounds) { if (check_bounds) { Py_ssize_t size = PyBytes_GET_SIZE(bytes); if (unlikely(index >= size) | ((index < 0) & unlikely(index < -size))) { PyErr_SetString(PyExc_IndexError, "string index out of range"); return -1; } } if (index < 0) index += PyBytes_GET_SIZE(bytes); return PyBytes_AS_STRING(bytes)[index]; } //////////////////// StringJoin.proto //////////////////// #if PY_MAJOR_VERSION < 3 #define __Pyx_PyString_Join __Pyx_PyBytes_Join #define __Pyx_PyBaseString_Join(s, v) (PyUnicode_CheckExact(s) ? PyUnicode_Join(s, v) : __Pyx_PyBytes_Join(s, v)) #else #define __Pyx_PyString_Join PyUnicode_Join #define __Pyx_PyBaseString_Join PyUnicode_Join #endif #if CYTHON_COMPILING_IN_CPYTHON #if PY_MAJOR_VERSION < 3 #define __Pyx_PyBytes_Join _PyString_Join #else #define __Pyx_PyBytes_Join _PyBytes_Join #endif #else static CYTHON_INLINE PyObject* __Pyx_PyBytes_Join(PyObject* sep, PyObject* values); /*proto*/ #endif //////////////////// StringJoin //////////////////// #if !CYTHON_COMPILING_IN_CPYTHON static CYTHON_INLINE PyObject* __Pyx_PyBytes_Join(PyObject* sep, PyObject* values) { return PyObject_CallMethodObjArgs(sep, PYIDENT("join"), values, NULL); } #endif //////////////////// ByteArrayAppendObject.proto //////////////////// static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyObject* value); //////////////////// ByteArrayAppendObject //////////////////// //@requires: ByteArrayAppend static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyObject* value) { Py_ssize_t ival; #if PY_MAJOR_VERSION < 3 if (unlikely(PyString_Check(value))) { if (unlikely(PyString_GET_SIZE(value) != 1)) { PyErr_SetString(PyExc_ValueError, "string must be of size 1"); return -1; } ival = (unsigned char) (PyString_AS_STRING(value)[0]); } else #endif { // CPython calls PyNumber_Index() internally ival = __Pyx_PyIndex_AsSsize_t(value); if (unlikely((ival < 0) | (ival > 255))) { if (ival == -1 && PyErr_Occurred()) return -1; PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)"); return -1; } } return __Pyx_PyByteArray_Append(bytearray, ival); } //////////////////// ByteArrayAppend.proto //////////////////// static CYTHON_INLINE int __Pyx_PyByteArray_Append(PyObject* bytearray, int value); //////////////////// ByteArrayAppend //////////////////// //@requires: ObjectHandling.c::PyObjectCallMethod static CYTHON_INLINE int __Pyx_PyByteArray_Append(PyObject* bytearray, int value) { PyObject *pyval, *retval; #if CYTHON_COMPILING_IN_CPYTHON if (likely((value >= 0) & (value <= 255))) { Py_ssize_t n = Py_SIZE(bytearray); if (likely(n != PY_SSIZE_T_MAX)) { if (unlikely(PyByteArray_Resize(bytearray, n + 1) < 0)) return -1; PyByteArray_AS_STRING(bytearray)[n] = value; return 0; } } else { PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)"); return -1; } #endif pyval = PyInt_FromLong(value); if (unlikely(!pyval)) return -1; retval = __Pyx_PyObject_CallMethod1(bytearray, PYIDENT("append"), pyval); Py_DECREF(pyval); if (unlikely(!retval)) return -1; Py_DECREF(retval); return 0; } cython-0.20.1+git90-g0e6e38e/Cython/Utility/TestCyUtilityLoader.pyx000066400000000000000000000002301231323242300246370ustar00rootroot00000000000000########## TestCyUtilityLoader ########## #@requires: OtherUtility test {{cy_loader}} impl ########## OtherUtility ########## req {{cy_loader}} impl cython-0.20.1+git90-g0e6e38e/Cython/Utility/TestCythonScope.pyx000066400000000000000000000030731231323242300240170ustar00rootroot00000000000000########## TestClass ########## # These utilities are for testing purposes cdef extern from *: cdef object __pyx_test_dep(object) @cname('__pyx_TestClass') cdef class TestClass(object): cdef public int value def __init__(self, int value): self.value = value def __str__(self): return 'TestClass(%d)' % self.value cdef cdef_method(self, int value): print 'Hello from cdef_method', value cpdef cpdef_method(self, int value): print 'Hello from cpdef_method', value def def_method(self, int value): print 'Hello from def_method', value @cname('cdef_cname') cdef cdef_cname_method(self, int value): print "Hello from cdef_cname_method", value @cname('cpdef_cname') cpdef cpdef_cname_method(self, int value): print "Hello from cpdef_cname_method", value @cname('def_cname') def def_cname_method(self, int value): print "Hello from def_cname_method", value @cname('__pyx_test_call_other_cy_util') cdef test_call(obj): print 'test_call' __pyx_test_dep(obj) @cname('__pyx_TestClass_New') cdef _testclass_new(int value): return TestClass(value) ########### TestDep ########## @cname('__pyx_test_dep') cdef test_dep(obj): print 'test_dep', obj ########## TestScope ########## @cname('__pyx_testscope') cdef object _testscope(int value): return "hello from cython scope, value=%d" % value ########## View.TestScope ########## @cname('__pyx_view_testscope') cdef object _testscope(int value): return "hello from cython.view scope, value=%d" % value cython-0.20.1+git90-g0e6e38e/Cython/Utility/TestUtilityLoader.c000066400000000000000000000004271231323242300237550ustar00rootroot00000000000000////////// TestUtilityLoader.proto ////////// test {{loader}} prototype ////////// TestUtilityLoader ////////// //@requires: OtherUtility test {{loader}} impl ////////// OtherUtility.proto ////////// req {{loader}} proto ////////// OtherUtility ////////// req {{loader}} impl cython-0.20.1+git90-g0e6e38e/Cython/Utility/TypeConversion.c000066400000000000000000000536321231323242300233200ustar00rootroot00000000000000/////////////// TypeConversions.proto /////////////// /* Type Conversion Predeclarations */ #define __Pyx_fits_Py_ssize_t(v, type, is_signed) ( \ (sizeof(type) < sizeof(Py_ssize_t)) || \ (sizeof(type) > sizeof(Py_ssize_t) && \ likely(v < (type)PY_SSIZE_T_MAX || \ v == (type)PY_SSIZE_T_MAX) && \ (!is_signed || likely(v > (type)PY_SSIZE_T_MIN || \ v == (type)PY_SSIZE_T_MIN))) || \ (sizeof(type) == sizeof(Py_ssize_t) && \ (is_signed || likely(v < (type)PY_SSIZE_T_MAX || \ v == (type)PY_SSIZE_T_MAX))) ) static CYTHON_INLINE char* __Pyx_PyObject_AsString(PyObject*); static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); #define __Pyx_PyByteArray_FromString(s) PyByteArray_FromStringAndSize((const char*)s, strlen((const char*)s)) #define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) #define __Pyx_PyBytes_FromString PyBytes_FromString #define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); #if PY_MAJOR_VERSION < 3 #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize #else #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize #endif #define __Pyx_PyObject_AsSString(s) ((signed char*) __Pyx_PyObject_AsString(s)) #define __Pyx_PyObject_AsUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s)) #define __Pyx_PyObject_FromUString(s) __Pyx_PyObject_FromString((const char*)s) #define __Pyx_PyBytes_FromUString(s) __Pyx_PyBytes_FromString((const char*)s) #define __Pyx_PyByteArray_FromUString(s) __Pyx_PyByteArray_FromString((const char*)s) #define __Pyx_PyStr_FromUString(s) __Pyx_PyStr_FromString((const char*)s) #define __Pyx_PyUnicode_FromUString(s) __Pyx_PyUnicode_FromString((const char*)s) #if PY_MAJOR_VERSION < 3 static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) { const Py_UNICODE *u_end = u; while (*u_end++) ; return u_end - u - 1; } #else #define __Pyx_Py_UNICODE_strlen Py_UNICODE_strlen #endif #define __Pyx_PyUnicode_FromUnicode(u) PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u)) #define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode #define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode #define __Pyx_Owned_Py_None(b) (Py_INCREF(Py_None), Py_None) #define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False)) static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x); static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); #if CYTHON_COMPILING_IN_CPYTHON #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) #else #define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) #endif #define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) #if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII static int __Pyx_sys_getdefaultencoding_not_ascii; static int __Pyx_init_sys_getdefaultencoding_params(void) { PyObject* sys = NULL; PyObject* default_encoding = NULL; PyObject* ascii_chars_u = NULL; PyObject* ascii_chars_b = NULL; sys = PyImport_ImportModule("sys"); if (sys == NULL) goto bad; default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); if (default_encoding == NULL) goto bad; if (strcmp(PyBytes_AsString(default_encoding), "ascii") == 0) { __Pyx_sys_getdefaultencoding_not_ascii = 0; } else { const char* default_encoding_c = PyBytes_AS_STRING(default_encoding); char ascii_chars[128]; int c; for (c = 0; c < 128; c++) { ascii_chars[c] = c; } __Pyx_sys_getdefaultencoding_not_ascii = 1; ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); if (ascii_chars_u == NULL) goto bad; ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); if (ascii_chars_b == NULL || strncmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { PyErr_Format( PyExc_ValueError, "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", default_encoding_c); goto bad; } } Py_XDECREF(sys); Py_XDECREF(default_encoding); Py_XDECREF(ascii_chars_u); Py_XDECREF(ascii_chars_b); return 0; bad: Py_XDECREF(sys); Py_XDECREF(default_encoding); Py_XDECREF(ascii_chars_u); Py_XDECREF(ascii_chars_b); return -1; } #endif #if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) #else #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) // __PYX_DEFAULT_STRING_ENCODING is either a user provided string constant // or we need to look it up here #if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT static char* __PYX_DEFAULT_STRING_ENCODING; static int __Pyx_init_sys_getdefaultencoding_params(void) { PyObject* sys = NULL; PyObject* default_encoding = NULL; char* default_encoding_c; sys = PyImport_ImportModule("sys"); if (sys == NULL) goto bad; default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); if (default_encoding == NULL) goto bad; default_encoding_c = PyBytes_AS_STRING(default_encoding); __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c)); strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); Py_DECREF(sys); Py_DECREF(default_encoding); return 0; bad: Py_XDECREF(sys); Py_XDECREF(default_encoding); return -1; } #endif #endif /////////////// TypeConversions /////////////// /* Type Conversion Functions */ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { return __Pyx_PyUnicode_FromStringAndSize(c_str, strlen(c_str)); } static CYTHON_INLINE char* __Pyx_PyObject_AsString(PyObject* o) { Py_ssize_t ignore; return __Pyx_PyObject_AsStringAndSize(o, &ignore); } static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { #if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT if ( #if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII __Pyx_sys_getdefaultencoding_not_ascii && #endif PyUnicode_Check(o)) { #if PY_VERSION_HEX < 0x03030000 char* defenc_c; // borrowed, cached reference PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); if (!defenc) return NULL; defenc_c = PyBytes_AS_STRING(defenc); #if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII { char* end = defenc_c + PyBytes_GET_SIZE(defenc); char* c; for (c = defenc_c; c < end; c++) { if ((unsigned char) (*c) >= 128) { // raise the error PyUnicode_AsASCIIString(o); return NULL; } } } #endif /*__PYX_DEFAULT_STRING_ENCODING_IS_ASCII*/ *length = PyBytes_GET_SIZE(defenc); return defenc_c; #else /* PY_VERSION_HEX < 0x03030000 */ if (PyUnicode_READY(o) == -1) return NULL; #if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII if (PyUnicode_IS_ASCII(o)) { // cached for the lifetime of the object *length = PyUnicode_GET_LENGTH(o); return PyUnicode_AsUTF8(o); } else { // raise the error PyUnicode_AsASCIIString(o); return NULL; } #else /* __PYX_DEFAULT_STRING_ENCODING_IS_ASCII */ return PyUnicode_AsUTF8AndSize(o, length); #endif /* __PYX_DEFAULT_STRING_ENCODING_IS_ASCII */ #endif /* PY_VERSION_HEX < 0x03030000 */ } else #endif /* __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT */ #if !CYTHON_COMPILING_IN_PYPY #if PY_VERSION_HEX >= 0x02060000 if (PyByteArray_Check(o)) { *length = PyByteArray_GET_SIZE(o); return PyByteArray_AS_STRING(o); } else #endif #endif { char* result; int r = PyBytes_AsStringAndSize(o, &result, length); if (unlikely(r < 0)) { return NULL; } else { return result; } } } /* Note: __Pyx_PyObject_IsTrue is written to minimize branching. */ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { int is_true = x == Py_True; if (is_true | (x == Py_False) | (x == Py_None)) return is_true; else return PyObject_IsTrue(x); } static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) { PyNumberMethods *m; const char *name = NULL; PyObject *res = NULL; #if PY_MAJOR_VERSION < 3 if (PyInt_Check(x) || PyLong_Check(x)) #else if (PyLong_Check(x)) #endif return Py_INCREF(x), x; m = Py_TYPE(x)->tp_as_number; #if PY_MAJOR_VERSION < 3 if (m && m->nb_int) { name = "int"; res = PyNumber_Int(x); } else if (m && m->nb_long) { name = "long"; res = PyNumber_Long(x); } #else if (m && m->nb_int) { name = "int"; res = PyNumber_Long(x); } #endif if (res) { #if PY_MAJOR_VERSION < 3 if (!PyInt_Check(res) && !PyLong_Check(res)) { #else if (!PyLong_Check(res)) { #endif PyErr_Format(PyExc_TypeError, "__%.4s__ returned non-%.4s (type %.200s)", name, name, Py_TYPE(res)->tp_name); Py_DECREF(res); return NULL; } } else if (!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "an integer is required"); } return res; } #if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 #if CYTHON_USE_PYLONG_INTERNALS #include "longintrepr.h" #endif #endif static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { Py_ssize_t ival; PyObject *x; #if PY_MAJOR_VERSION < 3 if (likely(PyInt_CheckExact(b))) return PyInt_AS_LONG(b); #endif if (likely(PyLong_CheckExact(b))) { #if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 #if CYTHON_USE_PYLONG_INTERNALS switch (Py_SIZE(b)) { case -1: return -(sdigit)((PyLongObject*)b)->ob_digit[0]; case 0: return 0; case 1: return ((PyLongObject*)b)->ob_digit[0]; } #endif #endif #if PY_VERSION_HEX < 0x02060000 return PyInt_AsSsize_t(b); #else return PyLong_AsSsize_t(b); #endif } x = PyNumber_Index(b); if (!x) return -1; ival = PyInt_AsSsize_t(x); Py_DECREF(x); return ival; } static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { #if PY_VERSION_HEX < 0x02050000 if (ival <= LONG_MAX) return PyInt_FromLong((long)ival); else { unsigned char *bytes = (unsigned char *) &ival; int one = 1; int little = (int)*(unsigned char*)&one; return _PyLong_FromByteArray(bytes, sizeof(size_t), little, 0); } #else return PyInt_FromSize_t(ival); #endif } /////////////// FromPyStructUtility.proto /////////////// {{struct_type_decl}}; static {{struct_type_decl}} {{funcname}}(PyObject *); /////////////// FromPyStructUtility /////////////// static {{struct_type_decl}} {{funcname}}(PyObject * o) { {{struct_type_decl}} result; PyObject *value = NULL; if (!PyMapping_Check(o)) { PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "a mapping", Py_TYPE(o)->tp_name); goto bad; } {{for member in var_entries:}} {{py:attr = "result." + member.cname}} value = PyObject_GetItem(o, PYIDENT("{{member.name}}")); if (!value) { PyErr_Format(PyExc_ValueError, \ "No value specified for struct attribute '%.{{max(200, len(member.name))}}s'", "{{member.name}}"); goto bad; } {{attr}} = {{member.type.from_py_function}}(value); if ({{member.type.error_condition(attr)}}) goto bad; Py_DECREF(value); {{endfor}} return result; bad: Py_XDECREF(value); return result; } /////////////// ObjectAsUCS4.proto /////////////// static CYTHON_INLINE Py_UCS4 __Pyx_PyObject_AsPy_UCS4(PyObject*); /////////////// ObjectAsUCS4 /////////////// static CYTHON_INLINE Py_UCS4 __Pyx_PyObject_AsPy_UCS4(PyObject* x) { long ival; if (PyUnicode_Check(x)) { Py_ssize_t length; #if CYTHON_PEP393_ENABLED length = PyUnicode_GET_LENGTH(x); if (likely(length == 1)) { return PyUnicode_READ_CHAR(x, 0); } #else length = PyUnicode_GET_SIZE(x); if (likely(length == 1)) { return PyUnicode_AS_UNICODE(x)[0]; } #if Py_UNICODE_SIZE == 2 else if (PyUnicode_GET_SIZE(x) == 2) { Py_UCS4 high_val = PyUnicode_AS_UNICODE(x)[0]; if (high_val >= 0xD800 && high_val <= 0xDBFF) { Py_UCS4 low_val = PyUnicode_AS_UNICODE(x)[1]; if (low_val >= 0xDC00 && low_val <= 0xDFFF) { return 0x10000 + (((high_val & ((1<<10)-1)) << 10) | (low_val & ((1<<10)-1))); } } } #endif #endif PyErr_Format(PyExc_ValueError, "only single character unicode strings can be converted to Py_UCS4, " "got length %" CYTHON_FORMAT_SSIZE_T "d", length); return (Py_UCS4)-1; } ival = __Pyx_PyInt_As_long(x); if (unlikely(ival < 0)) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_OverflowError, "cannot convert negative value to Py_UCS4"); return (Py_UCS4)-1; } else if (unlikely(ival > 1114111)) { PyErr_SetString(PyExc_OverflowError, "value too large to convert to Py_UCS4"); return (Py_UCS4)-1; } return (Py_UCS4)ival; } /////////////// ObjectAsPyUnicode.proto /////////////// static CYTHON_INLINE Py_UNICODE __Pyx_PyObject_AsPy_UNICODE(PyObject*); /////////////// ObjectAsPyUnicode /////////////// static CYTHON_INLINE Py_UNICODE __Pyx_PyObject_AsPy_UNICODE(PyObject* x) { long ival; #if CYTHON_PEP393_ENABLED #if Py_UNICODE_SIZE > 2 const long maxval = 1114111; #else const long maxval = 65535; #endif #else static long maxval = 0; #endif if (PyUnicode_Check(x)) { if (unlikely(__Pyx_PyUnicode_GET_LENGTH(x) != 1)) { PyErr_Format(PyExc_ValueError, "only single character unicode strings can be converted to Py_UNICODE, " "got length %" CYTHON_FORMAT_SSIZE_T "d", __Pyx_PyUnicode_GET_LENGTH(x)); return (Py_UNICODE)-1; } #if CYTHON_PEP393_ENABLED ival = PyUnicode_READ_CHAR(x, 0); #else return PyUnicode_AS_UNICODE(x)[0]; #endif } else { #if !CYTHON_PEP393_ENABLED if (unlikely(!maxval)) maxval = (long)PyUnicode_GetMax(); #endif ival = __Pyx_PyInt_As_long(x); } if (unlikely(ival < 0)) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_OverflowError, "cannot convert negative value to Py_UNICODE"); return (Py_UNICODE)-1; } else if (unlikely(ival > maxval)) { PyErr_SetString(PyExc_OverflowError, "value too large to convert to Py_UNICODE"); return (Py_UNICODE)-1; } return (Py_UNICODE)ival; } /////////////// CIntToPy.proto /////////////// static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value); /////////////// CIntToPy /////////////// static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value) { const {{TYPE}} neg_one = ({{TYPE}}) -1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (is_unsigned) { if (sizeof({{TYPE}}) < sizeof(long)) { return PyInt_FromLong((long) value); } else if (sizeof({{TYPE}}) <= sizeof(unsigned long)) { return PyLong_FromUnsignedLong((unsigned long) value); } else if (sizeof({{TYPE}}) <= sizeof(unsigned long long)) { return PyLong_FromUnsignedLongLong((unsigned long long) value); } } else { if (sizeof({{TYPE}}) <= sizeof(long)) { return PyInt_FromLong((long) value); } else if (sizeof({{TYPE}}) <= sizeof(long long)) { return PyLong_FromLongLong((long long) value); } } { int one = 1; int little = (int)*(unsigned char *)&one; unsigned char *bytes = (unsigned char *)&value; return _PyLong_FromByteArray(bytes, sizeof({{TYPE}}), little, !is_unsigned); } } /////////////// CIntFromPyVerify /////////////// #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func) \ { \ func_type value = func(x); \ if (sizeof(target_type) < sizeof(func_type)) { \ if (unlikely(value != (func_type) (target_type) value)) { \ func_type zero = 0; \ PyErr_SetString(PyExc_OverflowError, \ (is_unsigned && unlikely(value < zero)) ? \ "can't convert negative value to " #target_type : \ "value too large to convert to " #target_type); \ return (target_type) -1; \ } \ } \ return (target_type) value; \ } /////////////// CIntFromPy.proto /////////////// static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *); /////////////// CIntFromPy /////////////// //@requires: CIntFromPyVerify #if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 #if CYTHON_USE_PYLONG_INTERNALS #include "longintrepr.h" #endif #endif static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) { const {{TYPE}} neg_one = ({{TYPE}}) -1, const_zero = 0; const int is_unsigned = neg_one > const_zero; #if PY_MAJOR_VERSION < 3 if (likely(PyInt_Check(x))) { if (sizeof({{TYPE}}) < sizeof(long)) { __PYX_VERIFY_RETURN_INT({{TYPE}}, long, PyInt_AS_LONG) } else { long val = PyInt_AS_LONG(x); if (is_unsigned && unlikely(val < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to {{TYPE}}"); return ({{TYPE}}) -1; } return ({{TYPE}}) val; } } else #endif if (likely(PyLong_Check(x))) { if (is_unsigned) { #if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 #if CYTHON_USE_PYLONG_INTERNALS if (sizeof(digit) <= sizeof({{TYPE}})) { switch (Py_SIZE(x)) { case 0: return 0; case 1: return ({{TYPE}}) ((PyLongObject*)x)->ob_digit[0]; } } #endif #endif if (unlikely(Py_SIZE(x) < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to {{TYPE}}"); return ({{TYPE}}) -1; } if (sizeof({{TYPE}}) <= sizeof(unsigned long)) { __PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long, PyLong_AsUnsignedLong) } else if (sizeof({{TYPE}}) <= sizeof(unsigned long long)) { __PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long long, PyLong_AsUnsignedLongLong) } } else { #if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 #if CYTHON_USE_PYLONG_INTERNALS if (sizeof(digit) <= sizeof({{TYPE}})) { switch (Py_SIZE(x)) { case 0: return 0; case 1: return +({{TYPE}}) ((PyLongObject*)x)->ob_digit[0]; case -1: return -({{TYPE}}) ((PyLongObject*)x)->ob_digit[0]; } } #endif #endif if (sizeof({{TYPE}}) <= sizeof(long)) { __PYX_VERIFY_RETURN_INT({{TYPE}}, long, PyLong_AsLong) } else if (sizeof({{TYPE}}) <= sizeof(long long)) { __PYX_VERIFY_RETURN_INT({{TYPE}}, long long, PyLong_AsLongLong) } } { #if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) PyErr_SetString(PyExc_RuntimeError, "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); #else {{TYPE}} val; PyObject *v = __Pyx_PyNumber_Int(x); #if PY_MAJOR_VERSION < 3 if (likely(v) && !PyLong_Check(v)) { PyObject *tmp = v; v = PyNumber_Long(tmp); Py_DECREF(tmp); } #endif if (likely(v)) { int one = 1; int is_little = (int)*(unsigned char *)&one; unsigned char *bytes = (unsigned char *)&val; int ret = _PyLong_AsByteArray((PyLongObject *)v, bytes, sizeof(val), is_little, !is_unsigned); Py_DECREF(v); if (likely(!ret)) return val; } #endif return ({{TYPE}}) -1; } } else { {{TYPE}} val; PyObject *tmp = __Pyx_PyNumber_Int(x); if (!tmp) return ({{TYPE}}) -1; val = {{FROM_PY_FUNCTION}}(tmp); Py_DECREF(tmp); return val; } } cython-0.20.1+git90-g0e6e38e/Cython/Utility/__init__.py000066400000000000000000000000001231323242300222530ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Cython/Utility/arrayarray.h000066400000000000000000000076221231323242300225110ustar00rootroot00000000000000/////////////// ArrayAPI.proto /////////////// // arrayarray.h // // Artificial C-API for Python's type, // used by array.pxd // // last changes: 2009-05-15 rk // 2012-05-02 andreasvc // (see revision control) // #ifndef _ARRAYARRAY_H #define _ARRAYARRAY_H // These two forward declarations are explicitly handled in the type // declaration code, as including them here is too late for cython-defined // types to use them. // struct arrayobject; // typedef struct arrayobject arrayobject; // All possible arraydescr values are defined in the vector "descriptors" // below. That's defined later because the appropriate get and set // functions aren't visible yet. typedef struct arraydescr { int typecode; int itemsize; PyObject * (*getitem)(struct arrayobject *, Py_ssize_t); int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *); #if PY_VERSION_HEX >= 0x03000000 char *formats; #endif } arraydescr; struct arrayobject { PyObject_HEAD Py_ssize_t ob_size; union { char *ob_item; float *as_floats; double *as_doubles; int *as_ints; unsigned int *as_uints; unsigned char *as_uchars; signed char *as_schars; char *as_chars; unsigned long *as_ulongs; long *as_longs; short *as_shorts; unsigned short *as_ushorts; Py_UNICODE *as_pyunicodes; void *as_voidptr; } data; Py_ssize_t allocated; struct arraydescr *ob_descr; PyObject *weakreflist; /* List of weak references */ #if PY_VERSION_HEX >= 0x03000000 int ob_exports; /* Number of exported buffers */ #endif }; #ifndef NO_NEWARRAY_INLINE // fast creation of a new array static CYTHON_INLINE PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t size, struct arraydescr *descr) { arrayobject *op; size_t nbytes; if (size < 0) { PyErr_BadInternalCall(); return NULL; } nbytes = size * descr->itemsize; // Check for overflow if (nbytes / descr->itemsize != (size_t)size) { return PyErr_NoMemory(); } op = (arrayobject *) type->tp_alloc(type, 0); if (op == NULL) { return NULL; } op->ob_descr = descr; op->allocated = size; op->weakreflist = NULL; op->ob_size = size; if (size <= 0) { op->data.ob_item = NULL; } else { op->data.ob_item = PyMem_NEW(char, nbytes); if (op->data.ob_item == NULL) { Py_DECREF(op); return PyErr_NoMemory(); } } return (PyObject *) op; } #else PyObject* newarrayobject(PyTypeObject *type, Py_ssize_t size, struct arraydescr *descr); #endif /* ifndef NO_NEWARRAY_INLINE */ // fast resize (reallocation to the point) // not designed for filing small increments (but for fast opaque array apps) static CYTHON_INLINE int resize(arrayobject *self, Py_ssize_t n) { void *items = (void*) self->data.ob_item; PyMem_Resize(items, char, (size_t)(n * self->ob_descr->itemsize)); if (items == NULL) { PyErr_NoMemory(); return -1; } self->data.ob_item = (char*) items; self->ob_size = n; self->allocated = n; return 0; } // suitable for small increments; over allocation 50% ; // Remains non-smart in Python 2.3- ; but exists for compatibility static CYTHON_INLINE int resize_smart(arrayobject *self, Py_ssize_t n) { void *items = (void*) self->data.ob_item; Py_ssize_t newsize; if (n < self->allocated) { if (n*4 > self->allocated) { self->ob_size = n; return 0; } } newsize = n * 3 / 2 + 1; PyMem_Resize(items, char, (size_t)(newsize * self->ob_descr->itemsize)); if (items == NULL) { PyErr_NoMemory(); return -1; } self->data.ob_item = (char*) items; self->ob_size = n; self->allocated = newsize; return 0; } #endif /* _ARRAYARRAY_H */ cython-0.20.1+git90-g0e6e38e/Cython/Utils.py000066400000000000000000000310051231323242300201620ustar00rootroot00000000000000# # Cython -- Things that don't belong # anywhere else in particular # import os, sys, re, codecs modification_time = os.path.getmtime def cached_function(f): cache = {} uncomputed = object() def wrapper(*args): res = cache.get(args, uncomputed) if res is uncomputed: res = cache[args] = f(*args) return res return wrapper def cached_method(f): cache_name = '__%s_cache' % f.__name__ def wrapper(self, *args): cache = getattr(self, cache_name, None) if cache is None: cache = {} setattr(self, cache_name, cache) if args in cache: return cache[args] res = cache[args] = f(self, *args) return res return wrapper def replace_suffix(path, newsuf): base, _ = os.path.splitext(path) return base + newsuf def open_new_file(path): if os.path.exists(path): # Make sure to create a new file here so we can # safely hard link the output files. os.unlink(path) # we use the ISO-8859-1 encoding here because we only write pure # ASCII strings or (e.g. for file names) byte encoded strings as # Unicode, so we need a direct mapping from the first 256 Unicode # characters to a byte sequence, which ISO-8859-1 provides return codecs.open(path, "w", encoding="ISO-8859-1") def castrate_file(path, st): # Remove junk contents from an output file after a # failed compilation. # Also sets access and modification times back to # those specified by st (a stat struct). try: f = open_new_file(path) except EnvironmentError: pass else: f.write( "#error Do not use this file, it is the result of a failed Cython compilation.\n") f.close() if st: os.utime(path, (st.st_atime, st.st_mtime-1)) def file_newer_than(path, time): ftime = modification_time(path) return ftime > time @cached_function def search_include_directories(dirs, qualified_name, suffix, pos, include=False, sys_path=False): # Search the list of include directories for the given # file name. If a source file position is given, first # searches the directory containing that file. Returns # None if not found, but does not report an error. # The 'include' option will disable package dereferencing. # If 'sys_path' is True, also search sys.path. if sys_path: dirs = dirs + tuple(sys.path) if pos: file_desc = pos[0] from Cython.Compiler.Scanning import FileSourceDescriptor if not isinstance(file_desc, FileSourceDescriptor): raise RuntimeError("Only file sources for code supported") if include: dirs = (os.path.dirname(file_desc.filename),) + dirs else: dirs = (find_root_package_dir(file_desc.filename),) + dirs dotted_filename = qualified_name if suffix: dotted_filename += suffix if not include: names = qualified_name.split('.') package_names = tuple(names[:-1]) module_name = names[-1] module_filename = module_name + suffix package_filename = "__init__" + suffix for dir in dirs: path = os.path.join(dir, dotted_filename) if path_exists(path): return path if not include: package_dir = check_package_dir(dir, package_names) if package_dir is not None: path = os.path.join(package_dir, module_filename) if path_exists(path): return path path = os.path.join(dir, package_dir, module_name, package_filename) if path_exists(path): return path return None @cached_function def find_root_package_dir(file_path): dir = os.path.dirname(file_path) if file_path == dir: return dir elif is_package_dir(dir): return find_root_package_dir(dir) else: return dir @cached_function def check_package_dir(dir, package_names): for dirname in package_names: dir = os.path.join(dir, dirname) if not is_package_dir(dir): return None return dir @cached_function def is_package_dir(dir_path): for filename in ("__init__.py", "__init__.pyx", "__init__.pxd"): path = os.path.join(dir_path, filename) if path_exists(path): return 1 @cached_function def path_exists(path): # try on the filesystem first if os.path.exists(path): return True # figure out if a PEP 302 loader is around try: loader = __loader__ # XXX the code below assumes a 'zipimport.zipimporter' instance # XXX should be easy to generalize, but too lazy right now to write it archive_path = getattr(loader, 'archive', None) if archive_path: normpath = os.path.normpath(path) if normpath.startswith(archive_path): arcname = normpath[len(archive_path)+1:] try: loader.get_data(arcname) return True except IOError: return False except NameError: pass return False # file name encodings def decode_filename(filename): if isinstance(filename, unicode): return filename try: filename_encoding = sys.getfilesystemencoding() if filename_encoding is None: filename_encoding = sys.getdefaultencoding() filename = filename.decode(filename_encoding) except UnicodeDecodeError: pass return filename # support for source file encoding detection _match_file_encoding = re.compile(u"coding[:=]\s*([-\w.]+)").search def detect_file_encoding(source_filename): f = open_source_file(source_filename, encoding="UTF-8", error_handling='ignore') try: return detect_opened_file_encoding(f) finally: f.close() def detect_opened_file_encoding(f): # PEPs 263 and 3120 # Most of the time the first two lines fall in the first 250 chars, # and this bulk read/split is much faster. lines = f.read(250).split("\n") if len(lines) > 2: m = _match_file_encoding(lines[0]) or _match_file_encoding(lines[1]) if m: return m.group(1) else: return "UTF-8" else: # Fallback to one-char-at-a-time detection. f.seek(0) chars = [] for i in range(2): c = f.read(1) while c and c != u'\n': chars.append(c) c = f.read(1) encoding = _match_file_encoding(u''.join(chars)) if encoding: return encoding.group(1) return "UTF-8" def skip_bom(f): """ Read past a BOM at the beginning of a source file. This could be added to the scanner, but it's *substantially* easier to keep it at this level. """ if f.read(1) != u'\uFEFF': f.seek(0) normalise_newlines = re.compile(u'\r\n?|\n').sub class NormalisedNewlineStream(object): """The codecs module doesn't provide universal newline support. This class is used as a stream wrapper that provides this functionality. The new 'io' in Py2.6+/3.x supports this out of the box. """ def __init__(self, stream): # let's assume .read() doesn't change self.stream = stream self._read = stream.read self.close = stream.close self.encoding = getattr(stream, 'encoding', 'UTF-8') def read(self, count=-1): data = self._read(count) if u'\r' not in data: return data if data.endswith(u'\r'): # may be missing a '\n' data += self._read(1) return normalise_newlines(u'\n', data) def readlines(self): content = [] data = self.read(0x1000) while data: content.append(data) data = self.read(0x1000) return u''.join(content).splitlines(True) def seek(self, pos): if pos == 0: self.stream.seek(0) else: raise NotImplementedError io = None if sys.version_info >= (2,6): try: import io except ImportError: pass def open_source_file(source_filename, mode="r", encoding=None, error_handling=None, require_normalised_newlines=True): if encoding is None: # Most of the time the coding is unspecified, so be optimistic that # it's UTF-8. f = open_source_file(source_filename, encoding="UTF-8", mode=mode, error_handling='ignore') encoding = detect_opened_file_encoding(f) if (encoding == "UTF-8" and error_handling == 'ignore' and require_normalised_newlines): f.seek(0) skip_bom(f) return f else: f.close() # if not os.path.exists(source_filename): try: loader = __loader__ if source_filename.startswith(loader.archive): return open_source_from_loader( loader, source_filename, encoding, error_handling, require_normalised_newlines) except (NameError, AttributeError): pass # if io is not None: stream = io.open(source_filename, mode=mode, encoding=encoding, errors=error_handling) else: # codecs module doesn't have universal newline support stream = codecs.open(source_filename, mode=mode, encoding=encoding, errors=error_handling) if require_normalised_newlines: stream = NormalisedNewlineStream(stream) skip_bom(stream) return stream def open_source_from_loader(loader, source_filename, encoding=None, error_handling=None, require_normalised_newlines=True): nrmpath = os.path.normpath(source_filename) arcname = nrmpath[len(loader.archive)+1:] data = loader.get_data(arcname) if io is not None: return io.TextIOWrapper(io.BytesIO(data), encoding=encoding, errors=error_handling) else: try: import cStringIO as StringIO except ImportError: import StringIO reader = codecs.getreader(encoding) stream = reader(StringIO.StringIO(data)) if require_normalised_newlines: stream = NormalisedNewlineStream(stream) return stream def str_to_number(value): # note: this expects a string as input that was accepted by the # parser already if len(value) < 2: value = int(value, 0) elif value[0] == '0': if value[1] in 'xX': # hex notation ('0x1AF') value = int(value[2:], 16) elif value[1] in 'oO': # Py3 octal notation ('0o136') value = int(value[2:], 8) elif value[1] in 'bB': # Py3 binary notation ('0b101') value = int(value[2:], 2) else: # Py2 octal notation ('0136') value = int(value, 8) else: value = int(value, 0) return value def long_literal(value): if isinstance(value, basestring): value = str_to_number(value) return not -2**31 <= value < 2**31 # all() and any() are new in 2.5 try: # Make sure to bind them on the module, as they will be accessed as # attributes all = all any = any except NameError: def all(items): for item in items: if not item: return False return True def any(items): for item in items: if item: return True return False @cached_function def get_cython_cache_dir(): """get the cython cache dir Priority: 1. CYTHON_CACHE_DIR 2. (OS X): ~/Library/Caches/Cython (posix not OS X): XDG_CACHE_HOME/cython if XDG_CACHE_HOME defined 3. ~/.cython """ if 'CYTHON_CACHE_DIR' in os.environ: return os.environ['CYTHON_CACHE_DIR'] parent = None if os.name == 'posix': if sys.platform == 'darwin': parent = os.path.expanduser('~/Library/Caches') else: # this could fallback on ~/.cache parent = os.environ.get('XDG_CACHE_HOME') if parent and os.path.isdir(parent): return os.path.join(parent, 'cython') # last fallback: ~/.cython return os.path.expanduser(os.path.join('~', '.cython')) cython-0.20.1+git90-g0e6e38e/Cython/__init__.py000066400000000000000000000002101231323242300206130ustar00rootroot00000000000000from Cython.Shadow import __version__ # Void cython.* directives (for case insensitive operating systems). from Cython.Shadow import * cython-0.20.1+git90-g0e6e38e/Demos/000077500000000000000000000000001231323242300163145ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Demos/Makefile000066400000000000000000000004321231323242300177530ustar00rootroot00000000000000all: python setup.py build_ext --inplace test: all python run_primes.py 20 python run_numeric_demo.py python run_spam.py cd callback; $(MAKE) test clean: @echo Cleaning Demos @rm -f *.c *.o *.so *~ core @rm -rf build @cd callback; $(MAKE) clean @cd embed; $(MAKE) clean cython-0.20.1+git90-g0e6e38e/Demos/Makefile.nodistutils000066400000000000000000000006061231323242300223360ustar00rootroot00000000000000PYHOME = $(HOME)/pkg/python/version PYINCLUDE = \ -I$(PYHOME)/include/python2.2 \ -I$(PYHOME)/$(ARCH)/include/python2.2 %.c: %.pyx ../bin/cython $< %.o: %.c gcc -c -fPIC $(PYINCLUDE) $< %.so: %.o gcc -shared $< -lm -o $@ all: primes.so spam.so numeric_demo.so clean: @echo Cleaning Demos @rm -f *.c *.o *.so *~ core core.* @cd callback; $(MAKE) clean @cd embed; $(MAKE) clean cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/000077500000000000000000000000001231323242300204315ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/bpnn3.pxd000066400000000000000000000011761231323242300221730ustar00rootroot00000000000000cimport cython cdef double rand(double a, double b, random=*) @cython.locals(i=Py_ssize_t) cdef list makeMatrix(Py_ssize_t I, Py_ssize_t J, fill=*) cdef class NN: cdef Py_ssize_t ni, nh, no cdef list ai, ah, ao cdef list wi, wo cdef list ci, co @cython.locals(i=Py_ssize_t, j=Py_ssize_t, k=Py_ssize_t) cpdef update(self, list inputs) @cython.locals(i=Py_ssize_t, j=Py_ssize_t, k=Py_ssize_t, change=double) cpdef double backPropagate(self, list targets, double N, M) @cython.locals(i=Py_ssize_t, p=list, error=double) cpdef train(self, list patterns, Py_ssize_t iterations=*, double N=*, M=*) cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/bpnn3.py000066400000000000000000000123741231323242300220320ustar00rootroot00000000000000#!/usr/bin/python # Back-Propagation Neural Networks # # Written in Python. See http://www.python.org/ # # Neil Schemenauer import math import random as random # Local imports import util random.seed(0) # calculate a random number where: a <= rand < b def rand(a, b, random=random.random): return (b-a)*random() + a # Make a matrix (we could use NumPy to speed this up) def makeMatrix(I, J, fill=0.0): m = [] for i in range(I): m.append([fill]*J) return m class NN(object): # print 'class NN' def __init__(self, ni, nh, no): # number of input, hidden, and output nodes self.ni = ni + 1 # +1 for bias node self.nh = nh self.no = no # activations for nodes self.ai = [1.0]*self.ni self.ah = [1.0]*self.nh self.ao = [1.0]*self.no # create weights self.wi = makeMatrix(self.ni, self.nh) self.wo = makeMatrix(self.nh, self.no) # set them to random vaules for i in range(self.ni): for j in range(self.nh): self.wi[i][j] = rand(-2.0, 2.0) for j in range(self.nh): for k in range(self.no): self.wo[j][k] = rand(-2.0, 2.0) # last change in weights for momentum self.ci = makeMatrix(self.ni, self.nh) self.co = makeMatrix(self.nh, self.no) def update(self, inputs): # print 'update', inputs if len(inputs) != self.ni-1: raise ValueError('wrong number of inputs') # input activations for i in range(self.ni-1): #self.ai[i] = 1.0/(1.0+math.exp(-inputs[i])) self.ai[i] = inputs[i] # hidden activations for j in range(self.nh): sum = 0.0 for i in range(self.ni): sum = sum + self.ai[i] * self.wi[i][j] self.ah[j] = 1.0/(1.0+math.exp(-sum)) # output activations for k in range(self.no): sum = 0.0 for j in range(self.nh): sum = sum + self.ah[j] * self.wo[j][k] self.ao[k] = 1.0/(1.0+math.exp(-sum)) return self.ao[:] def backPropagate(self, targets, N, M): # print N, M if len(targets) != self.no: raise ValueError('wrong number of target values') # calculate error terms for output output_deltas = [0.0] * self.no # print self.no for k in range(self.no): ao = self.ao[k] output_deltas[k] = ao*(1-ao)*(targets[k]-ao) # calculate error terms for hidden hidden_deltas = [0.0] * self.nh for j in range(self.nh): sum = 0.0 for k in range(self.no): sum = sum + output_deltas[k]*self.wo[j][k] hidden_deltas[j] = self.ah[j]*(1-self.ah[j])*sum # update output weights for j in range(self.nh): for k in range(self.no): change = output_deltas[k]*self.ah[j] self.wo[j][k] = self.wo[j][k] + N*change + M*self.co[j][k] self.co[j][k] = change # update input weights for i in range(self.ni): for j in range(self.nh): change = hidden_deltas[j]*self.ai[i] self.wi[i][j] = self.wi[i][j] + N*change + M*self.ci[i][j] self.ci[i][j] = change # calculate error error = 0.0 for k in range(len(targets)): error = error + 0.5*(targets[k]-self.ao[k])**2 return error def test(self, patterns): for p in patterns: print('%s -> %s' % (p[0], self.update(p[0]))) def weights(self): print('Input weights:') for i in range(self.ni): print(self.wi[i]) print('') print('Output weights:') for j in range(self.nh): print(self.wo[j]) def train(self, patterns, iterations=2000, N=0.5, M=0.1): # N: learning rate # M: momentum factor for i in range(iterations): error = 0.0 for p in patterns: inputs = p[0] targets = p[1] self.update(inputs) error = error + self.backPropagate(targets, N, M) #if i % 100 == 0: # print i, 'error %-14f' % error def demo(): # Teach network XOR function pat = [ [[0,0], [0]], [[0,1], [1]], [[1,0], [1]], [[1,1], [0]] ] # create a network with two input, two hidden, and two output nodes n = NN(2, 3, 1) # train it with some patterns n.train(pat, 5000) # test it #n.test(pat) def time(fn, *args): import time, traceback begin = time.time() result = fn(*args) end = time.time() return result, end-begin def test_bpnn(iterations): times = [] for _ in range(iterations): result, t = time(demo) times.append(t) return times main = test_bpnn if __name__ == "__main__": import optparse parser = optparse.OptionParser( usage="%prog [options]", description=("Test the performance of a neural network.")) util.add_standard_options_to(parser) options, args = parser.parse_args() util.run_benchmark(options, options.num_runs, test_bpnn) cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/generators.py000066400000000000000000000040411231323242300231530ustar00rootroot00000000000000#!/usr/bin/python # micro benchmarks for generators COUNT = 10000 import cython @cython.locals(N=cython.Py_ssize_t) def count_to(N): for i in range(N): yield i @cython.locals(i=cython.Py_ssize_t) def round_robin(*_iterators): iterators = list(_iterators) to_drop = [] while iterators: for i, it in enumerate(iterators): try: value = next(it) except StopIteration: to_drop.append(i) else: yield value if to_drop: for i in reversed(to_drop): del iterators[i] del to_drop[:] def yield_from(*iterators): for it in iterators: yield from it def bm_plain(N): return count_to(COUNT * N) def bm_round_robin(N): return round_robin(*[ count_to(COUNT // i) for i in range(1,N+1) ]) def bm_yield_from(N): return yield_from(count_to(N), round_robin(*[ yield_from(count_to(COUNT // i)) for i in range(1,N+1) ]), count_to(N)) def bm_yield_from_nested(N): return yield_from(count_to(N), yield_from(count_to(N), round_robin(*[ yield_from(count_to(COUNT // i)) for i in range(1,N+1) ]), count_to(N)), count_to(N)) def time(fn, *args): from time import time begin = time() result = list(fn(*args)) end = time() return result, end-begin def benchmark(N): times = [] for _ in range(N): result, t = time(bm_yield_from_nested, 10) times.append(t) return times main = benchmark if __name__ == "__main__": import optparse parser = optparse.OptionParser( usage="%prog [options]", description=("Micro benchmarks for generators.")) import util util.add_standard_options_to(parser) options, args = parser.parse_args() util.run_benchmark(options, options.num_runs, benchmark) cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/nbody.pxd000066400000000000000000000012671231323242300222670ustar00rootroot00000000000000 cimport cython @cython.locals(x=Py_ssize_t) cdef combinations(list l) @cython.locals(x1=double, x2=double, y1=double, y2=double, z1=double, z2=double, m1=double, m2=double, vx=double, vy=double, vz=double, i=long) cdef advance(double dt, long n, list bodies=*, list pairs=*) @cython.locals(x1=double, x2=double, y1=double, y2=double, z1=double, z2=double, m=double, m1=double, m2=double, vx=double, vy=double, vz=double) cdef report_energy(list bodies=*, list pairs=*, double e=*) @cython.locals(vx=double, vy=double, vz=double, m=double) cdef offset_momentum(tuple ref, list bodies=*, double px=*, double py=*, double pz=*) cpdef test_nbody(long iterations) cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/nbody.py000066400000000000000000000107151231323242300221220ustar00rootroot00000000000000#!/usr/bin/env python """N-body benchmark from the Computer Language Benchmarks Game. This is intended to support Unladen Swallow's perf.py. Accordingly, it has been modified from the Shootout version: - Accept standard Unladen Swallow benchmark options. - Run report_energy()/advance() in a loop. - Reimplement itertools.combinations() to work with older Python versions. """ # Pulled from http://shootout.alioth.debian.org/u64q/benchmark.php?test=nbody&lang=python&id=4 # Contributed by Kevin Carson. # Modified by Tupteq, Fredrik Johansson, and Daniel Nanz. __contact__ = "collinwinter@google.com (Collin Winter)" # Python imports import optparse import sys from time import time # Local imports import util def combinations(l): """Pure-Python implementation of itertools.combinations(l, 2).""" result = [] for x in range(len(l) - 1): ls = l[x+1:] for y in ls: result.append((l[x],y)) return result PI = 3.14159265358979323 SOLAR_MASS = 4 * PI * PI DAYS_PER_YEAR = 365.24 BODIES = { 'sun': ([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], SOLAR_MASS), 'jupiter': ([4.84143144246472090e+00, -1.16032004402742839e+00, -1.03622044471123109e-01], [1.66007664274403694e-03 * DAYS_PER_YEAR, 7.69901118419740425e-03 * DAYS_PER_YEAR, -6.90460016972063023e-05 * DAYS_PER_YEAR], 9.54791938424326609e-04 * SOLAR_MASS), 'saturn': ([8.34336671824457987e+00, 4.12479856412430479e+00, -4.03523417114321381e-01], [-2.76742510726862411e-03 * DAYS_PER_YEAR, 4.99852801234917238e-03 * DAYS_PER_YEAR, 2.30417297573763929e-05 * DAYS_PER_YEAR], 2.85885980666130812e-04 * SOLAR_MASS), 'uranus': ([1.28943695621391310e+01, -1.51111514016986312e+01, -2.23307578892655734e-01], [2.96460137564761618e-03 * DAYS_PER_YEAR, 2.37847173959480950e-03 * DAYS_PER_YEAR, -2.96589568540237556e-05 * DAYS_PER_YEAR], 4.36624404335156298e-05 * SOLAR_MASS), 'neptune': ([1.53796971148509165e+01, -2.59193146099879641e+01, 1.79258772950371181e-01], [2.68067772490389322e-03 * DAYS_PER_YEAR, 1.62824170038242295e-03 * DAYS_PER_YEAR, -9.51592254519715870e-05 * DAYS_PER_YEAR], 5.15138902046611451e-05 * SOLAR_MASS) } SYSTEM = list(BODIES.values()) PAIRS = combinations(SYSTEM) def advance(dt, n, bodies=SYSTEM, pairs=PAIRS): for i in range(n): for (([x1, y1, z1], v1, m1), ([x2, y2, z2], v2, m2)) in pairs: dx = x1 - x2 dy = y1 - y2 dz = z1 - z2 mag = dt * ((dx * dx + dy * dy + dz * dz) ** (-1.5)) b1m = m1 * mag b2m = m2 * mag v1[0] -= dx * b2m v1[1] -= dy * b2m v1[2] -= dz * b2m v2[0] += dx * b1m v2[1] += dy * b1m v2[2] += dz * b1m for (r, [vx, vy, vz], m) in bodies: r[0] += dt * vx r[1] += dt * vy r[2] += dt * vz def report_energy(bodies=SYSTEM, pairs=PAIRS, e=0.0): for (((x1, y1, z1), v1, m1), ((x2, y2, z2), v2, m2)) in pairs: dx = x1 - x2 dy = y1 - y2 dz = z1 - z2 e -= (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5) for (r, [vx, vy, vz], m) in bodies: e += m * (vx * vx + vy * vy + vz * vz) / 2. return e def offset_momentum(ref, bodies=SYSTEM, px=0.0, py=0.0, pz=0.0): for (r, [vx, vy, vz], m) in bodies: px -= vx * m py -= vy * m pz -= vz * m (r, v, m) = ref v[0] = px / m v[1] = py / m v[2] = pz / m def test_nbody(iterations): # Warm-up runs. report_energy() advance(0.01, 20000) report_energy() times = [] for _ in range(iterations): t0 = time() report_energy() advance(0.01, 20000) report_energy() t1 = time() times.append(t1 - t0) return times main = test_nbody if __name__ == '__main__': parser = optparse.OptionParser( usage="%prog [options]", description=("Run the n-body benchmark.")) util.add_standard_options_to(parser) options, args = parser.parse_args() offset_momentum(BODIES['sun']) # Set up global state util.run_benchmark(options, options.num_runs, test_nbody) cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/nqueens.py000066400000000000000000000045761231323242300224750ustar00rootroot00000000000000#!/usr/bin/env python """Simple, brute-force N-Queens solver.""" __author__ = "collinwinter@google.com (Collin Winter)" # Python imports import optparse import re import string from time import time # Local imports import util import cython try: from builtins import range as _xrange except ImportError: from __builtin__ import xrange as _xrange # Pure-Python implementation of itertools.permutations(). @cython.locals(n=int, i=int, j=int) def permutations(iterable): """permutations(range(3), 2) --> (0,1) (0,2) (1,0) (1,2) (2,0) (2,1)""" pool = tuple(iterable) n = len(pool) indices = list(range(n)) cycles = list(range(1, n+1))[::-1] yield [ pool[i] for i in indices ] while n: for i in reversed(range(n)): j = cycles[i] - 1 if j == 0: indices[i:] = indices[i+1:] + indices[i:i+1] cycles[i] = n - i else: cycles[i] = j indices[i], indices[-j] = indices[-j], indices[i] yield [ pool[i] for i in indices ] break else: return # From http://code.activestate.com/recipes/576647/ @cython.locals(queen_count=int, i=int, vec=list) def n_queens(queen_count): """N-Queens solver. Args: queen_count: the number of queens to solve for. This is also the board size. Yields: Solutions to the problem. Each yielded value is looks like (3, 8, 2, 1, 4, ..., 6) where each number is the column position for the queen, and the index into the tuple indicates the row. """ cols = list(range(queen_count)) for vec in permutations(cols): if (queen_count == len({ vec[i]+i for i in cols }) == len({ vec[i]-i for i in cols })): yield vec def test_n_queens(iterations): # Warm-up runs. list(n_queens(8)) list(n_queens(8)) times = [] for _ in _xrange(iterations): t0 = time() list(n_queens(8)) t1 = time() times.append(t1 - t0) return times main = test_n_queens if __name__ == "__main__": parser = optparse.OptionParser( usage="%prog [options]", description=("Test the performance of an N-Queens solvers.")) util.add_standard_options_to(parser) options, args = parser.parse_args() util.run_benchmark(options, options.num_runs, test_n_queens) cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/richards.pxd000066400000000000000000000045711231323242300227540ustar00rootroot00000000000000cimport cython @cython.final cdef class Packet: cdef public object link cdef public object ident cdef public object kind cdef public Py_ssize_t datum cdef public list data cpdef append_to(self,lst) cdef class TaskRec: pass @cython.final cdef class DeviceTaskRec(TaskRec): cdef public object pending @cython.final cdef class IdleTaskRec(TaskRec): cdef public long control cdef public Py_ssize_t count @cython.final cdef class HandlerTaskRec(TaskRec): cdef public object work_in # = None cdef public object device_in # = None cpdef workInAdd(self, Packet p) cpdef deviceInAdd(self, Packet p) @cython.final cdef class WorkerTaskRec(TaskRec): cdef public object destination # = I_HANDLERA cdef public Py_ssize_t count cdef class TaskState: cdef public bint packet_pending # = True cdef public bint task_waiting # = False cdef public bint task_holding # = False cpdef packetPending(self) cpdef waiting(self) cpdef running(self) cpdef waitingWithPacket(self) cpdef bint isPacketPending(self) cpdef bint isTaskWaiting(self) cpdef bint isTaskHolding(self) cpdef bint isTaskHoldingOrWaiting(self) cpdef bint isWaitingWithPacket(self) cdef class TaskWorkArea: cdef public list taskTab # = [None] * TASKTABSIZE cdef public object taskList # = None cdef public Py_ssize_t holdCount # = 0 cdef public Py_ssize_t qpktCount # = 0 cdef class Task(TaskState): cdef public Task link # = taskWorkArea.taskList cdef public object ident # = i cdef public object priority # = p cdef public object input # = w cdef public object handle # = r cpdef addPacket(self,Packet p,Task old) cpdef runTask(self) cpdef waitTask(self) cpdef hold(self) cpdef release(self,i) cpdef qpkt(self,Packet pkt) cpdef findtcb(self,id) cdef class DeviceTask(Task): @cython.locals(d=DeviceTaskRec) cpdef fn(self,Packet pkt,DeviceTaskRec r) cdef class HandlerTask(Task): @cython.locals(h=HandlerTaskRec) cpdef fn(self,Packet pkt,HandlerTaskRec r) cdef class IdleTask(Task): @cython.locals(i=IdleTaskRec) cpdef fn(self,Packet pkt,IdleTaskRec r) cdef class WorkTask(Task): @cython.locals(w=WorkerTaskRec) cpdef fn(self,Packet pkt,WorkerTaskRec r) @cython.locals(t=Task) cpdef schedule() cdef class Richards: cpdef run(self, iterations) cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/richards.py000066400000000000000000000244301231323242300226050ustar00rootroot00000000000000# based on a Java version: # Based on original version written in BCPL by Dr Martin Richards # in 1981 at Cambridge University Computer Laboratory, England # and a C++ version derived from a Smalltalk version written by # L Peter Deutsch. # Java version: Copyright (C) 1995 Sun Microsystems, Inc. # Translation from C++, Mario Wolczko # Outer loop added by Alex Jacoby # Task IDs I_IDLE = 1 I_WORK = 2 I_HANDLERA = 3 I_HANDLERB = 4 I_DEVA = 5 I_DEVB = 6 # Packet types K_DEV = 1000 K_WORK = 1001 # Packet BUFSIZE = 4 BUFSIZE_RANGE = range(BUFSIZE) class Packet(object): def __init__(self,l,i,k): self.link = l self.ident = i self.kind = k self.datum = 0 self.data = [0] * BUFSIZE def append_to(self,lst): self.link = None if lst is None: return self else: p = lst next = p.link while next is not None: p = next next = p.link p.link = self return lst # Task Records class TaskRec(object): pass class DeviceTaskRec(TaskRec): def __init__(self): self.pending = None class IdleTaskRec(TaskRec): def __init__(self): self.control = 1 self.count = 10000 class HandlerTaskRec(TaskRec): def __init__(self): self.work_in = None self.device_in = None def workInAdd(self,p): self.work_in = p.append_to(self.work_in) return self.work_in def deviceInAdd(self,p): self.device_in = p.append_to(self.device_in) return self.device_in class WorkerTaskRec(TaskRec): def __init__(self): self.destination = I_HANDLERA self.count = 0 # Task class TaskState(object): def __init__(self): self.packet_pending = True self.task_waiting = False self.task_holding = False def packetPending(self): self.packet_pending = True self.task_waiting = False self.task_holding = False return self def waiting(self): self.packet_pending = False self.task_waiting = True self.task_holding = False return self def running(self): self.packet_pending = False self.task_waiting = False self.task_holding = False return self def waitingWithPacket(self): self.packet_pending = True self.task_waiting = True self.task_holding = False return self def isPacketPending(self): return self.packet_pending def isTaskWaiting(self): return self.task_waiting def isTaskHolding(self): return self.task_holding def isTaskHoldingOrWaiting(self): return self.task_holding or (not self.packet_pending and self.task_waiting) def isWaitingWithPacket(self): return self.packet_pending and self.task_waiting and not self.task_holding tracing = False layout = 0 def trace(a): global layout layout -= 1 if layout <= 0: print() layout = 50 print(a, end='') TASKTABSIZE = 10 class TaskWorkArea(object): def __init__(self): self.taskTab = [None] * TASKTABSIZE self.taskList = None self.holdCount = 0 self.qpktCount = 0 taskWorkArea = TaskWorkArea() class Task(TaskState): def __init__(self,i,p,w,initialState,r): self.link = taskWorkArea.taskList self.ident = i self.priority = p self.input = w self.packet_pending = initialState.isPacketPending() self.task_waiting = initialState.isTaskWaiting() self.task_holding = initialState.isTaskHolding() self.handle = r taskWorkArea.taskList = self taskWorkArea.taskTab[i] = self def fn(self,pkt,r): raise NotImplementedError def addPacket(self,p,old): if self.input is None: self.input = p self.packet_pending = True if self.priority > old.priority: return self else: p.append_to(self.input) return old def runTask(self): if self.isWaitingWithPacket(): msg = self.input self.input = msg.link if self.input is None: self.running() else: self.packetPending() else: msg = None return self.fn(msg,self.handle) def waitTask(self): self.task_waiting = True return self def hold(self): taskWorkArea.holdCount += 1 self.task_holding = True return self.link def release(self,i): t = self.findtcb(i) t.task_holding = False if t.priority > self.priority: return t else: return self def qpkt(self,pkt): t = self.findtcb(pkt.ident) taskWorkArea.qpktCount += 1 pkt.link = None pkt.ident = self.ident return t.addPacket(pkt,self) def findtcb(self,id): t = taskWorkArea.taskTab[id] if t is None: raise Exception("Bad task id %d" % id) return t # DeviceTask class DeviceTask(Task): def __init__(self,i,p,w,s,r): Task.__init__(self,i,p,w,s,r) def fn(self,pkt,r): d = r assert isinstance(d, DeviceTaskRec) if pkt is None: pkt = d.pending if pkt is None: return self.waitTask() else: d.pending = None return self.qpkt(pkt) else: d.pending = pkt if tracing: trace(pkt.datum) return self.hold() class HandlerTask(Task): def __init__(self,i,p,w,s,r): Task.__init__(self,i,p,w,s,r) def fn(self,pkt,r): h = r assert isinstance(h, HandlerTaskRec) if pkt is not None: if pkt.kind == K_WORK: h.workInAdd(pkt) else: h.deviceInAdd(pkt) work = h.work_in if work is None: return self.waitTask() count = work.datum if count >= BUFSIZE: h.work_in = work.link return self.qpkt(work) dev = h.device_in if dev is None: return self.waitTask() h.device_in = dev.link dev.datum = work.data[count] work.datum = count + 1 return self.qpkt(dev) # IdleTask class IdleTask(Task): def __init__(self,i,p,w,s,r): Task.__init__(self,i,0,None,s,r) def fn(self,pkt,r): i = r assert isinstance(i, IdleTaskRec) i.count -= 1 if i.count == 0: return self.hold() elif i.control & 1 == 0: i.control //= 2 return self.release(I_DEVA) else: i.control = i.control//2 ^ 0xd008 return self.release(I_DEVB) # WorkTask A = ord('A') class WorkTask(Task): def __init__(self,i,p,w,s,r): Task.__init__(self,i,p,w,s,r) def fn(self,pkt,r): w = r assert isinstance(w, WorkerTaskRec) if pkt is None: return self.waitTask() if w.destination == I_HANDLERA: dest = I_HANDLERB else: dest = I_HANDLERA w.destination = dest pkt.ident = dest pkt.datum = 0 for i in BUFSIZE_RANGE: # range(BUFSIZE) w.count += 1 if w.count > 26: w.count = 1 pkt.data[i] = A + w.count - 1 return self.qpkt(pkt) import time def schedule(): t = taskWorkArea.taskList while t is not None: pkt = None if tracing: print("tcb =", t.ident) if t.isTaskHoldingOrWaiting(): t = t.link else: if tracing: trace(chr(ord("0")+t.ident)) t = t.runTask() class Richards(object): def run(self, iterations): for i in range(iterations): taskWorkArea.holdCount = 0 taskWorkArea.qpktCount = 0 IdleTask(I_IDLE, 1, 10000, TaskState().running(), IdleTaskRec()) wkq = Packet(None, 0, K_WORK) wkq = Packet(wkq , 0, K_WORK) WorkTask(I_WORK, 1000, wkq, TaskState().waitingWithPacket(), WorkerTaskRec()) wkq = Packet(None, I_DEVA, K_DEV) wkq = Packet(wkq , I_DEVA, K_DEV) wkq = Packet(wkq , I_DEVA, K_DEV) HandlerTask(I_HANDLERA, 2000, wkq, TaskState().waitingWithPacket(), HandlerTaskRec()) wkq = Packet(None, I_DEVB, K_DEV) wkq = Packet(wkq , I_DEVB, K_DEV) wkq = Packet(wkq , I_DEVB, K_DEV) HandlerTask(I_HANDLERB, 3000, wkq, TaskState().waitingWithPacket(), HandlerTaskRec()) wkq = None; DeviceTask(I_DEVA, 4000, wkq, TaskState().waiting(), DeviceTaskRec()); DeviceTask(I_DEVB, 5000, wkq, TaskState().waiting(), DeviceTaskRec()); schedule() if taskWorkArea.holdCount == 9297 and taskWorkArea.qpktCount == 23246: pass else: return False return True def entry_point(iterations): r = Richards() startTime = time.time() result = r.run(iterations) endTime = time.time() return result, startTime, endTime def main(iterations = 10, entry_point = entry_point): print("Richards benchmark (Python) starting... [%r]" % entry_point) result, startTime, endTime = entry_point(iterations) if not result: print("Incorrect results!") return -1 print("finished.") total_s = endTime - startTime print("Total time for %d iterations: %.2f secs" % (iterations, total_s)) print("Average time per iteration: %.2f ms" % (total_s*1000/iterations)) return 42 try: import sys if '-nojit' in sys.argv: sys.argv.remove('-nojit') raise ImportError import pypyjit except ImportError: pass else: import types for item in globals().values(): if isinstance(item, types.FunctionType): pypyjit.enable(item.func_code) elif isinstance(item, type): for it in item.__dict__.values(): if isinstance(it, types.FunctionType): pypyjit.enable(it.func_code) if __name__ == '__main__': import sys if len(sys.argv) >= 2: main(iterations = int(sys.argv[1])) else: main() cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/setup.py000066400000000000000000000005151231323242300221440ustar00rootroot00000000000000from distutils.core import setup from Cython.Build import cythonize directives = { 'optimize.inline_defnode_calls': True } setup( name = 'benchmarks', ext_modules = cythonize("*.py", language_level=3, annotate=True, compiler_directives=directives, exclude="setup.py"), ) cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/spectralnorm.pxd000066400000000000000000000006411231323242300236600ustar00rootroot00000000000000 cimport cython cdef inline double eval_A(double i, double j) @cython.locals(i=long) cdef list eval_A_times_u(list u) @cython.locals(i=long) cdef list eval_At_times_u(list u) cdef list eval_AtA_times_u(list u) @cython.locals(j=long, u_j=double, partial_sum=double) cdef double part_A_times_u(double i, list u) @cython.locals(j=long, u_j=double, partial_sum=double) cdef double part_At_times_u(double i, list u) cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/spectralnorm.py000066400000000000000000000031351231323242300235160ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The Computer Language Benchmarks Game # http://shootout.alioth.debian.org/ # Contributed by Sebastien Loisel # Fixed by Isaac Gouy # Sped up by Josh Goldfoot # Dirtily sped up by Simon Descarpentries # Concurrency by Jason Stitt from time import time import util import optparse def eval_A (i, j): return 1.0 / ((i + j) * (i + j + 1) / 2 + i + 1) def eval_A_times_u (u): return [ part_A_times_u(i,u) for i in range(len(u)) ] def eval_At_times_u (u): return [ part_At_times_u(i,u) for i in range(len(u)) ] def eval_AtA_times_u (u): return eval_At_times_u (eval_A_times_u (u)) def part_A_times_u(i, u): partial_sum = 0 for j, u_j in enumerate(u): partial_sum += eval_A (i, j) * u_j return partial_sum def part_At_times_u(i, u): partial_sum = 0 for j, u_j in enumerate(u): partial_sum += eval_A (j, i) * u_j return partial_sum DEFAULT_N = 130 def main(n): times = [] for i in range(n): t0 = time() u = [1] * DEFAULT_N for dummy in range (10): v = eval_AtA_times_u (u) u = eval_AtA_times_u (v) vBv = vv = 0 for ue, ve in zip (u, v): vBv += ue * ve vv += ve * ve tk = time() times.append(tk - t0) return times if __name__ == "__main__": parser = optparse.OptionParser( usage="%prog [options]", description="Test the performance of the spectralnorm benchmark") util.add_standard_options_to(parser) options, args = parser.parse_args() util.run_benchmark(options, options.num_runs, main) cython-0.20.1+git90-g0e6e38e/Demos/benchmarks/util.py000066400000000000000000000035141231323242300217630ustar00rootroot00000000000000#!/usr/bin/env python """Utility code for benchmark scripts.""" __author__ = "collinwinter@google.com (Collin Winter)" import math import operator try: reduce except NameError: from functools import reduce def run_benchmark(options, num_runs, bench_func, *args): """Run the given benchmark, print results to stdout. Args: options: optparse.Values instance. num_runs: number of times to run the benchmark bench_func: benchmark function. `num_runs, *args` will be passed to this function. This should return a list of floats (benchmark execution times). """ if options.profile: import cProfile prof = cProfile.Profile() prof.runcall(bench_func, num_runs, *args) prof.print_stats(sort=options.profile_sort) else: data = bench_func(num_runs, *args) if options.take_geo_mean: product = reduce(operator.mul, data, 1) print(math.pow(product, 1.0 / len(data))) else: for x in data: print(x) def add_standard_options_to(parser): """Add a bunch of common command-line flags to an existing OptionParser. This function operates on `parser` in-place. Args: parser: optparse.OptionParser instance. """ parser.add_option("-n", action="store", type="int", default=100, dest="num_runs", help="Number of times to run the test.") parser.add_option("--profile", action="store_true", help="Run the benchmark through cProfile.") parser.add_option("--profile_sort", action="store", type="str", default="time", help="Column to sort cProfile output by.") parser.add_option("--take_geo_mean", action="store_true", help="Return the geo mean, rather than individual data.") cython-0.20.1+git90-g0e6e38e/Demos/callback/000077500000000000000000000000001231323242300200505ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Demos/callback/Makefile000066400000000000000000000002431231323242300215070ustar00rootroot00000000000000all: python Setup.py build_ext --inplace test: all python run_cheese.py clean: @echo Cleaning Demos/callback @rm -f cheese.c *.o *.so *~ core @rm -rf build cython-0.20.1+git90-g0e6e38e/Demos/callback/Makefile.nodistutils000066400000000000000000000005031231323242300240660ustar00rootroot00000000000000PYHOME = $(HOME)/pkg/python/version PYINCLUDE = \ -I$(PYHOME)/include/python2.2 \ -I$(PYHOME)/$(ARCH)/include/python2.2 %.c: %.pyx ../../bin/cython $< %.o: %.c gcc -c -fPIC $(PYINCLUDE) $< %.so: %.o gcc -shared $< -lm -o $@ all: cheese.so clean: @echo Cleaning Demos/callback @rm -f *.c *.o *.so *~ core core.* cython-0.20.1+git90-g0e6e38e/Demos/callback/README.txt000066400000000000000000000005271231323242300215520ustar00rootroot00000000000000This example demonstrates how you can wrap a C API that has a callback interface, so that you can pass Python functions to it as callbacks. The files cheesefinder.h and cheesefinder.c represent the C library to be wrapped. The file cheese.pyx is the Pyrex module which wraps it. The file run_cheese.py demonstrates how to call the wrapper. cython-0.20.1+git90-g0e6e38e/Demos/callback/Setup.py000066400000000000000000000003521231323242300215220ustar00rootroot00000000000000from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize setup( name = 'callback', ext_modules=cythonize([ Extension("cheese", ["cheese.pyx", "cheesefinder.c"]), ]), ) cython-0.20.1+git90-g0e6e38e/Demos/callback/cheese.pyx000066400000000000000000000005051231323242300220460ustar00rootroot00000000000000# # Cython wrapper for the cheesefinder API # cdef extern from "cheesefinder.h": ctypedef void (*cheesefunc)(char *name, void *user_data) void find_cheeses(cheesefunc user_func, void *user_data) def find(f): find_cheeses(callback, f) cdef void callback(char *name, void *f): (f)(name) cython-0.20.1+git90-g0e6e38e/Demos/callback/cheesefinder.c000066400000000000000000000005031231323242300226360ustar00rootroot00000000000000/* * An example of a C API that provides a callback mechanism. */ #include "cheesefinder.h" static char *cheeses[] = { "cheddar", "camembert", "that runny one", 0 }; void find_cheeses(cheesefunc user_func, void *user_data) { char **p = cheeses; while (*p) { user_func(*p, user_data); ++p; } } cython-0.20.1+git90-g0e6e38e/Demos/callback/cheesefinder.h000066400000000000000000000001631231323242300226450ustar00rootroot00000000000000typedef void (*cheesefunc)(char *name, void *user_data); void find_cheeses(cheesefunc user_func, void *user_data); cython-0.20.1+git90-g0e6e38e/Demos/callback/run_cheese.py000066400000000000000000000001501231323242300225360ustar00rootroot00000000000000import cheese def report_cheese(name): print("Found cheese: " + name) cheese.find(report_cheese) cython-0.20.1+git90-g0e6e38e/Demos/embed/000077500000000000000000000000001231323242300173705ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Demos/embed/Makefile000066400000000000000000000032701231323242300210320ustar00rootroot00000000000000# Makefile for creating our standalone Cython program PYTHON=python PYVERSION=$(shell $(PYTHON) -c "import sys; print(sys.version[:3])") INCDIR=$(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_python_inc())") PLATINCDIR=$(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_python_inc(plat_specific=True))") LIBDIR1=$(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBDIR'))") LIBDIR2=$(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBPL'))") PYLIB=$(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBRARY')[3:-2])") CC=$(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('CC'))") LINKCC=$(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LINKCC'))") LINKFORSHARED=$(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LINKFORSHARED'))") LIBS=$(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBS'))") SYSLIBS= $(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('SYSLIBS'))") embedded: embedded.o $(LINKCC) -o $@ $^ -L$(LIBDIR1) -L$(LIBDIR2) -l$(PYLIB) $(LIBS) $(SYSLIBS) $(LINKFORSHARED) embedded.o: embedded.c $(CC) -c $^ -I$(INCDIR) -I$(PLATINCDIR) CYTHON=../../cython.py embedded.c: embedded.pyx @$(PYTHON) $(CYTHON) --embed embedded.pyx all: embedded clean: @echo Cleaning Demos/embed @rm -f *~ *.o *.so core core.* *.c embedded test.output test: clean all ./embedded > test.output $(PYTHON) assert_equal.py embedded.output test.output cython-0.20.1+git90-g0e6e38e/Demos/embed/Makefile.msc000066400000000000000000000017551231323242300216210ustar00rootroot00000000000000# Makefile for Microsoft C Compiler, building a DLL PYVERSION = 2.2 PYHOME = \Python$(PYVERSION:.=) PYINCLUDE = -I$(PYHOME)\include PYLIB = /LIBPATH:$(PYHOME)\libs CFLAGS = $(PYINCLUDE) /Ox /W3 /GX -nologo .SUFFIXES: .exe .dll .obj .c .cpp .pyx .pyx.c: $(PYHOME)\Python.exe ../../cython.py $< all: main.exe clean: del /Q/F *.obj embedded.h embedded.c main.exe embedded.dll embedded.lib embedded.exp # When linking the DLL we must explicitly list all of the exports # There doesn't seem to be an easy way to get DL_EXPORT to have the correct definition # to do the export for us without breaking the importing of symbols from the core # python library. embedded.dll: embedded.obj link /nologo /DLL /INCREMENTAL:NO $(PYLIB) $** /IMPLIB:$*.lib /DEF:<< /OUT:$*.dll EXPORTS initembedded EXPORTS spam << main.exe: main.obj embedded.lib link /nologo $** $(PYLIB) /OUT:main.exe embedded.h: embedded.c main.obj: embedded.h embedded.obj: embedded.c $(CC) /MD $(CFLAGS) -c $** embedded.lib: embedded.dll cython-0.20.1+git90-g0e6e38e/Demos/embed/Makefile.msc.static000066400000000000000000000007641231323242300231060ustar00rootroot00000000000000# Makefile for Microsoft compiler statically linking PYVERSION = 2.2 PYHOME = \Python$(PYVERSION:.=) PYINCLUDE = -I$(PYHOME)\include PYLIB = /LIBPATH:$(PYHOME)\libs python22.lib CFLAGS = $(PYINCLUDE) /Ox /W3 /GX -nologo .SUFFIXES: .exe .dll .obj .c .cpp .pyx .pyx.c: $(PYHOME)\Python.exe ../../cython.py $< all: main.exe clean: -del /Q/F *.obj embedded.h embedded.c main.exe main.exe: main.obj embedded.obj link /nologo $** $(PYLIB) /OUT:main.exe embedded.h: embedded.c main.obj: embedded.h cython-0.20.1+git90-g0e6e38e/Demos/embed/Makefile.unix000066400000000000000000000006301231323242300220110ustar00rootroot00000000000000# Makefile for creating our standalone Cython program PYVERSION=2.3 PYPREFIX=/usr INCLUDES=-I$(PYPREFIX)/include/python$(PYVERSION) embedded: embedded.o gcc -o $@ $^ -lpython$(PYVERSION) embedded.o: embedded.c gcc -c $^ $(INCLUDES) embedded.c: embedded.pyx @python ../../cython.py --embed embedded.pyx all: embedded clean: @echo Cleaning Demos/embed @rm -f *~ *.o *.so core core.* *.c embedded cython-0.20.1+git90-g0e6e38e/Demos/embed/README000066400000000000000000000003141231323242300202460ustar00rootroot00000000000000This example demonstrates how Cython-generated code can be called directly from a main program written in C. The Windows makefiles were contributed by Duncan Booth . cython-0.20.1+git90-g0e6e38e/Demos/embed/assert_equal.py000066400000000000000000000003431231323242300224320ustar00rootroot00000000000000import sys f1 = open(sys.argv[1]) f2 = open(sys.argv[2]) try: if f1.read() != f2.read(): print ("Files differ") sys.exit(1) else: print ("Files identical") finally: f1.close() f2.close() cython-0.20.1+git90-g0e6e38e/Demos/embed/embedded.output000066400000000000000000000000331231323242300223770ustar00rootroot00000000000000__main__ Hi, I'm embedded. cython-0.20.1+git90-g0e6e38e/Demos/embed/embedded.pyx000066400000000000000000000001601231323242300216600ustar00rootroot00000000000000 print __name__ if __name__ == "__main__": print "Hi, I'm embedded." else: print "I'm being imported." cython-0.20.1+git90-g0e6e38e/Demos/freeze/000077500000000000000000000000001231323242300175745ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Demos/freeze/Makefile000066400000000000000000000025071231323242300212400ustar00rootroot00000000000000CC = gcc CYTHON = ../../bin/cython CYTHON_FREEZE = ../../bin/cython_freeze PYTHON = python RST2HTML = rst2html PY_LDFLAGS = $(shell $(PYTHON) -c 'from distutils.sysconfig import get_config_var as g; import sys; sys.stdout.write(" ".join([g("LINKFORSHARED"), "-L"+g("LIBPL")]) + "\n")') PY_CPPFLAGS = $(shell $(PYTHON) -c 'from distutils.sysconfig import *; import sys; sys.stdout.write("-I"+get_python_inc() + "\n")') PY_LDLIBS = $(shell $(PYTHON) -c 'from distutils.sysconfig import get_config_var as g; import sys; sys.stdout.write(" ".join(["-lpython"+g("VERSION"), g("SYSLIBS"), g("LIBS"), g("LOCALMODLIBS")]) + "\n")') CFLAGS = -fPIC -fno-strict-aliasing -g -O2 -Wall -Wextra CPPFLAGS = $(PY_CPPFLAGS) LDFLAGS = $(PY_LDFLAGS) LDLIBS = $(PY_LDLIBS) # Name of executable TARGETS = nCr python # List of Cython source files, with main module first. CYTHON_SOURCE = combinatorics.pyx cmath.pyx CYTHON_SECONDARY = $(CYTHON_SOURCE:.pyx=.c) $(TARGETS:=.c) all : $(TARGETS) html : README.html $(TARGETS) : % : %.o $(CYTHON_SOURCE:.pyx=.o) nCr.c : $(CYTHON_FREEZE) $(CYTHON_SOURCE:.pyx=) > $@ python.c : $(CYTHON_FREEZE) --pymain $(CYTHON_SOURCE:.pyx=) > $@ %.c : %.pyx $(CYTHON) $(CYTHONFLAGS) $^ %.html : %.txt $(RST2HTML) $^ $@ clean: $(RM) *.o $(CYTHON_SECONDARY) $(TARGETS) README.html .PHONY: clean .SECONDARY: $(CYTHON_SECONDARY) cython-0.20.1+git90-g0e6e38e/Demos/freeze/README.txt000066400000000000000000000067611231323242300213040ustar00rootroot00000000000000NAME ==== cython_freeze - create a C file for embedding Cython modules SYNOPSIS ======== cython_freeze [-o outfile] [-p] module [...] DESCRIPTION =========== **cython_freeze** generates a C source file to embed a Python interpreter with one or more Cython modules built in. This allows one to create a single executable from Cython code, without having to have separate shared objects for each Cython module. A major advantage of this approach is that it allows debuging with gprof(1), which does not work with shared objects. Unless ``-p`` is given, the first module's ``__name__`` is set to ``"__main__"`` and is imported on startup; if ``-p`` is given, a normal Python interpreter is built, with the given modules built into the binary. Note that this method differs from ``cython --embed``. The ``--embed`` options modifies the resulting C source file to include a ``main()`` function, so it can only be used on a single Cython module. The advantage ``--embed`` is simplicity. This module, on the other hand, can be used with multiple modules, but it requires another C source file to be created. OPTIONS ======= -o FILE, --outfile=FILE write output to FILE instead of standard output -p, --pymain do not automatically run the first module as __main__ EXAMPLE ======= In the Demos/freeze directory, there exist two Cython modules: cmath.pyx A module that interfaces with the -lm library. combinatorics.pyx A module that implements n-choose-r using cmath. Both modules have the Python idiom ``if __name__ == "__main__"``, which only execute if that module is the "main" module. If run as main, cmath prints the factorial of the argument, while combinatorics prints n-choose-r. The provided Makefile creates an executable, *nCr*, using combinatorics as the "main" module. It basically performs the following (ignoring the compiler flags):: $ cython_freeze combinatorics cmath > nCr.c $ cython combinatorics.pyx $ cython cmath.pyx $ gcc -c nCr.c $ gcc -c combinatorics.c $ gcc -c cmath.c $ gcc nCr.o combinatorics.o cmath.o -o nCr Because the combinatorics module was listed first, its ``__name__`` is set to ``"__main__"``, while cmath's is set to ``"cmath"``. The executable now contains a Python interpreter and both Cython modules. :: $ ./nCr USAGE: ./nCr n r Prints n-choose-r. $ ./nCr 15812351235 12 5.10028093999e+113 You may wish to build a normal Python interpreter, rather than having one module as "main". This may happen if you want to use your module from an interactive shell or from another script, yet you still want it statically linked so you can profile it with gprof. To do this, add the ``--pymain`` flag to ``cython_freeze``. In the Makefile, the *python* executable is built like this. :: $ cython_freeze --pymain combinatorics cmath -o python.c $ gcc -c python.c $ gcc python.o combinatorics.o cmath.o -o python Now ``python`` is a normal Python interpreter, but the cmath and combinatorics modules will be built into the executable. :: $ ./python Python 2.6.2 (release26-maint, Apr 19 2009, 01:58:18) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import cmath >>> cmath.factorial(155) 4.7891429014634364e+273 PREREQUISITES ============= Cython 0.11.2 (or newer, assuming the API does not change) SEE ALSO ======== * `Python `_ * `Cython `_ * `freeze.py `_ cython-0.20.1+git90-g0e6e38e/Demos/freeze/cmath.pyx000066400000000000000000000010771231323242300214370ustar00rootroot00000000000000cdef extern from "math.h": double c_lgamma "lgamma" (double) double c_exp "exp" (double) def exp(n): """Return e**n.""" return c_exp(n) def lfactorial(n): """Return an estimate of the log factorial of n.""" return c_lgamma(n+1) def factorial(n): """Return an estimate of the factorial of n.""" return c_exp( c_lgamma(n+1) ) if __name__ == "__main__": import sys if len(sys.argv) != 2: sys.stderr.write("USAGE: %s n\nPrints n!.\n" % sys.argv[0]) sys.exit(2) n, = map(float, sys.argv[1:]) print factorial(n) cython-0.20.1+git90-g0e6e38e/Demos/freeze/combinatorics.pyx000066400000000000000000000006651231323242300232010ustar00rootroot00000000000000import cmath def nCr(n, r): """Return the number of ways to choose r elements of a set of n.""" return cmath.exp( cmath.lfactorial(n) - cmath.lfactorial(r) - cmath.lfactorial(n-r) ) if __name__ == "__main__": import sys if len(sys.argv) != 3: sys.stderr.write("USAGE: %s n r\nPrints n-choose-r.\n" % sys.argv[0]) sys.exit(2) n, r = map(float, sys.argv[1:]) print nCr(n, r) cython-0.20.1+git90-g0e6e38e/Demos/integrate0.py000066400000000000000000000002241231323242300207260ustar00rootroot00000000000000def f(x): return x**2-x def integrate_f(a, b, N): s = 0.0 dx = (b-a)/N for i in range(N): s += f(a+i*dx) return s * dx cython-0.20.1+git90-g0e6e38e/Demos/integrate1.pyx000066400000000000000000000002241231323242300211170ustar00rootroot00000000000000def f(x): return x**2-x def integrate_f(a, b, N): s = 0.0 dx = (b-a)/N for i in range(N): s += f(a+i*dx) return s * dx cython-0.20.1+git90-g0e6e38e/Demos/integrate2.pyx000066400000000000000000000003171231323242300211230ustar00rootroot00000000000000cdef double f(double x) except? -2: return x**2-x def integrate_f(double a, double b, int N): cdef int i s = 0.0 dx = (b-a)/N for i in range(N): s += f(a+i*dx) return s * dx cython-0.20.1+git90-g0e6e38e/Demos/integrate_timing.py000066400000000000000000000005621231323242300222220ustar00rootroot00000000000000import timeit import integrate0, integrate1, integrate2 number = 10 py_time = None for m in ('integrate0', 'integrate1', 'integrate2'): print m t = min(timeit.repeat("integrate_f(0.0, 10.0, 10000000)", "from %s import integrate_f" % m, number=number)) if py_time is None: py_time = t print " ", t / number, "s" print " ", py_time / t cython-0.20.1+git90-g0e6e38e/Demos/libraries/000077500000000000000000000000001231323242300202705ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Demos/libraries/call_mymath.pyx000066400000000000000000000001331231323242300233210ustar00rootroot00000000000000cdef extern from "mymath.h": double sinc(double) def call_sinc(x): return sinc(x) cython-0.20.1+git90-g0e6e38e/Demos/libraries/mymath.c000066400000000000000000000001171231323242300217320ustar00rootroot00000000000000#include "math.h" double sinc(double x) { return x == 0 ? 1 : sin(x)/x; } cython-0.20.1+git90-g0e6e38e/Demos/libraries/mymath.h000066400000000000000000000000251231323242300217350ustar00rootroot00000000000000double sinc(double); cython-0.20.1+git90-g0e6e38e/Demos/libraries/setup.py000066400000000000000000000016201231323242300220010ustar00rootroot00000000000000import os from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext # For demo purposes, we build our own tiny library. try: print "building libmymath.a" assert os.system("gcc -shared -fPIC -c mymath.c -o mymath.o") == 0 assert os.system("ar rcs libmymath.a mymath.o") == 0 except: if not os.path.exists("libmymath.a"): print "Error building external library, please create libmymath.a manually." sys.exit(1) # Here is how to use the library built above. ext_modules=[ Extension("call_mymath", sources = ["call_mymath.pyx"], include_dirs = [os.getcwd()], # path to .h file(s) library_dirs = [os.getcwd()], # path to .a or .so file(s) libraries = ['mymath']) ] setup( name = 'Demos', cmdclass = {'build_ext': build_ext}, ext_modules = ext_modules, ) cython-0.20.1+git90-g0e6e38e/Demos/numpy_demo.pyx000066400000000000000000000003061231323242300212310ustar00rootroot00000000000000cimport numpy import numpy def sum_of_squares(numpy.ndarray[double, ndim=1] arr): cdef long N = arr.shape[0] cdef double ss = 0 for i in range(N): ss += arr[i]**2 return ss cython-0.20.1+git90-g0e6e38e/Demos/overflow_perf.pyx000066400000000000000000000103511231323242300217350ustar00rootroot00000000000000# distutils: extra_compile_args = -O3 import cython ctypedef fused INT: int long long unsigned int unsigned long long object ctypedef fused C_INT: int long long unsigned int unsigned long long @cython.overflowcheck(False) def fib(INT n): """ >>> [fib(k) for k in range(10)] [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] """ cdef INT a, b, k a, b = 0, 1 for k in range(n): a, b = b, a + b return int(b) @cython.overflowcheck(True) def fib_overflow(INT n): """ >>> [fib_overflow(k) for k in range(10)] [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] """ cdef INT a, b, k a, b = 0, 1 for k in range(n): a, b = b, a + b return int(b) @cython.overflowcheck(False) def collatz(INT n): """ >>> collatz(1) 0 >>> collatz(5) 5 >>> collatz(10) 6 """ cdef INT k = 0 while n != 1: if n % 2 == 0: n /= 2 else: n = 3*n + 1 k += 1 return int(k) @cython.overflowcheck(True) @cython.overflowcheck.fold(False) def collatz_overflow(INT n): """ >>> collatz_overflow(1) 0 >>> collatz_overflow(5) 5 >>> collatz_overflow(10) 6 """ cdef INT k = 0 while n != 1: if n % 2 == 0: n /= 2 else: n = 3*n + 1 k += 1 return int(k) @cython.overflowcheck(True) @cython.overflowcheck.fold(True) def collatz_overflow_fold(INT n): """ >>> collatz_overflow_fold(1) 0 >>> collatz_overflow_fold(5) 5 >>> collatz_overflow_fold(10) 6 """ cdef INT k = 0 while n != 1: if n % 2 == 0: n /= 2 else: n = 3*n + 1 k += 1 return int(k) @cython.overflowcheck(False) def factorial(INT n): """ >>> factorial(2) 2 >>> factorial(5) 120 """ cdef INT k, res = 1 for k in range(2, n+1): res = res * k return int(res) @cython.overflowcheck(True) def factorial_overflow(INT n): """ >>> factorial_overflow(2) 2 >>> factorial_overflow(5) 120 """ cdef INT k, res = 1 for k in range(2, n+1): res = res * k return int(res) @cython.overflowcheck(False) def most_orthogonal(C_INT[:,::1] vectors): cdef C_INT n = vectors.shape[0] cdef C_INT* a cdef C_INT* b cdef double min_dot = 2 # actual max is 1 for i in range(n): for j in range(i): a = &vectors[i, 0] b = &vectors[j, 0] # A highly nested arithmetic expression... normalized_dot = (1.0 * (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]) / ((a[0]*a[0] + a[1]*a[1] + a[2]*a[2]) * (b[0]*b[0] + b[1]*b[1]+b[2]*b[2]))) if normalized_dot < min_dot: min_dot = normalized_dot min_pair = i, j return vectors[i], vectors[j] @cython.overflowcheck(True) @cython.overflowcheck.fold(False) def most_orthogonal_overflow(C_INT[:,::1] vectors): cdef C_INT n = vectors.shape[0] cdef C_INT* a cdef C_INT* b cdef double min_dot = 2 # actual max is 1 for i in range(n): for j in range(i): a = &vectors[i, 0] b = &vectors[j, 0] # A highly nested arithmetic expression... normalized_dot = ((a[0]*b[0] + a[1]*b[1] + a[2]*b[2]) / (1.0 * (a[0]*a[0] + a[1]*a[1] + a[2]*a[2]) * (b[0]*b[0] + b[1]*b[1]+b[2]*b[2]))) if normalized_dot < min_dot: min_dot = normalized_dot min_pair = i, j return vectors[i], vectors[j] @cython.overflowcheck(True) @cython.overflowcheck.fold(True) def most_orthogonal_overflow_fold(C_INT[:,::1] vectors): cdef C_INT n = vectors.shape[0] cdef C_INT* a cdef C_INT* b cdef double min_dot = 2 # actual max is 1 for i in range(n): for j in range(i): a = &vectors[i, 0] b = &vectors[j, 0] # A highly nested arithmetic expression... normalized_dot = ((a[0]*b[0] + a[1]*b[1] + a[2]*b[2]) / (1.0 * (a[0]*a[0] + a[1]*a[1] + a[2]*a[2]) * (b[0]*b[0] + b[1]*b[1]+b[2]*b[2]))) if normalized_dot < min_dot: min_dot = normalized_dot min_pair = i, j return vectors[i], vectors[j] cython-0.20.1+git90-g0e6e38e/Demos/overflow_perf_run.py000066400000000000000000000035551231323242300224410ustar00rootroot00000000000000from overflow_perf import * import sys import timeit try: import numpy as np except ImportError: np = None def run_tests(N): global f for func in most_orthogonal, fib, collatz, factorial: print func.__name__ for type in ['int', 'unsigned int', 'long long', 'unsigned long long', 'object']: if func == most_orthogonal: if type == 'object' or np == None: continue type_map = {'int': 'int32', 'unsigned int': 'uint32', 'long long': 'int64', 'unsigned long long': 'uint64'} shape = N, 3 arg = np.ndarray(shape, dtype=type_map[type]) arg[:] = 1000 * np.random.random(shape) else: arg = N try: print "%s[%s](%s)" % (func.__name__, type, N) with_overflow = my_timeit(globals()[func.__name__ + "_overflow"][type], arg) no_overflow = my_timeit(func[type], arg) print "\t%0.04e\t%0.04e\t%0.04f" % (no_overflow, with_overflow, with_overflow / no_overflow) if func.__name__ + "_overflow_fold" in globals(): with_overflow = my_timeit(globals()[func.__name__ + "_overflow_fold"][type], arg) print "\t%0.04e\t%0.04e\t%0.04f" % (no_overflow, with_overflow, with_overflow / no_overflow), "(folded)" except OverflowError: print " ", "Overflow" def my_timeit(func, N): global f, arg f = func arg = N for exponent in range(10, 30): times = 2 ** exponent res = min(timeit.repeat("f(arg)", setup="from __main__ import f, arg", repeat=5, number=times)) if res > .25: break return res / times params = sys.argv[1:] if not params: params = [129, 9, 97] for arg in params: print print "N", arg run_tests(int(arg)) cython-0.20.1+git90-g0e6e38e/Demos/primes.pyx000066400000000000000000000005761231323242300203650ustar00rootroot00000000000000print "starting" def primes(int kmax): # cdef int n, k, i cdef int p[1000] result = [] if kmax > 1000: kmax = 1000 k = 0 n = 2 while k < kmax: i = 0 while i < k and n % p[i] <> 0: i = i + 1 if i == k: p[k] = n k = k + 1 result.append(n) n = n + 1 return result cython-0.20.1+git90-g0e6e38e/Demos/pyprimes.py000066400000000000000000000003601231323242300205350ustar00rootroot00000000000000def primes(kmax): p = [] k = 0 n = 2 while k < kmax: i = 0 while i < k and n % p[i] != 0: i = i + 1 if i == k: p.append(n) k = k + 1 n = n + 1 return p cython-0.20.1+git90-g0e6e38e/Demos/run_numeric_demo.py000066400000000000000000000001761231323242300222240ustar00rootroot00000000000000import Numeric import numeric_demo a = Numeric.array([[1.0, 3.5, 8.4], [2.3, 6.6, 4.1]], "f") numeric_demo.print_2d_array(a) cython-0.20.1+git90-g0e6e38e/Demos/run_primes.py000066400000000000000000000001701231323242300210470ustar00rootroot00000000000000import sys from primes import primes if len(sys.argv) >= 2: n = int(sys.argv[1]) else: n = 1000 print primes(n) cython-0.20.1+git90-g0e6e38e/Demos/run_spam.py000066400000000000000000000001761231323242300205160ustar00rootroot00000000000000from spam import Spam s = Spam() print "Created:", s s.set_amount(42) print "Amount =", s.get_amount() s.describe() s = None cython-0.20.1+git90-g0e6e38e/Demos/setup.py000066400000000000000000000012241231323242300200250ustar00rootroot00000000000000# Run as: # python setup.py build_ext --inplace import sys sys.path.insert(0, "..") from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize ext_modules = cythonize("**/*.pyx", exclude="numpy_*.pyx") # Only compile the following if numpy is installed. try: from numpy.distutils.misc_util import get_numpy_include_dirs numpy_demo = [Extension("*", ["numpy_*.pyx"], include_dirs=get_numpy_include_dirs())] ext_modules.extend(cythonize(numpy_demo)) except ImportError: pass setup( name = 'Demos', ext_modules = ext_modules, ) cython-0.20.1+git90-g0e6e38e/Demos/spam.pyx000066400000000000000000000005701231323242300200200ustar00rootroot00000000000000# # Example of an extension type. # cdef class Spam: cdef public int amount def __cinit__(self): self.amount = 0 def __dealloc__(self): print self.amount, "tons of spam is history." def get_amount(self): return self.amount def set_amount(self, new_amount): self.amount = new_amount def describe(self): print self.amount, "tons of spam!" cython-0.20.1+git90-g0e6e38e/Doc/000077500000000000000000000000001231323242300157525ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Doc/About.html000066400000000000000000000211761231323242300177210ustar00rootroot00000000000000 About Cython


Cython

A language for writing Python extension modules

What is Cython all about?

Cython is a language specially designed for writing Python extension modules. It's designed to bridge the gap between the nice, high-level, easy-to-use world of Python and the messy, low-level world of C.

You may be wondering why anyone would want a special language for this. Python is really easy to extend using C or C++, isn't it? Why not just write your extension modules in one of those languages?

Well, if you've ever written an extension module for Python, you'll know that things are not as easy as all that. First of all, there is a fair bit of boilerplate code to write before you can even get off the ground. Then you're faced with the problem of converting between Python and C data types. For the basic types such as numbers and strings this is not too bad, but anything more elaborate and you're into picking Python objects apart using the Python/C API calls, which requires you to be meticulous about maintaining reference counts, checking for errors at every step and cleaning up properly if anything goes wrong. Any mistakes and you have a nasty crash that's very difficult to debug.

Various tools have been developed to ease some of the burdens of producing extension code, of which perhaps SWIG is the best known. SWIG takes a definition file consisting of a mixture of C code and specialised declarations, and produces an extension module. It writes all the boilerplate for you, and in many cases you can use it without knowing about the Python/C API. But you need to use API calls if any substantial restructuring of the data is required between Python and C.

What's more, SWIG gives you no help at all if you want to create a new built-in Python type. It will generate pure-Python classes which wrap (in a slightly unsafe manner) pointers to C data structures, but creation of true extension types is outside its scope.

Another notable attempt at making it easier to extend Python is PyInline , inspired by a similar facility for Perl. PyInline lets you embed pieces of C code in the midst of a Python file, and automatically extracts them and compiles them into an extension. But it only converts the basic types automatically, and as with SWIG,  it doesn't address the creation of new Python types.

Cython aims to go far beyond what any of these previous tools provides. Cython deals with the basic types just as easily as SWIG, but it also lets you write code to convert between arbitrary Python data structures and arbitrary C data structures, in a simple and natural way, without knowing anything about the Python/C API. That's right -- nothing at all! Nor do you have to worry about reference counting or error checking -- it's all taken care of automatically, behind the scenes, just as it is in interpreted Python code. And what's more, Cython lets you define new built-in Python types just as easily as you can define new classes in Python.

Sound too good to be true? Read on and find out how it's done.

The Basics of Cython

The fundamental nature of Cython can be summed up as follows: Cython is Python with C data types.

Cython is Python: Almost any piece of Python code is also valid Cython code. (There are a few limitations, but this approximation will serve for now.) The Cython compiler will convert it into C code which makes equivalent calls to the Python/C API. In this respect, Cython is similar to the former Python2C project (to which I would supply a reference except that it no longer seems to exist).

...with C data types. But Cython is much more than that, because parameters and variables can be declared to have C data types. Code which manipulates Python values and C values can be freely intermixed, with conversions occurring automatically wherever possible. Reference count maintenance and error checking of Python operations is also automatic, and the full power of Python's exception handling facilities, including the try-except and try-finally statements, is available to you -- even in the midst of manipulating C data.

Here's a small example showing some of what can be done. It's a routine for finding prime numbers. You tell it how many primes you want, and it returns them as a Python list.

primes.pyx
 1  def primes(int kmax):
 2      cdef int n, k, i
 3      cdef int p[1000]
 4      result = []
 5      if kmax > 1000:
 6          kmax = 1000
 7      k = 0
 8      n = 2
 9      while k < kmax:
10          i = 0
11          while i < k and n % p[i] <> 0:
12              i = i + 1
13          if i == k:
14             p[k] = n
15             k = k + 1
16             result.append(n)
17          n = n + 1
18      return result
You'll see that it starts out just like a normal Python function definition, except that the parameter kmax is declared to be of type int . This means that the object passed will be converted to a C integer (or a TypeError will be raised if it can't be).

Lines 2 and 3 use the cdef statement to define some local C variables. Line 4 creates a Python list which will be used to return the result. You'll notice that this is done exactly the same way it would be in Python. Because the variable result hasn't been given a type, it is assumed to hold a Python object.

Lines 7-9 set up for a loop which will test candidate numbers for primeness until the required number of primes has been found. Lines 11-12, which try dividing a candidate by all the primes found so far, are of particular interest. Because no Python objects are referred to, the loop is translated entirely into C code, and thus runs very fast.

When a prime is found, lines 14-15 add it to the p array for fast access by the testing loop, and line 16 adds it to the result list. Again, you'll notice that line 16 looks very much like a Python statement, and in fact it is, with the twist that the C parameter n is automatically converted to a Python object before being passed to the append method. Finally, at line 18, a normal Python return statement returns the result list.

Compiling primes.pyx with the Cython compiler produces an extension module which we can try out in the interactive interpreter as follows:

>>> import primes
>>> primes.primes(10)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
>>>
See, it works! And if you're curious about how much work Cython has saved you, take a look at the C code generated for this module .

Language Details

For more about the Cython language, see the Language Overview .

Future Plans

Cython is not finished. Substantial tasks remaining include:
  • Support for certain Python language features which are planned but not yet implemented. See the Limitations section of the Language Overview for a current list.
  • C++ support. This could be a very big can of worms - careful thought required before going there.
  • Reading C/C++ header files directly would be very nice, but there are some severe problems that I will have to find solutions for first, such as what to do about preprocessor macros. My current thinking is to use a separate tool to convert .h files into Cython declarations, possibly with some manual intervention.
cython-0.20.1+git90-g0e6e38e/Doc/FAQ.html000066400000000000000000000107421231323242300172530ustar00rootroot00000000000000 FAQ.html


Cython FAQ

Contents


How do I call Python/C API routines?

Declare them as C functions inside a cdef extern from block. Use the type name object for any parameters and return types which are Python object references. Don't use the word const anywhere. Here is an example which defines and uses the PyString_FromStringAndSize routine:
cdef extern from "Python.h":
    object PyString_FromStringAndSize(char *, int)

cdef char buf[42]
my_string = PyString_FromStringAndSize(buf, 42)

How do I convert a C string containing null bytes to a Python string?

Put in a declaration for the PyString_FromStringAndSize API routine and use that. See How do I call Python/C API routines?

How do I access the data inside a Numeric array object?

Use a cdef extern from block to include the Numeric header file and declare the array object as an external extension type. The following code illustrates how to do this:
cdef extern from "Numeric/arrayobject.h":

    struct PyArray_Descr:
        int type_num, elsize
        char type

    ctypedef class Numeric.ArrayType [object PyArrayObject]:
        cdef char *data
        cdef int nd
        cdef int *dimensions, *strides
        cdef object base
        cdef PyArray_Descr *descr
        cdef int flags

For more information about external extension types, see the "External Extension Types" section of the "Extension Types" documentation page.

Cython says my extension type object has no attribute 'rhubarb', but I know it does. What gives?

You're probably trying to access it through a reference which Cython thinks is a generic Python object. You need to tell Cython that it's a reference to your extension type by means of a declaration,
for example,
cdef class Vegetables:
    cdef int rhubarb

...
cdef Vegetables veg
veg.rhubarb = 42
Also see the "Attributes" section of the "Extension Types" documentation page.

Python says my extension type has no method called 'quack', but I know it does. What gives?

You may have declared the method using cdef instead of def. Only functions and methods declared with def are callable from Python code.
--- cython-0.20.1+git90-g0e6e38e/Doc/extension_types.html000066400000000000000000000600121231323242300220770ustar00rootroot00000000000000 Extension Types


Extension Types

Contents

Introduction

As well as creating normal user-defined classes with the Python class statement, Cython also lets you create new built-in Python types, known as extension types. You define an extension type using the cdef class statement. Here's an example:
cdef class Shrubbery:

    cdef int width, height

    def __init__(self, w, h):
        self.width = w
        self.height = h

    def describe(self):
        print "This shrubbery is", self.width, \
            "by", self.height, "cubits."

As you can see, a Cython extension type definition looks a lot like a Python class definition. Within it, you use the def statement to define methods that can be called from Python code. You can even define many of the special methods such as __init__ as you would in Python.

The main difference is that you can use the cdef statement to define attributes. The attributes may be Python objects (either generic or of a particular extension type), or they may be of any C data type. So you can use extension types to wrap arbitrary C data structures and provide a Python-like interface to them.

Attributes

Attributes of an extension type are stored directly in the object's C struct. The set of attributes is fixed at compile time; you can't add attributes to an extension type instance at run time simply by assigning to them, as you could with a Python class instance. (You can subclass the extension type in Python and add attributes to instances of the subclass, however.)

There are two ways that attributes of an extension type can be accessed: by Python attribute lookup, or by direct access to the C struct from Cython code. Python code is only able to access attributes of an extension type by the first method, but Cython code can use either method.

By default, extension type attributes are only accessible by direct access, not Python access, which means that they are not accessible from Python code. To make them accessible from Python code, you need to declare them as public or readonly. For example,

cdef class Shrubbery:
    cdef public int width, height
    cdef readonly float depth
makes the width and height attributes readable and writable from Python code, and the depth attribute readable but not writable.

Note that you can only expose simple C types, such as ints, floats and strings, for Python access. You can also expose Python-valued attributes, although read-write exposure is only possible for generic Python attributes (of type object). If the attribute is declared to be of an extension type, it must be exposed readonly.

Note also that the public and readonly options apply only to Python access, not direct access. All the attributes of an extension type are always readable and writable by direct access.

Howerver, for direct access to be possible, the Cython compiler must know that you have an instance of that type, and not just a generic Python object. It knows this already in the case of the "self" parameter of the methods of that type, but in other cases you will have to tell it by means of a declaration. For example,

cdef widen_shrubbery(Shrubbery sh, extra_width):
    sh.width = sh.width + extra_width
If you attempt to access an extension type attribute through a generic object reference, Cython will use a Python attribute lookup. If the attribute is exposed for Python access (using public or readonly) then this will work, but it will be much slower than direct access.

Extension types and None

When you declare a parameter or C variable as being of an extension type, Cython will allow it to take on the value None as well as values of its declared type. This is analogous to the way a C pointer can take on the value NULL, and you need to exercise the same caution because of it. There is no problem as long as you are performing Python operations on it, because full dynamic type checking will be applied. However, when you access C attributes of an extension type (as in the widen_shrubbery function above), it's up to you to make sure the reference you're using is not None -- in the interests of efficiency, Cython does not check this.

You need to be particularly careful when exposing Python functions which take extension types as arguments. If we wanted to make widen_shrubbery a Python function, for example, if we simply wrote

def widen_shrubbery(Shrubbery sh, extra_width): # This is
    sh.width = sh.width + extra_width           # dangerous!
then users of our module could crash it by passing None for the sh parameter.

One way to fix this would be

def widen_shrubbery(Shrubbery sh, extra_width):
    if sh is None:
        raise TypeError
    sh.width = sh.width + extra_width
but since this is anticipated to be such a frequent requirement, Cython provides a more convenient way. Parameters of a Python function declared as an extension type can have a not None clause:
def widen_shrubbery(Shrubbery sh not None, extra_width):
    sh.width = sh.width + extra_width
Now the function will automatically check that sh is not None along with checking that it has the right type.

Note, however that the not None clause can only be used in Python functions (defined with def) and not C functions (defined with cdef). If you need to check whether a parameter to a C function is None, you will need to do it yourself.

Some more things to note:

  • The self parameter of a method of an extension type is guaranteed never to be None.
  • When comparing a value with None, keep in mind that, if x is a Python object, x is None and x is not None are very efficient because they translate directly to C pointer comparisons, whereas x == None and x != None, or simply using x as a boolean value (as in if x: ...) will invoke Python operations and therefore be much slower.

Special methods

Although the principles are similar, there are substantial differences between many of the __xxx__ special methods of extension types and their Python counterparts. There is a separate page devoted to this subject, and you should read it carefully before attempting to use any special methods in your extension types.

Properties

There is a special syntax for defining properties in an extension class:
cdef class Spam:

    property cheese:

        "A doc string can go here."

        def __get__(self):
            # This is called when the property is read.
            ...

        def __set__(self, value):
            # This is called when the property is written.
            ...

        def __del__(self):
            # This is called when the property is deleted.
 

The __get__, __set__ and __del__ methods are all optional; if they are omitted, an exception will be raised when the corresponding operation is attempted.

Here's a complete example. It defines a property which adds to a list each time it is written to, returns the list when it is read, and empties the list when it is deleted.
 

cheesy.pyx Test input
cdef class CheeseShop:

  cdef object cheeses

  def __new__(self):
    self.cheeses = []

  property cheese:

    def __get__(self):
      return "We don't have: %s" % self.cheeses

    def __set__(self, value):
      self.cheeses.append(value)

    def __del__(self):
      del self.cheeses[:]

from cheesy import CheeseShop

shop = CheeseShop()
print shop.cheese

shop.cheese = "camembert"
print shop.cheese

shop.cheese = "cheddar"
print shop.cheese

del shop.cheese
print shop.cheese

Test output
We don't have: []
We don't have: ['camembert']
We don't have: ['camembert', 'cheddar']
We don't have: []

Subclassing

An extension type may inherit from a built-in type or another extension type:
cdef class Parrot:
    ...

cdef class Norwegian(Parrot):
    ...


A complete definition of the base type must be available to Cython, so if the base type is a built-in type, it must have been previously declared as an extern extension type. If the base type is defined in another Cython module, it must either be declared as an extern extension type or imported using the cimport statement.

An extension type can only have one base class (no multiple inheritance).

Cython extension types can also be subclassed in Python. A Python class can inherit from multiple extension types provided that the usual Python rules for multiple inheritance are followed (i.e. the C layouts of all the base classes must be compatible).

C methods

Extension types can have C methods as well as Python methods. Like C functions, C methods are declared using cdef instead of def. C methods are "virtual", and may be overridden in derived extension types.

pets.pyx
Output
cdef class Parrot:

  cdef void describe(self):
    print "This parrot is resting."

cdef class Norwegian(Parrot):

  cdef void describe(self):
    Parrot.describe(self)
    print "Lovely plumage!"


cdef Parrot p1, p2
p1 = Parrot()
p2 = Norwegian()
print "p1:"
p1.describe()
print "p2:"
p2.describe()

p1:
This parrot is resting.
p2:
This parrot is resting.
Lovely plumage!

The above example also illustrates that a C method can call an inherited C method using the usual Python technique, i.e.
Parrot.describe(self)

Forward-declaring extension types

Extension types can be forward-declared, like struct and union types. This will be necessary if you have two extension types that need to refer to each other, e.g.
cdef class Shrubbery # forward declaration

cdef class Shrubber:
    cdef Shrubbery work_in_progress

cdef class Shrubbery:
    cdef Shrubber creator

If you are forward-declaring an exension type that has a base class, you must specify the base class in both the forward declaration and its subsequent definition, for example,
cdef class A(B)

...

cdef class A(B):
    # attributes and methods

Making extension types weak-referenceable

By default, extension types do not support having weak references made to them. You can enable weak referencing by declaring a C attribute of type object called __weakref__. For example,

cdef class ExplodingAnimal:
    """This animal will self-destruct when it is
       no longer strongly referenced."""
   
    cdef object __weakref__

Public and external extension types

Extension types can be declared extern or public. An extern extension type declaration makes an extension type defined in external C code available to a Cython module. A public extension type declaration makes an extension type defined in a Cython module available to external C code.

External extension types

An extern extension type allows you to gain access to the internals of Python objects defined in the Python core or in a non-Cython extension module.
NOTE: In Cython versions before 0.8, extern extension types were also used to reference extension types defined in another Cython module. While you can still do that, Cython 0.8 and later provides a better mechanism for this. See Sharing C Declarations Between Cython Modules.
Here is an example which will let you get at the C-level members of the built-in complex object.
cdef extern from "complexobject.h":

    struct Py_complex:
        double real
        double imag

    ctypedef class __builtin__.complex [object PyComplexObject]:
        cdef Py_complex cval

# A function which uses the above type
def spam(complex c):
    print "Real:", c.cval.real
    print "Imag:", c.cval.imag

Some important things to note are:
  1. In this example, ctypedef class has been used. This is because, in the Python header files, the PyComplexObject struct is declared with

    ctypedef struct {
        ...
    } PyComplexObject;

  2. As well as the name of the extension type, the module in which its type object can be found is also specified. See the implicit importing section below. 

  3. When declaring an external extension type, you don't declare any methods. Declaration of methods is not required in order to call them, because the calls are Python method calls. Also, as with structs and unions, if your extension class declaration is inside a cdef extern from block, you only need to declare those C members which you wish to access.

Implicit importing

Backwards Incompatibility Note: You will have to update any pre-0.8 Cython modules you have which use extern extension types. I apologise for this, but for complicated reasons it proved to be too difficult to continue supporting the old way of doing these while introducing the new features that I wanted.
Cython 0.8 and later requires you to include a module name in an extern extension class declaration, for example,
cdef extern class MyModule.Spam:
    ...
The type object will be implicitly imported from the specified module and bound to the corresponding name in this module. In other words, in this example an implicit
    from MyModule import Spam
statement will be executed at module load time.

The module name can be a dotted name to refer to a module inside a package hierarchy, for example,

cdef extern class My.Nested.Package.Spam:
    ...
You can also specify an alternative name under which to import the type using an as clause, for example,
    cdef extern class My.Nested.Package.Spam as Yummy:
       ...
which corresponds to the implicit import statement
    from My.Nested.Package import Spam as Yummy

Type names vs. constructor names

Inside a Cython module, the name of an extension type serves two distinct purposes. When used in an expression, it refers to a module-level global variable holding the type's constructor (i.e. its type-object). However, it can also be used as a C type name to declare variables, arguments and return values of that type.

When you declare

cdef extern class MyModule.Spam:
    ...
the name Spam serves both these roles. There may be other names by which you can refer to the constructor, but only Spam can be used as a type name. For example, if you were to explicity import MyModule, you could use MyModule.Spam() to create a Spam instance, but you wouldn't be able to use MyModule.Spam as a type name.

When an as clause is used, the name specified in the as clause also takes over both roles. So if you declare

cdef extern class MyModule.Spam as Yummy:
    ...
then Yummy becomes both the type name and a name for the constructor. Again, there are other ways that you could get hold of the constructor, but only Yummy is usable as a type name.

Public extension types

An extension type can be declared public, in which case a .h file is generated containing declarations for its object struct and type object. By including the .h file in external C code that you write, that code can access the attributes of the extension type.

Name specification clause

The part of the class declaration in square brackets is a special feature only available for extern or public extension types. The full form of this clause is
[object object_struct_name, type type_object_name ]
where object_struct_name is the name to assume for the type's C struct, and type_object_name is the name to assume for the type's statically declared type object. (The object and type clauses can be written in either order.)

If the extension type declaration is inside a cdef extern from block, the object clause is required, because Cython must be able to generate code that is compatible with the declarations in the header file. Otherwise, for extern extension types, the object clause is optional.

For public extension types, the object and type clauses are both required, because Cython must be able to generate code that is compatible with external C code.



Back to the Language Overview
 

cython-0.20.1+git90-g0e6e38e/Doc/index.html000066400000000000000000000056761231323242300177650ustar00rootroot00000000000000 Cython - Front Page  
Cython A smooth blend of the finest Python 
with the unsurpassed power 
of raw C.
Welcome to Cython, a language for writing Python extension modules. Cython makes creating an extension module is almost as easy as creating a Python module! To find out more, consult one of the edifying documents below.

Documentation

About Cython

Read this to find out what Cython is all about and what it can do for you.

Language Overview

A description of all the features of the Cython language. This is the closest thing to a reference manual in existence yet.

FAQ

Want to know how to do something in Cython? Check here first.

Other Resources

Michael's Quick Guide to Cython

This tutorial-style presentation will take you through the steps of creating some Cython modules to wrap existing C libraries. Contributed by Michael JasonSmith.

Mail to the Author

If you have a question that's not answered by anything here, you're not sure about something, or you have a bug to report or a suggestion to make, or anything at all to say about Cython, feel free to email me: greg@cosc.canterbury.ac.nz
cython-0.20.1+git90-g0e6e38e/Doc/overview.html000066400000000000000000001213371231323242300205150ustar00rootroot00000000000000 Cython Language Overview


Overview of the Cython Language 

This document informally describes the extensions to the Python language made by Cython. Some day there will be a reference manual covering everything in more detail.
 

Contents


Basics

This section describes the basic features of the Cython language. The facilities covered in this section allow you to create Python-callable functions that manipulate C data structures and convert between Python and C data types. Later sections will cover facilities for wrapping external C code, creating new Python types and cooperation between Cython modules.

Python functions vs. C functions

There are two kinds of function definition in Cython:

Python functions are defined using the def statement, as in Python. They take Python objects as parameters and return Python objects.

C functions are defined using the new cdef statement. They take either Python objects or C values as parameters, and can return either Python objects or C values.

Within a Cython module, Python functions and C functions can call each other freely, but only Python functions can be called from outside the module by interpreted Python code. So, any functions that you want to "export" from your Cython module must be declared as Python functions using def.

Parameters of either type of function can be declared to have C data types, using normal C declaration syntax. For example,

def spam(int i, char *s):
    ...
cdef int eggs(unsigned long l, float f):
    ...
When a parameter of a Python function is declared to have a C data type, it is passed in as a Python object and automatically converted to a C value, if possible. Automatic conversion is currently only possible for numeric types and string types; attempting to use any other type for the parameter of a Python function will result in a compile-time error.

C functions, on the other hand, can have parameters of any type, since they're passed in directly using a normal C function call.

Python objects as parameters and return values

If no type is specified for a parameter or return value, it is assumed to be a Python object. (Note that this is different from the C convention, where it would default to int.) For example, the following defines a C function that takes two Python objects as parameters and returns a Python object:
cdef spamobjs(x, y):
    ...
Reference counting for these objects is performed automatically according to the standard Python/C API rules (i.e. borrowed references are taken as parameters and a new reference is returned).

The name object can also be used to explicitly declare something as a Python object. This can be useful if the name being declared would otherwise be taken as the name of a type, for example,

cdef ftang(object int):
    ...
declares a parameter called int which is a Python object. You can also use object as the explicit return type of a function, e.g.
cdef object ftang(object int):
    ...
In the interests of clarity, it is probably a good idea to always be explicit about object parameters in C functions.

C variable and type definitions

The cdef statement is also used to declare C variables, either local or module-level:
cdef int i, j, k
cdef float f, g[42], *h
and C struct, union or enum types:
cdef struct Grail:
    int age
    float volume
cdef union Food:
    char *spam
    float *eggs
cdef enum CheeseType:
    cheddar, edam, 
    camembert
cdef enum CheeseState:
    hard = 1
    soft = 2
    runny = 3
There is currently no special syntax for defining a constant, but you can use an anonymous enum declaration for this purpose, for example,
cdef enum:
    tons_of_spam = 3
Note that the words struct, union and enum are used only when defining a type, not when referring to it. For example, to declare a variable pointing to a Grail you would write
cdef Grail *gp
and not
cdef struct Grail *gp # WRONG
There is also a ctypedef statement for giving names to types, e.g.
ctypedef unsigned long ULong
ctypedef int *IntPtr

Automatic type conversions

In most situations, automatic conversions will be performed for the basic numeric and string types when a Python object is used in a context requiring a C value, or vice versa. The following table summarises the conversion possibilities.

C types
From Python types
To Python types
[unsigned] char
[unsigned] short
int, long
int, long
int
unsigned int
unsigned long
[unsigned] long long
int, long

long

float, double, long double
int, long, float
float
char *
str
str

Caveats when using a Python string in a C context

You need to be careful when using a Python string in a context expecting a char *. In this situation, a pointer to the contents of the Python string is used, which is only valid as long as the Python string exists. So you need to make sure that a reference to the original Python string is held for as long as the C string is needed. If you can't guarantee that the Python string will live long enough, you will need to copy the C string.

Cython detects and prevents some mistakes of this kind. For instance, if you attempt something like
cdef char *s
s = pystring1 + pystring2
then Cython will produce the error message "Obtaining char * from temporary Python value". The reason is that concatenating the two Python strings produces a new Python string object that is referenced only by a temporary internal variable that Cython generates. As soon as the statement has finished, the temporary variable will be decrefed and the Python string deallocated, leaving s dangling. Since this code could not possibly work, Cython refuses to compile it.

The solution is to assign the result of the concatenation to a Python variable, and then obtain the char * from that, i.e.
cdef char *s
p = pystring1 + pystring2
s = p
It is then your responsibility to hold the reference p for as long as necessary.

Keep in mind that the rules used to detect such errors are only heuristics. Sometimes Cython will complain unnecessarily, and sometimes it will fail to detect a problem that exists. Ultimately, you need to understand the issue and be careful what you do.

Scope rules

Cython determines whether a variable belongs to a local scope, the module scope, or the built-in scope completely statically. As with Python, assigning to a variable which is not otherwise declared implicitly declares it to be a Python variable residing in the scope where it is assigned. Unlike Python, however, a name which is referred to but not declared or assigned is assumed to reside in the builtin scope, not the module scope. Names added to the module dictionary at run time will not shadow such names.

You can use a global statement at the module level to explicitly declare a name to be a module-level name when there would otherwise not be any indication of this, for example,

global __name__
print __name__
Without the global statement, the above would print the name of the builtins module.

Note: A consequence of these rules is that the module-level scope behaves the same way as a Python local scope if you refer to a variable before assigning to it. In particular, tricks such as the following will not work in Cython:
try:
  x = True
except NameError:
  True = 1
because, due to the assignment, the True will always be looked up in the module-level scope. You would have to do something like this instead:
import __builtin__
try:
True = __builtin__.True
except AttributeError:
True = 1

Statements and expressions

Control structures and expressions follow Python syntax for the most part. When applied to Python objects, they have the same semantics as in Python (unless otherwise noted). Most of the Python operators can also be applied to C values, with the obvious semantics.

If Python objects and C values are mixed in an expression, conversions are performed automatically between Python objects and C numeric or string types.

Reference counts are maintained automatically for all Python objects, and all Python operations are automatically checked for errors, with appropriate action taken.

Differences between C and Cython expressions

There are some differences in syntax and semantics between C expressions and Cython expressions, particularly in the area of C constructs which have no direct equivalent in Python.
  • An integer literal without an L suffix is treated as a C constant, and will be truncated to whatever size your C compiler thinks appropriate. With an L suffix, it will be converted to Python long integer (even if it would be small enough to fit into a C int).

  • There is no -> operator in Cython. Instead of p->x, use p.x
  •  
  • There is no * operator in Cython. Instead of *p, use p[0]
  •  
  • There is an & operator, with the same semantics as in C.
  •  
  • The null C pointer is called NULL, not 0 (and NULL is a reserved word).
  •  
  • Character literals are written with a c prefix, for example:
    • c'X'
  • Type casts are written <type>value , for example:
    • cdef char *p, float *q
      p = <char*>q
    Warning: Don't attempt to use a typecast to convert between Python and C data types -- it won't do the right thing. Leave Cython to perform the conversion automatically.

Integer for-loops

You should be aware that a for-loop such as
for i in range(n):
    ...
won't be very fast, even if i and n are declared as C integers, because range is a Python function. For iterating over ranges of integers, Cython has another form of for-loop:
for i from 0 <= i < n:
    ...
If the loop variable and the lower and upper bounds are all C integers, this form of loop will be much faster, because Cython will translate it into pure C code.

Some things to note about the for-from loop:

  • The target expression must be a variable name.
  • The name between the lower and upper bounds must be the same as the target name.
  • The direction of iteration is determined by the relations. If they are both from the set {<, <=} then it is upwards; if they are both from the set {>, >=} then it is downwards. (Any other combination is disallowed.)
Like other Python looping statements, break and continue may be used in the body, and the loop may have an else clause.


Error return values

If you don't do anything special, a function declared with cdef that does not return a Python object has no way of reporting Python exceptions to its caller. If an exception is detected in such a function, a warning message is printed and the exception is ignored.

If you want a C function that does not return a Python object to be able to propagate exceptions to its caller, you need to declare an exception value for it. Here is an example:

cdef int spam() except -1:
    ...
With this declaration, whenever an exception occurs inside spam, it will immediately return with the value -1. Furthermore, whenever a call to spam returns -1, an exception will be assumed to have occurred and will be propagated.

When you declare an exception value for a function, you should never explicitly return that value. If all possible return values are legal and you can't reserve one entirely for signalling errors, you can use an alternative form of exception value declaration:

cdef int spam() except? -1:
    ...
The "?" indicates that the value -1 only indicates a possible error. In this case, Cython generates a call to PyErr_Occurredif the exception value is returned, to make sure it really is an error.

There is also a third form of exception value declaration:

cdef int spam() except *:
    ...
This form causes Cython to generate a call to PyErr_Occurred after every call to spam, regardless of what value it returns. If you have a function returning void that needs to propagate errors, you will have to use this form, since there isn't any return value to test.

Some things to note:

  • Currently, exception values can only declared for functions returning an integer, float or pointer type, and the value must be a literal, not an expression (although it can be negative). The only possible pointer exception value is NULL. Void functions can only use the except * form.

  •  
  • The exception value specification is part of the signature of the function. If you're passing a pointer to a function as a parameter or assigning it to a variable, the declared type of the parameter or variable must have the same exception value specification (or lack thereof). Here is an example of a pointer-to-function declaration with an exception value:
    • int (*grail)(int, char *) except -1
  • You don't need to (and shouldn't) declare exception values for functions which return Python objects. Remember that a function with no declared return type implicitly returns a Python object.

Checking return values of non-Cython functions

It's important to understand that the except clause does not cause an error to be raised when the specified value is returned. For example, you can't write something like
cdef extern FILE *fopen(char *filename, char *mode) except NULL # WRONG!
and expect an exception to be automatically raised if a call to fopen returns NULL. The except clause doesn't work that way; its only purpose is for propagating exceptions that have already been raised, either by a Cython function or a C function that calls Python/C API routines. To get an exception from a non-Python-aware function such as fopen, you will have to check the return value and raise it yourself, for example,
cdef FILE *p
p = fopen("spam.txt", "r")
if p == NULL:
    raise SpamError("Couldn't open the spam file")


The include statement

For convenience, a large Cython module can be split up into a number of files which are put together using the include statement, for example
include "spamstuff.pxi"
The contents of the named file are textually included at that point. The included file can contain any complete top-level Cython statements, including other include statements. The include statement itself can only appear at the top level of a file.

The include statement can also be used in conjunction with public declarations to make C functions and variables defined in one Cython module accessible to another. However, note that some of these uses have been superseded by the facilities described in Sharing Declarations Between Cython Modules, and it is expected that use of the include statement for this purpose will be phased out altogether in future versions.


Interfacing with External C Code

One of the main uses of Cython is wrapping existing libraries of C code. This is achieved by using external declarations to declare the C functions and variables from the library that you want to use.

You can also use public declarations to make C functions and variables defined in a Cython module available to external C code. The need for this is expected to be less frequent, but you might want to do it, for example, if you are embedding Python in another application as a scripting language. Just as a Cython module can be used as a bridge to allow Python code to call C code, it can also be used to allow C code to call Python code.

External declarations

By default, C functions and variables declared at the module level are local to the module (i.e. they have the C static storage class). They can also be declared extern to specify that they are defined elsewhere, for example:
cdef extern int spam_counter
cdef extern void order_spam(int tons)

Referencing C header files

When you use an extern definition on its own as in the examples above, Cython includes a declaration for it in the generated C file. This can cause problems if the declaration doesn't exactly match the declaration that will be seen by other C code. If you're wrapping an existing C library, for example, it's important that the generated C code is compiled with exactly the same declarations as the rest of the library.

To achieve this, you can tell Cython that the declarations are to be found in a C header file, like this:

cdef extern from "spam.h":
    int spam_counter
    void order_spam(int tons)
The cdef extern from clause does three things:
  1. It directs Cython to place a #include statement for the named header file in the generated C code.
  2.  
  3. It prevents Cython from generating any C code for the declarations found in the associated block.
  4.  
  5. It treats all declarations within the block as though they started with cdef extern.
It's important to understand that Cython does not itself read the C header file, so you still need to provide Cython versions of any declarations from it that you use. However, the Cython declarations don't always have to exactly match the C ones, and in some cases they shouldn't or can't. In particular:
  1. Don't use const. Cython doesn't know anything about const, so just leave it out. Most of the time this shouldn't cause any problem, although on rare occasions you might have to use a cast. 1
  2.  
  3. Leave out any platform-specific extensions to C declarations such as __declspec().
  4.  
  5. If the header file declares a big struct and you only want to use a few members, you only need to declare the members you're interested in. Leaving the rest out doesn't do any harm, because the C compiler will use the full definition from the header file.

    In some cases, you might not need any of the struct's members, in which case you can just put pass in the body of the struct declaration, e.g.

        cdef extern from "foo.h":
            struct spam:
                pass


    Note that you can only do this inside a cdef extern from block; struct declarations anywhere else must be non-empty.

  6. If the header file uses typedef names such as size_t to refer to platform-dependent flavours of numeric types, you will need a corresponding ctypedef statement, but you don't need to match the type exactly, just use something of the right general kind (int, float, etc). For example,
    1. ctypedef int size_t
    will work okay whatever the actual size of a size_t is (provided the header file defines it correctly).
     
  7. If the header file uses macros to define constants, translate them into a dummy enum declaration.
  8.  
  9. If the header file defines a function using a macro, declare it as though it were an ordinary function, with appropriate argument and result types.
A few more tricks and tips:
  • If you want to include a C header because it's needed by another header, but don't want to use any declarations from it, put pass in the extern-from block:
      cdef extern from "spam.h":
          pass
  • If you want to include some external declarations, but don't want to specify a header file (because it's included by some other header that you've already included) you can put * in place of the header file name:
cdef extern from *:
    ...

Styles of struct, union and enum declaration

There are two main ways that structs, unions and enums can be declared in C header files: using a tag name, or using a typedef. There are also some variations based on various combinations of these.

It's important to make the Cython declarations match the style used in the header file, so that Cython can emit the right sort of references to the type in the code it generates. To make this possible, Cython provides two different syntaxes for declaring a struct, union or enum type. The style introduced above corresponds to the use of a tag name. To get the other style, you prefix the declaration with ctypedef, as illustrated below.

The following table shows the various possible styles that can be found in a header file, and the corresponding Cython declaration that you should put in the cdef exern from block. Struct declarations are used as an example; the same applies equally to union and enum declarations.

Note that in all the cases below, you refer to the type in Cython code simply as Foo, not struct Foo.
 
  C code Possibilities for corresponding Cython code Comments
1 struct Foo {
  ...
};
cdef struct Foo:
  ...
Cython will refer to the type as struct Foo in the generated C code.
2 typedef struct {
  ...
} Foo;
ctypedef struct Foo:
  ...
Cython will refer to the type simply as Foo in the generated C code.
3 typedef struct foo {
  ...
} Foo;
cdef struct foo:
  ...
ctypedef foo Foo #optional
If the C header uses both a tag and a typedef with different names, you can use either form of declaration in Cython (although if you need to forward reference the type, you'll have to use the first form).
ctypedef struct Foo:
  ...
4 typedef struct Foo {
  ...
} Foo;
cdef struct Foo:
  ...
If the header uses the same name for the tag and the typedef, you won't be able to include a ctypedef for it -- but then, it's not necessary.

Accessing Python/C API routines

One particular use of the cdef extern from statement is for gaining access to routines in the Python/C API. For example,
cdef extern from "Python.h":
    object PyString_FromStringAndSize(char *s, int len)
will allow you to create Python strings containing null bytes.


Resolving naming conflicts - C name specifications

Each Cython module has a single module-level namespace for both Python and C names. This can be inconvenient if you want to wrap some external C functions and provide the Python user with Python functions of the same names.

Cython 0.8 provides a couple of different ways of solving this problem. The best way, especially if you have many C functions to wrap, is probably to put the extern C function declarations into a different namespace using the facilities described in the section on sharing declarations between Cython modules.

The other way is to use a c name specification to give different Cython and C names to the C function. Suppose, for example, that you want to wrap an external function called eject_tomato. If you declare it as

cdef extern void c_eject_tomato "eject_tomato" (float speed)
then its name inside the Cython module will be c_eject_tomato, whereas its name in C will be eject_tomato. You can then wrap it with
def eject_tomato(speed):
  c_eject_tomato(speed)
so that users of your module can refer to it as eject_tomato.

Another use for this feature is referring to external names that happen to be Cython keywords. For example, if you want to call an external function called print, you can rename it to something else in your Cython module.

As well as functions, C names can be specified for variables, structs, unions, enums, struct and union members, and enum values. For example,

cdef extern int one "ein", two "zwei"
cdef extern float three "drei"

cdef struct spam "SPAM":
  int i "eye"
cdef enum surprise "inquisition":
  first "alpha"
  second "beta" = 3

Public Declarations

You can make C variables and functions defined in a Cython module accessible to external C code (or another Cython module) using the public keyword, as follows:
cdef public int spam # public variable declaration

cdef public void grail(int num_nuns): # public function declaration
    ...

If there are any public declarations in a Cython module, a .h file is generated containing equivalent C declarations for inclusion in other C code.

Cython also generates a .pxi file containing Cython versions of the declarations for inclusion in another Cython module using the include statement. If you use this, you will need to arrange for the module using the declarations to be linked against the module defining them, and for both modules to be available to the dynamic linker at run time. I haven't tested this, so I can't say how well it will work on the various platforms.

NOTE: If all you want to export is an extension type, there is now a better way -- see Sharing Declarations Between Cython Modules.


Extension Types

One of the most powerful features of Cython is the ability to easily create new built-in Python types, called extension types. This is a major topic in itself, so there is a  separate page devoted to it.


Sharing Declarations Between Cython Modules

Cython 0.8 introduces a substantial new set of facilities allowing a Cython module to easily import and use C declarations and extension types from another Cython module. You can now create a set of co-operating Cython modules just as easily as you can create a set of co-operating Python modules. There is a separate page devoted to this topic.


Limitations

Unsupported Python features

Cython is not quite a full superset of Python. The following restrictions apply:
  • Function definitions (whether using def or cdef) cannot be nested within other function definitions.
  •  
  • Class definitions can only appear at the top level of a module, not inside a function.
  •  
  • The import * form of import is not allowed anywhere (other forms of the import statement are fine, though).
  •  
  • Generators cannot be defined in Cython.

  • The globals() and locals() functions cannot be used.
  • The above restrictions will most likely remain, since removing them would be difficult and they're not really needed for Cython's intended applications.

    There are also some temporary limitations, which may eventually be lifted, including:

  • Class and function definitions cannot be placed inside control structures.
  •  
  • In-place arithmetic operators (+=, etc) are not yet supported.
  •  
  • List comprehensions are not yet supported.
  •  
  • There is no support for Unicode.
  •  
  • Special methods of extension types cannot have functioning docstrings.

  • The use of string literals as comments is not recommended at present, because Cython doesn't optimize them away, and won't even accept them in places where executable statements are not allowed.
  • Semantic differences between Python and Cython

    Behaviour of class scopes

    In Python, referring to a method of a class inside the class definition, i.e. while the class is being defined, yields a plain function object, but in Cython it yields an unbound method2. A consequence of this is that the usual idiom for using the classmethod and staticmethod functions, e.g.
    class Spam:
      def method(cls):
        ...
      method = classmethod(method)
    will not work in Cython. This can be worked around by defining the function outside the class, and then assigning the result of classmethod or staticmethod inside the class, i.e.
    def Spam_method(cls):
      ...
    class Spam:
      method = classmethod(Spam_method)


    Footnotes

    1. A problem with const could arise if you have something like
    cdef extern from "grail.h":
      char *nun
    where grail.h actually contains
    extern const char *nun;
    and you do
    cdef void languissement(char *s):
      #something that doesn't change s
    ...
    languissement(nun)
    which will cause the C compiler to complain. You can work around it by casting away the constness:
    languissement(<char *>nun)

    2. The reason for the different behaviour of class scopes is that Cython-defined Python functions are PyCFunction objects, not PyFunction objects, and are not recognised by the machinery that creates a bound or unbound method when a function is extracted from a class. To get around this, Cython wraps each method in an unbound method object itself before storing it in the class's dictionary.
     

    cython-0.20.1+git90-g0e6e38e/Doc/primes.c000066400000000000000000000077361231323242300174320ustar00rootroot00000000000000#include "Python.h" static PyObject *__Pyx_UnpackItem(PyObject *, int); static int __Pyx_EndUnpack(PyObject *, int); static int __Pyx_PrintItem(PyObject *); static int __Pyx_PrintNewline(void); static void __Pyx_ReRaise(void); static void __Pyx_RaiseWithTraceback(PyObject *, PyObject *, PyObject *); static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); static PyObject *__Pyx_GetExcValue(void); static PyObject *__Pyx_GetName(PyObject *dict, char *name); static PyObject *__pyx_m; static PyObject *__pyx_d; static PyObject *__pyx_b; PyObject *__pyx_f_primes(PyObject *__pyx_self, PyObject *__pyx_args); /*proto*/ PyObject *__pyx_f_primes(PyObject *__pyx_self, PyObject *__pyx_args) { int __pyx_v_kmax; int __pyx_v_n; int __pyx_v_k; int __pyx_v_i; int (__pyx_v_p[1000]); PyObject *__pyx_v_result; PyObject *__pyx_r; PyObject *__pyx_1 = 0; int __pyx_2; int __pyx_3; int __pyx_4; PyObject *__pyx_5 = 0; PyObject *__pyx_6 = 0; if (!PyArg_ParseTuple(__pyx_args, "i", &__pyx_v_kmax)) return 0; __pyx_v_result = Py_None; Py_INCREF(__pyx_v_result); /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":2 */ /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":3 */ /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":4 */ __pyx_1 = PyList_New(0); if (!__pyx_1) goto __pyx_L1; Py_DECREF(__pyx_v_result); __pyx_v_result = __pyx_1; __pyx_1 = 0; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":5 */ __pyx_2 = (__pyx_v_kmax > 1000); if (__pyx_2) { /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":6 */ __pyx_v_kmax = 1000; goto __pyx_L2; } __pyx_L2:; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":7 */ __pyx_v_k = 0; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":8 */ __pyx_v_n = 2; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":9 */ while (1) { __pyx_L3:; __pyx_2 = (__pyx_v_k < __pyx_v_kmax); if (!__pyx_2) break; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":10 */ __pyx_v_i = 0; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":11 */ while (1) { __pyx_L5:; if (__pyx_3 = (__pyx_v_i < __pyx_v_k)) { __pyx_3 = ((__pyx_v_n % (__pyx_v_p[__pyx_v_i])) != 0); } if (!__pyx_3) break; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":12 */ __pyx_v_i = (__pyx_v_i + 1); } __pyx_L6:; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":13 */ __pyx_4 = (__pyx_v_i == __pyx_v_k); if (__pyx_4) { /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":14 */ (__pyx_v_p[__pyx_v_k]) = __pyx_v_n; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":15 */ __pyx_v_k = (__pyx_v_k + 1); /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":16 */ __pyx_1 = PyObject_GetAttrString(__pyx_v_result, "append"); if (!__pyx_1) goto __pyx_L1; __pyx_5 = PyInt_FromLong(__pyx_v_n); if (!__pyx_5) goto __pyx_L1; __pyx_6 = PyTuple_New(1); if (!__pyx_6) goto __pyx_L1; PyTuple_SET_ITEM(__pyx_6, 0, __pyx_5); __pyx_5 = 0; __pyx_5 = PyObject_CallObject(__pyx_1, __pyx_6); if (!__pyx_5) goto __pyx_L1; Py_DECREF(__pyx_6); __pyx_6 = 0; Py_DECREF(__pyx_5); __pyx_5 = 0; goto __pyx_L7; } __pyx_L7:; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":17 */ __pyx_v_n = (__pyx_v_n + 1); } __pyx_L4:; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":18 */ Py_INCREF(__pyx_v_result); __pyx_r = __pyx_v_result; goto __pyx_L0; __pyx_r = Py_None; Py_INCREF(__pyx_r); goto __pyx_L0; __pyx_L1:; Py_XDECREF(__pyx_1); Py_XDECREF(__pyx_5); Py_XDECREF(__pyx_6); __pyx_r = 0; __pyx_L0:; Py_DECREF(__pyx_v_result); return __pyx_r; } static struct PyMethodDef __pyx_methods[] = { {"primes", (PyCFunction)__pyx_f_primes, METH_VARARGS, 0}, {0, 0, 0, 0} }; void initprimes(void); /*proto*/ void initprimes(void) { __pyx_m = Py_InitModule4("primes", __pyx_methods, 0, 0, PYTHON_API_VERSION); __pyx_d = PyModule_GetDict(__pyx_m); __pyx_b = PyImport_AddModule("__builtin__"); PyDict_SetItemString(__pyx_d, "__builtins__", __pyx_b); } /* Runtime support code */ cython-0.20.1+git90-g0e6e38e/Doc/s5/000077500000000000000000000000001231323242300163015ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Doc/s5/Makefile000066400000000000000000000005221231323242300177400ustar00rootroot00000000000000 SLIDES=$(subst .txt,.html,$(wildcard *.txt)) SOURCES=$(subst .py,.c,$(subst .pyx,.c,$(wildcard */*.py */*.pyx))) slides: $(SLIDES) $(SOURCES) %.html: %.txt rst2s5 --current-slide --language=en $< $@ %.c: %.py cython --annotate $< %.c: %.pyx cython --annotate $< clean: rm -f *~ $(SLIDES) $(SOURCES) $(subst .c,.html,$(SOURCES)) cython-0.20.1+git90-g0e6e38e/Doc/s5/cython-ep2008.txt000066400000000000000000000163441231323242300212720ustar00rootroot00000000000000============================================== The Cython Compiler for C-Extensions in Python ============================================== Dr. Stefan Behnel ----------------- .. class:: center http://www.cython.org/ cython-dev@codespeak.net .. footer:: Dr. Stefan Behnel, EuroPython 2008, Vilnius/Lietuva .. include:: About myself ============ * Passionate Python developer since 2002 * after Basic, Logo, Pascal, Prolog, Scheme, Java, ... * CS studies in Germany, Ireland, France * PhD in distributed systems in 2007 * Language design for self-organising systems * Darmstadt University of Technologies, Germany * Current occupations: * Employed by Senacor Technologies AG, Germany * IT transformations, SOA design, Java-Development, ... * »lxml« OpenSource XML toolkit for Python * http://codespeak.net/lxml/ * Cython What is Cython? =============== Cython is * an Open-Source project * http://cython.org * a Python compiler (almost) * an enhanced, optimising fork of Pyrex * an extended Python language for * writing fast Python extension modules * interfacing Python with C libraries A little bit of history ======================= * April 2002: release of Pyrex 0.1 by Greg Ewing * Greg considers Pyrex a language in design phase * Pyrex became a key language for many projects * over the years, many people patched their Pyrex * not all patches were answered by Greg (not in time) * minor forks and enhanced branches followed * March 2006: my fork of Pyrex for »lxml« XML toolkit * November 2006: »SageX« fork of Pyrex * by Robert Bradshaw, William Stein (Univ. Seattle, USA) * context: »Sage«, a free mathematics software package * 28th July 2007: official Cython launch * integration of lxml's Pyrex fork into SageX * the rest is in http://hg.cython.org/cython-devel/ Major Cython Developers ======================= * Robert Bradshaw and Stefan Behnel * lead developers * Greg Ewing * main developer and maintainer of Pyrex * we happily share code and discuss ideas * Dag Sverre Seljebotn * Google Summer-of-Code developer * NumPy integration, many ideas and enhancements * many, *many* others - see * http://cython.org/ * the mailing list archives of Cython and Pyrex How to use Cython ================= * you write Python code * Cython translates it into C code * your C compiler builds a shared library for CPython * you import your module * Cython has support for * compile-time includes/imports * with dependency tracking * distutils * *optionally* compile Python code from setup.py! Example: compiling Python code ============================== .. sourcecode:: bash $ cat worker.py .. sourcecode:: python class HardWorker(object): u"Almost Sisyphus" def __init__(self, task): self.task = task def work_hard(self): for i in range(100): self.task() .. sourcecode:: bash $ cython worker.py * translates to 842 line `.c file `_ (Cython 0.9.8) * lots of portability #define's * tons of helpful C comments with Python code snippets * a lot of code that you don't want to write yourself Portable Code ============= * Cython compiler generates C code that compiles * with all major compilers (C and C++) * on all major platforms * in Python 2.3 to 3.0 beta1 * Cython language syntax follows Python 2.6 * optional Python 3 syntax support is on TODO list * get involved to get it quicker! \... the fastest way to port Python 2 code to Py3 ;-) Python 2 feature support ======================== * most of Python 2 syntax is supported * top-level classes and functions * exceptions * object operations, arithmetic, ... * plus some Py3/2.6 features: * keyword-only arguments * unicode literals via ``__future__`` import * in recent developer branch: * ``with`` statement * closures (i.e. local classes and functions) are close! Speed ===== Cython generates very efficient C code * according to PyBench: * conditions and loops run 2-8x faster than in Py2.5 * most benchmarks run 30%-80% faster * overall more than 30% faster for plain Python code * optional type declarations * let Cython generate plain C instead of C-API calls * make code several times faster than the above Type declarations ================= * »cdef« keyword declares * local variables with C types * functions with C signatures * classes as builtin extension types * Example:: def stupid_lower_case(char* s): cdef Py_ssize_t size, i size = len(s) for i in range(size): if s[i] >= 'A' and s[i] <= 'Z': s[i] += 'a' - 'A' return s Why is this stupid? =================== Ask Cython! .. sourcecode:: bash $ cat stupidlowercase.py :: def stupid_lower_case(char* s): cdef Py_ssize_t size, i size = len(s) for i in range(size): if s[i] >= 'A' and s[i] <= 'Z': s[i] += 'a' - 'A' return s .. sourcecode:: bash $ cython --annotate stupidlowercase.py => `stupidlowercase.html `_ Calling C functions =================== * Example:: cdef extern from "Python.h": # copied from the Python C-API docs: object PyUnicode_DecodeASCII( char* s, Py_ssize_t size, char* errors) cdef extern from "string.h": int strlen(char *s) cdef slightly_better_lower_case(char* s): cdef Py_ssize_t i, size = strlen(s) for i in range(size): if s[i] >= 'A' and s[i] <= 'Z': s[i] += 'a' - 'A' return PyUnicode_DecodeASCII(s, size, NULL) Features in work ================ * Dynamic classes and functions with closures .. sourcecode:: python def factory(a,b): def closure_function(c): return a+b+c return closure_function * Native support for new ``buffer`` protocol * part of NumPy integration by Dag Seljebotn .. sourcecode:: python def inplace_negative_grayscale_image( ndarray[unsigned char, 2] image): cdef int i, j for i in range(image.shape[0]): for j in range(image.shape[1]): arr[i, j] = 255 - arr[i, j] Huge pile of great ideas ======================== * Cython Enhancement Proposals (CEPs) * http://wiki.cython.org/enhancements * native pickle support for extension classes * meta-programming facilities * type inference strategies * compile-time assertions for optimisations * object-like C-array handling * improved C++ integration * ... Conclusion ========== * Cython is a tool for * efficiently translating Python code to C * easily interfacing to external C libraries * Use it to * speed up existing Python modules * concentrate on optimisations, not rewrites! * write C extensions for CPython * don't change the language just to get fast code! * wrap C libraries *in Python* * concentrate on the mapping, not the glue! ... but Cython is also ====================== * a great project * a very open playground for great ideas! Cython ====== **Cython** **C-Extensions in Python** \... use it, and join the project! http://cython.org/ cython-0.20.1+git90-g0e6e38e/Doc/s5/ep2008/000077500000000000000000000000001231323242300172175ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Doc/s5/ep2008/stupidlowercase.py000066400000000000000000000002751231323242300230120ustar00rootroot00000000000000 def stupid_lower_case(char* s): cdef Py_ssize_t size, i size = len(s) for i in range(size): if s[i] >= 'A' and s[i] <= 'Z': s[i] += 'a' - 'A' return s cython-0.20.1+git90-g0e6e38e/Doc/s5/ep2008/worker.py000066400000000000000000000002701231323242300211010ustar00rootroot00000000000000 class HardWorker(object): u"Almost Sisyphus" def __init__(self, task): self.task = task def work_hard(self): for i in range(100): self.task() cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/000077500000000000000000000000001231323242300167165ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/000077500000000000000000000000001231323242300203425ustar00rootroot00000000000000cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/blank.gif000066400000000000000000000000611231323242300221150ustar00rootroot00000000000000GIF89a‘ÿÿÿÿÀÀÀ!ù,T;cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/bodybg.gif000066400000000000000000000236071231323242300223070ustar00rootroot00000000000000GIF89aæNÄÿÀÀÀµµµ½½½ÆÆÆÎÎÎÖÖÖÞÞÞçççïïï÷÷÷çïïï÷÷÷ÿÿÆÎÎÎÖÖÖÞÞÞççµ½½½ÆÆç÷÷ÎÞÞÖççÞïïÆÖÖ½ÎÎÎçç!ù,æNÿà!ÏuÔó@ŽšB¤ÌôlM€µÔ|?)  BÖc(, Fo¹Ô1–³¦ÀŽDEe¨­ü,Ópm›gÇÙ¢ÒpœßðÚˆÔ¸< ªºÃÑ(8 e= qXdK P‡q<8k:a D9U3 G  ;W[hQ[ …˜L H5 2³‚¦¹"®A0g#pñ~TÇ+u£AáBU·*4¤QmÉÆWJÖ`ËPŒ2ðPUB •¦æ´tÙ æ­êtIí×JmÚ!œ€ðP:ãÏh( |–!u ÒnE¢ YÚÀ$PLÊB,&ªø^ü C[°bæ0KvsLPá­Ý$Ø ‚ œÊñ†ºîÔ™Œ, xʳ(‹c- ú²+ £f¶© ¡OR4ZCÈ Á7æ%# \ ;Âô³É]?ZË CÊp·µ6áh欄„,8X°@7ÖB¼UòFÂ-ÃÕöJáÖ@ûóÃpFgØyr_8`@„Yÿh6õÉbtsÅ%¡öŸ±!QZP†!‚uÔUwÝ&âÄÀHˆ™„ ¸XÃBb ÄHwé`aˆS,eFŠ”|Ò@|< Âu%`2„¦’VNªx@Ú˜ØJU%ƒÌT$ÆM‘ß^;ÐÒ€<€d’$ì!^нù" pñÈ!§Ô{èUsÑ—bLðgØ7ƒp0·á4À¦X…Î #Ž´êÆSšV“±§k¨sEë­Aù5CA„d  çŽ*ñÀ*ìÔÅë3h†aï½îߎ4< EÞ9ðX9‘{Òò0<äÍu°˜‹BLédù’‰†AÊñtÜèUWšrÃ\4‡‘/~þ•׳Ê+ϰ…I\-ªAÔ± =èµÌe›ÒSrC›5ÑîÆU*í-çÀɺtŒ‡vU ¯o=c+W#’Á \‡ 9I@Åb…H@·ÓSIÜgô„ÄbÐþƇþ=ãÞî†ã*sí qò—ÔŒv¼ÞŒAQ.‹ÿH×Ð¥èƒl »f$ýå®éÊ‚:GH¡%Ž!!ÀÆe|Ç}:p‰úS@Ж‡·;Ì ÑÛ„ô¹86ÐiR íXbÖ+0÷ü hn##›zsòL P‡çȪ‘— ‘˜±3Į<äL4X ® ðà “'/³Ê&˜@0Ìb òÚÁ‘Ph¢#˜7:·¬ÍÄ ²:ˆÒ°½ Á1Ô“\Aèã>’4ÌCÂ)®Þ‰Î{@àÇ,”g§#4o+'¬’cp¦çœ«ÈZÀ\£M¡#Œ@à ›8ÀÉL±)o@^<ÓÀYA~Š N®„ÿðŒ(ÜÄ7q„fh„(ßðñ¨À3¤B¸á›â\a)ihãÆ ¨0à@X£›ö(>$‡Qy¡) @¦À¨"YL {4ÒÌ(IcÉ£Êðg0 .B‰ÀQJC.á!‹„B%‰ƒ8æ G‘œÕ?†aé FP^Tc‰Šá­ e$WY†5\8ìÑB9â³–d¸Òry#f E&¦dpØÁ T·k„02oß47q9m, 4‹üÖAƒ_Q !©¤[ƒ†™3’PËBkHÀÈF/… ~*ç@ÆÈa:+àà9 uÄ?ýÜÍBFcž¼ÿÂŒ¨¡˜— z¥nžÁ ™ B#RX±€¡" ’—$ x8Ëh|ÓM£8I Øh^¡hTEbÑÐæÂÄXÉmýr¥øBjÊl¢ HpÃ`Õ&œÆ‘L owŒ’`œV»GÚÃT@ˆ„˜ÊpïŒõreXôë¨Óÿ¯Äf[ˆ6Ï@Cð‹$-42x'%ÝõɌ铄\¤•KŒQ4œ™PÀX`«ín>|¡#Þ^ùÝ8t3/pB8[š`ðX=T”ß- =m‘„FÑ)­œzÆ›×Èñ1 Ì3NpAÐJkh­Ÿ!äy8€U¾&ðá¢C+ÍÏ,C†# `P£¯lcœ!L ”Ðhò¬6(˜=¹(®ªJƒ wÚƒ]ø“ éÚ6g‰[“ëD°v‘¤Y~†»ë¡™ ÛØzªTt×0ãÜÉ)šO±Í(UìVi£À¥x~6²»fÔzL˜ÿìC#P@ „£¤Ÿh7r£™Ê›r8uÞ­Z3a€m‚ý3¥Æ)ù ‹q©ªDE†„r°g ‡ÍP;J›BÍØÜ"@™É‘Á#Û¦…Žô¤j0 +ë’Cr(˜œÝ#RÖ»ˆõl$/øÕP eYÉñË9µ;Š.Ø}0FЙ¨[ùä¢:¥/â Xl$¬X…'p`8ªƒ†’QÁÊâsp$lë(Á\B å[uVwzñB™f<½âPèÉr®¿Ê«d¿5êÌ÷ðÓx£ÁÞ[‰jìŽò¶½kÏ .3¡QGÆ ¤ëó[Ò¹à0ÉÏ*'6ÿ!Æ7¨ðdGÀÇô‰As;™8ýS%$Á£ „:p 7Cü$È¿\9f0̲m0 \jmDV-¦—ÌGzmÁ¼“rUèt¡R«˜§œ<ÿPé:Î0ôÉ:JÂÒ mŸƼ³»®N1–Þƒ‡  Ž`»5P]õ~reÔ"1Žü~OçMÐ 3»@"Àõ €í´u€À¨ÈÄ(âJJ¡9P‹„ RòSC°çRFsF”` 4«Ò#4‰q¼A“’ÿµ| ÍP‚åU€9%# ÖÚÔ­]‘*Oª ÃâÖ¿B¼(“•ÿC:z1¢NýÔW° Á<Äl$æí¼Ðu­éõa¯uY–µ“C 0Ò"j)ú”› ™uÿ@¦u­jðϯģu•‰Z©Ú(¬[B1¤¼Ö;@°D4P¨DÖ`ŽÂ ¡è ðL¤2Z^º cãÇò¶f´Ã ³Fa'ÃÆîJ3¨ÍGŽå²P0jÂuý·¶ðË‹¥<Ç–P§ˆÚÖÒÆèÉAçpP-âG3ö?ÍáçVB‹’N°´¼ ,ÿÒ(t4—yÙ‘²á¹mµyÝðžzw1kÀr­ݼM~ê o:üè*u Z\g’$‰0 ¾M}‘z‘Å­°}6Ž„Œgx‚ãé¹@1ì«âAGb.–i.[…ƒpÃX.Ú ûF1‰ò'ÞÈÁv¶)¬*Å2ÞþDC“ãF²ù( &hŠ€€f;E¦íûæLJAv09#ðO·”ÂTÇ?jÄ™ÀÝïH~láÞåŸ ½Ð Ã"pWQ)Áéµà#¸^ ˆ !2¤ñâ€ïUÁ~›.Ô æ£L%+ €°>ÞÀÁIu€+¹ôLÿ¤ÐGAx{¸”Ù#‰N!ßóHnFp ÑÑ íäŒ0LÐ[†Æʃ+´ŽAcó³Y(„KdH)Q ]ïõàAo$%Hðµy‡QÙaÕMV•jš ÷tJ§;cz QÇG(žlTÄ~_ MsH¡ ÊAþ$©Dëºoú[øï|ohÑðjÈ`z´1Z!ªí~òK€Ž ÓJ0½®ú½‘“a¨‡È ‚’ô”Z °/ 8›«DÙÞ;4ÃÁ‡².ñµ©å“?C ‚ !”˜Sq„Ñ[(I[ »šîâîŽ`‡">hm hÿ 4åRgY&••¬‰²¬Lå²™µò<£(&—m×3eRH†`¼ŽÒ)µj½b³Úì™`t¥Dé`>£ ÇÃqh¿ DEa‚¤P¼„Å –@@|¨$Pè00H%$)PT´$àñ%È,P´ly~‚†Š¦,„Q-Ø ­¨A8P¨=<)ôMà-,èy•BÐXÌXá5Bø¶@,öüì,ì4úr%QPp&v{šR%Ôª²ž©­94<¤Šä•0@æÜ ÓØ´ ôûD’¤$JT‚õÒ†" ¸†šWesç \8¡ vŒp;‘… <*ÿHâdÇ5C´ôÃÅÕ¦ Ô4Lˆ>‚r–@fåΙy…¦:Šù‰Da*$g+´áƒ0G n<öàvÁj•&Pxªví”. J;zÓ3pÎp “çz†þY0áVŸÖ+m‹£‚³>p-Ÿ1î‰TˆÊƒ$Qع.Äûß¼çŠ “iv@ñ&½«J;\l8PÀ¬¬®ÅäÊ€_!Ln¾õCR83ŒÁ r±Í{¼84lôïÇ_øÇÉ=Œ°‡ Ê\‚}X@ÓIÿAÔ7ßl1’"æñÏVJ¸Ÿ<õ·Þ’O©VñµÌ? M5´ëLƒÏ[ÛxKih?3µÝn§É e‹ À m5Œàšì¶Û–°3³¾ÑÀíüÌ C{GFÚ˜§ðgdµÿçÅ݃G.B+Nõ^=©äÌx×g–˜€÷ßÑœ z .Oq›4ºØ¾åÀ–úÅ/*Ò¢©Ò­]n|&xfØég!;ɳ´HCßöOõ½£‡˜ÆÓ»ºam] ÀhmF®ò€ü3È0 šã¯ ½ vdÒG$ß§/ß«Dcȧ8˜oy ƒ, ;÷]À lÃÄ4ì4âzB#òBD >Ú]J8aFD;„–«Ú%BÏ ”šÓrH¾m‡5ÿ£ Ü /ѲWÆd$®pU„8E‹hxÉÅÐkPC]˜V >ô‚záÅT²ÍPðÿK¡Z`¢$ªê§H… 0%ç%eBé €„€*”(£ƒÙ¨ÊBl'‚3ê j2IƈFª]‹rùXe(¿¼,- ˆš‡/r”Ó0n&ßz$&sHªÁ­(‹ÜZèg² Ëf 0Ôˆ0äLÈ6²@^f8P-mƒ­'—Ÿic_ÑÂ(c‘UfÐöÊÓ`ÛÉd3™ÔÂJÆ"Ÿiä+(¨’R‰œ]Ùd ³ (¯œÐʤ VÀHK­Ã w+×D ’,X2lÇÔ§‚Âä¢r¨3F’s£”bX‹a+ «ÿ–˜•‡¡‹ZDø 5 9sšÓ*Fg…U>§žâØ•×'R&)OcZ`VúD\M4¬p‡'R„¨*D"H…“ƒØnªDù¡3ÚÖ¶ànFëe)°i¦n é `0\uêšòi­0¨ã§s²*:Žv…a‰ãaƒDz4²oT ÀZ úņü`Y¨²€%W¥ñ wÀ«ÍB™0<ÀþbkØIÓéað¢‚ÌËØ›1®u+XCd?æFøŒXäR¬å ®b¤ì³©3+Ø% ]~íAÁ–F82¹VtM•íÍëƒXùsklØôÞ1\2½)h.%®êžÿ7¬cèÈÜöà‚P 70½;\x©K/ãî0¤Ÿ™Fæv“Fa¨4hÈzß™×x:…“;T‹¦¡øà«ï蛿¶A¾‚ÓA~72æ}er`ߌ†6ð®¼Z>v¶é5ØÁãHë¯H ’ƒž &ˆa€ä†Á<Ð)RrB‰„x¶ÑÅ%"Øèa*–žÁh›.ØEŒðä‚ 7αi@[¨‘ ˆÀäÀe7@r³Hé”àË>¸iz ä ŒS*¯Ÿ!íëRLQ €†lÈ3$ ÐÆ5ë%#9ÉÙP[8“/Ï`Àn´¯ÿä ï}â~ügOT€åE´Û ™eì" )a†tD£ÄÓpŽîœY@4P¤–Ri/­…K¸YÕh„9¤°FF@?žÜTRÚ€FÙCaºNôN]všÔ)}¯T  4.P€~uƒA(_Á[vu‹£hìö,²Ô¼@´U<«ŽdNØG¨ ’»Êm‰—è&¡`_ûÚþË·é‘ïf²ÎÙÒô·Â9Õƒë{y­^¸¿!.ÛœqáÜØe8¦,îT7ñRï¸ÇEš<ÎÀ€¯G¹­Knrâ8jT,o¸Ëkùé°kå,¯ùÇ9C-‹Íœç  móŸ  ½ÿ–p ¥£ª€ô¤×²ZVÉ×ÄýËq¨—Ó¸DwúαŽðgh\ç#÷zÔ‹Cb*<ìqŽÖ^¯vµ“80 ¹Õ÷:é UßøØïnÀ™.ðá­¸ßSW ¢è o/üÅJj=~»½ëŒ¯Zz¼–…ÅOþ©0k»â%ŸyzÑ@&Ôæ??ÒÊó¸ó}7=ÆX•s+”žõKj‘)æ.øº^öŒÊûÙUuݧ‘,z¿=îéü‘:ÜW#>Å|&‘”,‹È5é=ÿü†ú<åòìA쯳~á-Ÿè¾÷1“OjmŸûÖ/ÿyà–rækì_Q’·w®¯~þæÉ'Úïõë[8ÿƒ«$(_>YÝþýZµXȈÂB`C°‹4 Úݲ…8ÌÝ(X ŽÂ~EDê ’`CÝù^® D€`ãtÃÆà˜ †¨‚7Øà bcY™ÿÁž ú`PpAi|Cá)'áæß†Â æ8(¡¡òñ”!Z„Á3m`õE¡f[ÈÃû5Äša2 üAášá‚] ¤ßåuáfáÂC°áÒÖf¼æ¡>‚Lß’¡¶áæÁ 'Œáø" J‹P,zµÈ &á$’ é”²þÄ–Ÿû9«pžOâõÑÿžuÌ$"P¬âñ•”´G"UÂDb(Ì¢ìÙ‹q¸I ¢-Þa –!%öŸ…Üܦâ(rb)>Ìiâ>@ž,>#+¾Åéà :È®E/fI)`h" ô![€cæ~¡.^F:†£øµI`<^ômŸà":^ãóµâc1â1²_N zÅÀ߇=bÝ>¢•¥7¡•y0$Ô$®e#"!Eöã碄Vf$äóÉ£<ÂEâŒ(žGEÖ\ÿ^"ä~UãBvdá9d:\Ø%Ÿ7¶äMø" "B„K’Æå"K*Rbí=â”c=åç%ÿÏ>z<Ôd‚8åSÂŒ<`%WV¥ß]âfD¥®IWZ\TKå àHZcIú¢^™9žÒ¢¨%Ä㘅Qò£\êBö$„áåXª]h•TX.I^BïµÊ³0&¹A$8ë@¦az¥ÜÕÀ.þ$`ª#õYX¡Mz&ãáR:!\Gdrš“øAïA kšÔgªˆlæØ•Õ¦ÛàfƒÁŠæÍô&uMßž#ob¦Å‘”qNel&çÁÙ¢Þ¥ñ §SUbzÀãOuÞÔꈃRªu>§®]mªfZާª UPÄh2 w–Ó½Wej'Á§ÒMŸ)L]s*Î}~RNÅÿ€P„§}¦'q%’c-mÚŒ¦Î'"×|š€‚.h~Ví­d«¸çÅ0¨á¡Ï Ô§>mèâ8¢‡žç„–æ²å<\_ö'…’v†Áΰh‹ž(•]ÂP ž[ðg-…¨ª\¢u5a«”(2â'e(3ºf˜ (Yõè7üh >éÔߎêeÝV´‘ wf(BŠÞ évâŠûÔ ®”©–v œÜ­YYƒ(0†X+ Ã5 ¡š6–'úA]š]Oú€èñ¤l½…˜i–NÉQÛb™…6 mž_ —ûÈé¤ÒÂ¡Š†(¦qªüU&>Vâdª_îhÆ©ûêŒÐi+tÿË6¶«Ÿæ"æŒ8Vâq•c¾DÊŒ2ÔœŠYêŸ1ˆJF„<¨â«Ô@>¨«‚]NíL˜6+d©DÖŒÄÀfü©(žæKyò<†Ð&7Yb¶Ž‰)P´–ݤª³ÕŸ9"¸º³–««­é•-g[X(bÖf¦RÃá «d$í¹¬ªé<â\–­ŽÜéH¢e>ƒL¼ÅVêæa«øáhÁ~Ã?Êç:,'|šÔ-#Ω’[éÁÿEŸ7¬i³ ebGY¾¿J¥­†lÉá>®©`2Qø}k «½(O)¤ìÖ™›P„®RWâê!~e(¦aÖž ¶¢Ã®ÿ΋dÒë핪šb\­Víùù)r=Sòì$Ñ)嵯 †NKïEHlÉ]aÆݵÈêfTìr^§ÝfåÖ=“ÝZ-úÐÖÑi¿v!ÁÅ«”¢Ó£è$Þö-ZâkÇ’&nŸ[(ÎåØF[†‰Ð²J-ºnâ`4j*½æKÚRË[:bííäÉ&[Þâ!šÅ‚‘`®îµÖnæ1æÖ&âÚá:æd¹æÜÏ!­Å1fèÝ\ýõ-±öÎÍåËËêÞò ã-6˨2ØÝ"éB\^š«ºÊB­wœ«÷*¯‹ú€( c ô—z¤G÷¢/ܪ¯ùbY6 Q˜Îo͹ÿ¤R¶ï*åV],º$®}ÂÉ…aì®àÿ¡ѥÉ^  ¯ÃÉhÿÞw‚¢TÊ/öfÓáÜË®²æÒ‚åùâà9PL/(ÿ¦püUŽO¬l«„ZòN0…þ-ÎyX O=ð^ÍÌÆp:š%®Ö1Pf£f\e÷®Ú fô—"€Á³bð bžÕÞ¨ÏMnGñs%X±Ü‚%ÑÇHÊû0ú[À* f …Œc§°`5Ð ”O.öâp+Þò\¸QŸo òÄZRˆZdÉO$À$Kа.²e8ÍÊ$«»‘ŒÁ%«ÈáU­(›ò)£²'„;cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/cython-logo64.png000066400000000000000000000072761231323242300235000ustar00rootroot00000000000000‰PNG  IHDR@@ÝnAHsRGB®ÎébKGDÿÿÿ ½§“fIDATxÚÕ›{˜Å•À}gF–×¢Tš(Ô¬ʼnAãŠÈúmDd5ŠQ×ÝÀóaƒqó)“h?”$1Ñ Ï èˆàc@@ Œw·»«jÿè¾wî½Ó}çÞ ¨[ß×_wWשó¨S§NSíXk)T*ÓJ©n-EÄIdgÛÈ G‰ˆlSJY¬µÔ××[kƒçºÛ½ïä—Ì{¥Rª`â¼¥‹Ú[÷_ÕÙ–Dóe6O³Œ\â$€áüÎÙ3UõyaV/ßðÔj:ÞßAQ__ÿ’µûÆW­ýëé­aý'ÍfHèž)S¦üó3Ï@%LWžÕðÔ}í­ûg®[p™“H¤?žý½§mgò£™©Ž6Ø6Ãv£¡#™dÍë s´íÊ!²èÓ4÷b‡–Å–Ôž$£û)¥F8ÖÚ A§œrÊð>}úT¬Zµjszðbå ”Z\˜Ue€"òQv»lI_,ÊÖ•ˆNm¾>åxÖœ'¬—Já¹)Ö-¸Ü ;š“‚RêÞ|LçþèÏÖs;ñR©àr;Ѿ;n°øm9H*aÙÀçÜù‡[Üð¦_¬ÀO‚ßmmÁ=_±,lnñC ¿ F¯ê&—|uÍP&":ftrÚuF¥Ôׇ hx‡ˆôíFA¹¥2†Ìã7óªç‹Èͱ2wGô„5[ÐqB\+"ãò¨:x;«j´ˆ¼žˆ>, ì€3áûObmÉÓÒN}}ý8 )Ÿ¼‰s—ZÏMíôRC=7Åšy_O«ñXà‚l!6eõ:4ý =w‘v]|Ïé»n6ÿ¯¯DŽ‚ˆ|0é®eÖsSx®‹ç¥ð]Ïsáƒ/ÆO-fØOs´1‘/aßs3À^ØZð’‹ñöAËÔó êMãõë] Æ æÎeТ:ð=7廩Þ@/t{×LÌL¨Æuù$ÃB w¬©`ûŠÜ™8êy'R•E¤_–Tg¾¸ûA§ç¿]–B T„¯{Ó,LžN+•ˆ8û'F“·u³‰!àeÀ¯Ò«««'ÔÕÕm*öîÝ»«¹¹y Ð7_á¢ìAOó{ˆˆì>höà@KeO ”R½€·€eâøˆ|-îc¤”RÃwzèøn`9°ø 0øð•àz‰ˆgOšcGˆÈÖRXWJ­NùÜ_DZ³µ°èѰADædWLš¿ü£ý/h­1¾Ö£}´ö1ÚL\3ï’?©˜k+{hðp>òÐ\|AûþƒFë+ÒˆµŸ!â-^Bºé@}}ý¿Z{&/liÚ÷1Z‡Üæ ÆøAý†Ùo]‚uŽlê‹ù?/Ån-4Ž“æ/ŸªS›|7°í¾^®›±¼ž¼k퇫‰_‡no¸­Í¼3£ºÐ4\ˆßu¯àöæ575oÀØÏuµÔ`¼S1ît<ïZŒ Æã‚õÿ ¸=Ž€Ç€ïÄR`;§û®Ù–&"¥òâ¬æ¿aCŸ5$ûnóÞkWÞ^ÐPÂé"òK€Ónþõ4­ý‘#Þ­¹kÉ•~ÒÛrß}Àcÿ—1’pš€!À®žœ Lyç2ÁùJj—gcet£S¬­È¶}€ö˜vcEäÕœš7'üëÝŠq³zsfR»úþ"­ª‘DÔjöðBN‘uEZÁÚ´óQ¾$"ë ®†J©Ï‡‹ÐÁ*ûDd`Q‹Q Aý€×Ñ|7p›ˆò•v :µ?£hÁÆô:::†0¦iSò½À–ˆ«6Ê%‹óŸ‘ ¥ºÁJ©·D|Z."gEÙ8ÃtŽRjs‰È7Æ ßF^(RšzEûP‰ûÇŽ;{ðàÁ5•••5‰d2Ù‘L&“û÷ïïlii¹¸$†®?‹È9ÅnLþüÓAܘ|SDî-ik¦”J„1‚ãqdÒ¬œøÀùÀ|àsE4¸¥˜Øò'ø(·(¥‚´èßÇ\}€ÃÈNþµSDÚmM”R•À4`p&pä!¢Ù^$ÈÕüRDÞüD†UU¸y<êS Í¾/"‡LaúînàêOùÔÞ̑NJ”RÃxÕ 2ˆYüxJDJ]͇¤!§§—S] \$"ÛK€Rê<àIº2åÅ”÷o‰Èc‡È ^.‡JÝFhx¿G„Ѫu%²uÀdÙó1­,ƒÖµ%‚.&Šˆ!ýðŸ%Zåq"òB¡Fg6¬¨î{—Y_Ÿk1§Yc7ÆVZk°Æ`»5¦ÍZ»]kóTE…¾gåoïA'„Âï_Jˆ øGy9;°¸¸„ŽZ€Q"âj4ù®å‹ ö*k̬¹×óecÌ”€y›+k0a]ðlöá:ÿ°î'—¾[@áÒxb©Š”!^ Ô•œ†£òçÍ[ºÇ3ÈZ®xö¶sª›÷d¿ÞÎ{Ö˜~ÖØìÑO3&|ƘÖß=CŠ©”>Fvu‰ÌL+v¾k­+ÂðÚƒgßñ´íÕN«Ñº_×áƒî¡¶ìˆ˜otÕ!s…•R5ÀK„Û."OF}˜´`Ùpk8Þ;­1´Öß`4A1`4Xs5öŒîšh5vÜp ‰Dp8Ðb°‰Mìí÷µ³ÝÝ ÜDöÁ±âJξrÊ— ³¶bÕú˜\&l¨ÎÝUÛšðÝn›‰Û%ã2GQ0€þï^ó:GÝ7¦§øW!œT\&>õîç0ÚÙb_•gÍ1¶Ë˜å2ls™ÏÀÙd­ÖI°‡au‹µ†®g]ËÖo42œÓËÀÉeÀeöÙ^§s¹EWcÌl¶º1ßÕ6¯ì8uäGwà§#˜O¿£eZ-Ç-y½ô/C™œ µþD“]›Ç|W]8â í:ÿ–µÖjBh郱<…µÇŸZ¹ð_ߘ…Õ;Ð&‘˸Z¦Ÿ9— …\²Þ þ„]¡ÔÁÆÀ®éMƘ³²G1_´ïœ·öæ*°ü˜Ý¥!RÅMÔ¨GÔaö–;ÊÀg3dkÿYm¬Š3fÚš ëfm˜r°LœJ—þî:—ë<_Ü´Lœó»S~g­^”BÉÎhõ©ñVØjÁúa*%•—ß)ãݤ=—ï+K"òp°|\ùJx s7\pµ1þ¿i£ÛóšàĘíʤ³™$X*"f$ê¨]ý› ÞLT&¦pùiö|^ýƒ‹~ü"²å{×ö4 º90„^hӆѫ_cÔª?Ò˜ Rj.…qF—‹DdIÏ~ã•û°ºñsÚ¼Õë{()çVò^@Dn!ÈV–RUJMêy3Ðùr Â©<•ŽTóûõ|-µ+Æà8Á)Çyíc‹ +¥7–ØOæ”mlyû‚ëAÏÁê‘ËZtªú0W3zͳ=Ä.–”@ï‡ÀÉ"²5."42Ü_,¡ÓÍ'ô>,ªõ«gE•ÖŒÂ8ý€æm*-ßøQ ¡øUÀi%Ðù¹½Ø˜à`v‰Ú°P"ÒzÃa}C#\Š]Øœ&£KŽ Ï攑Àh抈ßÐÐPUSSSÕ»wï ß÷+kjjƘDee¥àû¾ÕZkÏó´ëººªªÊommõfÏží‡4ô¦sÉú©¨ˆòF«Ü|0ògüq1¨,ƒã8›‰ÄÒŠŠŠªªª>¬®®ÞÞ“mmmƒÛÛÛ÷body #currentSlide {position: fixed;} /* div#header {background: #FCC;} div#footer {background: #CCF;} div#controls {background: #BBD;} div#currentSlide {background: #FFC;} */ cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/iepngfix.htc000066400000000000000000000023231231323242300226530ustar00rootroot00000000000000 cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/opera.css000066400000000000000000000003171231323242300221630ustar00rootroot00000000000000/* DO NOT CHANGE THESE unless you really want to break Opera Show */ .slide { visibility: visible !important; position: static !important; page-break-before: always; } #slide0 {page-break-before: avoid;} cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/outline.css000066400000000000000000000012701231323242300225330ustar00rootroot00000000000000/* don't change this unless you want the layout stuff to show up in the outline view! */ .layout div, #footer *, #controlForm * {display: none;} #footer, #controls, #controlForm, #navLinks, #toggle { display: block; visibility: visible; margin: 0; padding: 0;} #toggle {float: right; padding: 0.5em;} html>body #toggle {position: fixed; top: 0; right: 0;} /* making the outline look pretty-ish */ #slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;} #slide0 h1 {padding-top: 1.5em;} .slide h1 {margin: 1.5em 0 0; padding-top: 0.25em; border-top: 1px solid #888; border-bottom: 1px solid #AAA;} #toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;} cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/pretty.css000066400000000000000000000176511231323242300224150ustar00rootroot00000000000000/* Following are the presentation styles -- edit away! */ /* body {background: #FFF url(cython.png) 1em 1em no-repeat; color: #000; font-size: 2em;} */ :link, :visited {text-decoration: none; color: #545454;} #controls :active {color: #545454 !important;} #controls :focus {outline: 1px dotted #545454;} h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;} ul, pre {margin: 0; line-height: 1em;} html, body {margin: 0; padding: 0;} blockquote, q {font-style: italic;} blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em; text-align: center; font-size: 1em;} blockquote p {margin: 2em;} blockquote p strong {font-size: 1.5em;} blockquote i {font-style: normal;} blockquote b {display: block; margin-top: 0.5em; font-weight: normal; font-size: smaller; font-style: normal;} blockquote b i {font-style: italic;} kbd {font-weight: bold; font-size: 1em;} sup {font-size: smaller; line-height: 1px;} .slide {padding-top: 3em; } .slide code {padding: 2px 0.25em; font-weight: bold; color: #533;} .slide code.bad, code del {color: red;} .slide code.old {color: silver;} .slide .pre {padding: 0; margin: 0 0 0 0; color: #533; font-size: 80%;} .slide pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 90%;} /* .slide pre {padding: 0; margin: 0 0 0 0; color: #533; font-size: 90%;} */ .slide pre code {display: block;} .slide div > ul {padding-left: 0; margin-left: 0; list-style: disc; } .slide li {margin-top: 0.75em; margin-right: 0;} .slide ul ul {line-height: 1; padding-left: 1em; margin-left: 2%; margin-right: 5%; list-style: disc; } .slide ul ul li {margin: .4em; font-size: 85%; list-style: square;} .slide img.leader {display: block; margin: 0 auto;} div#header, div#footer {background: #f0f0f0; color: #545454; font-family: Verdana, Helvetica, sans-serif; padding: 0;} div#header {background: #f0f0f0 url(cython-logo64.png) 1ex 0.2ex no-repeat; line-height: 1px; border-bottom: solid #545454 4px; height: 2.4em;} div#footer {font-size: 0.5em; font-weight: bold; padding: 0.6em 0; border-top: solid #545454 3px;} #footer h1, #footer h2 {display: block; padding: 0 1.5ex;} #footer h2 {font-style: italic;} #footer a {color: #545454;} div.long {font-size: 0.75em;} .slide h1 {position: absolute; top: 0.2em; left: 87px; z-index: 1; margin: 0; padding: 0.3ex 0 0 25px; white-space: nowrap; font: bold 150%/1em Helvetica, sans-serif; /* text-transform: capitalize; */ color: #646464; background: #f0f0f0;} .slide h3 {font-size: 130%;} h1 abbr {font-variant: small-caps;} div#controls {position: absolute; left: 50%; bottom: 0; width: 50%; text-align: right; font: bold 0.7em Verdana, Helvetica, sans-serif;} html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;} div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; margin: 0; padding: 0;} #controls #navLinks a {padding: 0; margin: 0 0.5em; background: #f0f0f0; border: none; color: #545454; cursor: pointer;} #controls #navList {height: 1em;} #controls #navList #jumplist {position: absolute; bottom: 0; right: 0; background: #f0f0f0; color: black;} #currentSlide {text-align: center; font-size: 0.5em; color: #545454; left: 90%; bottom: 2px;} #slide0 {padding-top: 3em; font-size: 90%;} #slide0 h1 {position: static; margin: 1em 0 0; padding: 0; font: bold 2em Helvetica, sans-serif; white-space: normal; color: #000; background: transparent;} #slide0 h2 {font: bold italic 1em Helvetica, sans-serif; margin: 1.25em;} #slide0 h3 {margin-top: 1.5em; font-size: 1.5em;} #slide0 h4 {margin-top: 0; font-size: 1em;} ul.urls {list-style: none; display: inline; margin: 0;} .urls li {display: inline; margin: 0;} .note {display: none;} .external {border-bottom: 1px dotted gray;} html>body .external {border-bottom: none;} /* .external:after {content: " \274F"; font-size: smaller; color: #7B7;} */ /* .incremental, .incremental *, .incremental *:after {color: #545454; visibility: visible;} */ .incremental, .incremental *, .incremental *:after {visibility: hidden;} img.incremental {visibility: hidden;} .slide .current {color: #B02;} .center {text-align: center; } .right {text-align: right; } .small {font-size: 60%; } img.center {display: block; margin-left: auto; margin-right: auto; } .slide .syntax {padding: 2px 0.25em; font-weight: bold; color: #533; font-size:85%; } /* diagnostics li:after {content: " [" attr(class) "]"; color: #F88;} */ /* Syntax highlighting */ /* .syntax { background: #f0f0f0; } */ .syntax .c { color: #60a0b0; font-style: italic } /* Comment */ .syntax .err { border: 1px solid #FF0000 } /* Error */ .syntax .k { color: #007020; font-weight: bold } /* Keyword */ .syntax .o { color: #666666 } /* Operator */ .syntax .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */ .syntax .cp { color: #007020 } /* Comment.Preproc */ .syntax .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */ .syntax .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */ .syntax .gd { color: #A00000 } /* Generic.Deleted */ .syntax .ge { font-style: italic } /* Generic.Emph */ .syntax .gr { color: #FF0000 } /* Generic.Error */ .syntax .gh { color: #000080; font-weight: bold } /* Generic.Heading */ .syntax .gi { color: #00A000 } /* Generic.Inserted */ .syntax .go { color: #404040 } /* Generic.Output */ .syntax .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ .syntax .gs { font-weight: bold } /* Generic.Strong */ .syntax .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ .syntax .gt { color: #0040D0 } /* Generic.Traceback */ .syntax .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ .syntax .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ .syntax .kp { color: #007020 } /* Keyword.Pseudo */ .syntax .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ .syntax .kt { color: #902000 } /* Keyword.Type */ .syntax .m { color: #40a070 } /* Literal.Number */ .syntax .s { color: #4070a0 } /* Literal.String */ .syntax .na { color: #4070a0 } /* Name.Attribute */ .syntax .nb { color: #007020 } /* Name.Builtin */ .syntax .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ .syntax .no { color: #60add5 } /* Name.Constant */ .syntax .nd { color: #555555; font-weight: bold } /* Name.Decorator */ .syntax .ni { color: #d55537; font-weight: bold } /* Name.Entity */ .syntax .ne { color: #007020 } /* Name.Exception */ .syntax .nf { color: #06287e } /* Name.Function */ .syntax .nl { color: #002070; font-weight: bold } /* Name.Label */ .syntax .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ .syntax .nt { color: #062873; font-weight: bold } /* Name.Tag */ .syntax .nv { color: #bb60d5 } /* Name.Variable */ .syntax .ow { color: #007020; font-weight: bold } /* Operator.Word */ .syntax .w { color: #bbbbbb } /* Text.Whitespace */ .syntax .mf { color: #40a070 } /* Literal.Number.Float */ .syntax .mh { color: #40a070 } /* Literal.Number.Hex */ .syntax .mi { color: #40a070 } /* Literal.Number.Integer */ .syntax .mo { color: #40a070 } /* Literal.Number.Oct */ .syntax .sb { color: #4070a0 } /* Literal.String.Backtick */ .syntax .sc { color: #4070a0 } /* Literal.String.Char */ .syntax .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ .syntax .s2 { color: #4070a0 } /* Literal.String.Double */ .syntax .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ .syntax .sh { color: #4070a0 } /* Literal.String.Heredoc */ .syntax .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ .syntax .sx { color: #c65d09 } /* Literal.String.Other */ .syntax .sr { color: #235388 } /* Literal.String.Regex */ .syntax .s1 { color: #4070a0 } /* Literal.String.Single */ .syntax .ss { color: #517918 } /* Literal.String.Symbol */ .syntax .bp { color: #007020 } /* Name.Builtin.Pseudo */ .syntax .vc { color: #bb60d5 } /* Name.Variable.Class */ .syntax .vg { color: #bb60d5 } /* Name.Variable.Global */ .syntax .vi { color: #bb60d5 } /* Name.Variable.Instance */ .syntax .il { color: #40a070 } /* Literal.Number.Integer.Long */ cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/print.css000066400000000000000000000017211231323242300222110ustar00rootroot00000000000000/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */ .slide, ul {page-break-inside: avoid; visibility: visible !important;} h1 {page-break-after: avoid;} body {font-size: 12pt; background: white;} * {color: black;} #slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;} #slide0 h3 {margin: 0; padding: 0;} #slide0 h4 {margin: 0 0 0.5em; padding: 0;} #slide0 {margin-bottom: 3em;} h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;} .extra {background: transparent !important;} div.extra, pre.extra, .example {font-size: 10pt; color: #333;} ul.extra a {font-weight: bold;} p.example {display: none;} #header {display: none;} #footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;} #footer h2, #controls {display: none;} /* The following rule keeps the layout stuff out of print. Remove at your own risk! */ .layout, .layout * {display: none !important;} cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/s5-core.css000066400000000000000000000006121231323242300223300ustar00rootroot00000000000000/* Do not edit or override these styles! The system will likely break if you do. */ div#header, div#footer, div#controls, .slide {position: absolute;} html>body div#header, html>body div#footer, html>body div#controls, html>body .slide {position: fixed;} .handout {display: none;} .layout {display: block;} .slide, .hideme, .incremental {visibility: hidden;} #slide0 {visibility: visible;} cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/slides.css000066400000000000000000000003561231323242300223430ustar00rootroot00000000000000@import url(s5-core.css); /* required to make the slide show run at all */ @import url(framing.css); /* sets basic placement and size of slide components */ @import url(pretty.css); /* stuff that makes the slides look better than blah */cython-0.20.1+git90-g0e6e38e/Doc/s5/ui/default/slides.js000066400000000000000000000365271231323242300222000ustar00rootroot00000000000000// S5 v1.1 slides.js -- released into the Public Domain // // Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information // about all the wonderful and talented contributors to this code! var undef; var slideCSS = ''; var snum = 0; var smax = 1; var incpos = 0; var number = undef; var s5mode = true; var defaultView = 'slideshow'; var controlVis = 'visible'; var isIE = navigator.appName == 'Microsoft Internet Explorer' ? 1 : 0; var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0; var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0; function hasClass(object, className) { if (!object.className) return false; return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1); } function hasValue(object, value) { if (!object) return false; return (object.search('(^|\\s)' + value + '(\\s|$)') != -1); } function removeClass(object,className) { if (!object) return; object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2); } function addClass(object,className) { if (!object || hasClass(object, className)) return; if (object.className) { object.className += ' '+className; } else { object.className = className; } } function GetElementsWithClassName(elementName,className) { var allElements = document.getElementsByTagName(elementName); var elemColl = new Array(); for (var i = 0; i< allElements.length; i++) { if (hasClass(allElements[i], className)) { elemColl[elemColl.length] = allElements[i]; } } return elemColl; } function isParentOrSelf(element, id) { if (element == null || element.nodeName=='BODY') return false; else if (element.id == id) return true; else return isParentOrSelf(element.parentNode, id); } function nodeValue(node) { var result = ""; if (node.nodeType == 1) { var children = node.childNodes; for (var i = 0; i < children.length; ++i) { result += nodeValue(children[i]); } } else if (node.nodeType == 3) { result = node.nodeValue; } return(result); } function slideLabel() { var slideColl = GetElementsWithClassName('*','slide'); var list = document.getElementById('jumplist'); smax = slideColl.length; for (var n = 0; n < smax; n++) { var obj = slideColl[n]; var did = 'slide' + n.toString(); obj.setAttribute('id',did); if (isOp) continue; var otext = ''; var menu = obj.firstChild; if (!menu) continue; // to cope with empty slides while (menu && menu.nodeType == 3) { menu = menu.nextSibling; } if (!menu) continue; // to cope with slides with only text nodes var menunodes = menu.childNodes; for (var o = 0; o < menunodes.length; o++) { otext += nodeValue(menunodes[o]); } list.options[list.length] = new Option(n + ' : ' + otext, n); } } function currentSlide() { var cs; if (document.getElementById) { cs = document.getElementById('currentSlide'); } else { cs = document.currentSlide; } cs.innerHTML = '' + snum + '<\/span> ' + '\/<\/span> ' + '' + (smax-1) + '<\/span>'; if (snum == 0) { cs.style.visibility = 'hidden'; } else { cs.style.visibility = 'visible'; } } function go(step) { if (document.getElementById('slideProj').disabled || step == 0) return; var jl = document.getElementById('jumplist'); var cid = 'slide' + snum; var ce = document.getElementById(cid); if (incrementals[snum].length > 0) { for (var i = 0; i < incrementals[snum].length; i++) { removeClass(incrementals[snum][i], 'current'); removeClass(incrementals[snum][i], 'incremental'); } } if (step != 'j') { snum += step; lmax = smax - 1; if (snum > lmax) snum = lmax; if (snum < 0) snum = 0; } else snum = parseInt(jl.value); var nid = 'slide' + snum; var ne = document.getElementById(nid); if (!ne) { ne = document.getElementById('slide0'); snum = 0; } if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;} if (incrementals[snum].length > 0 && incpos == 0) { for (var i = 0; i < incrementals[snum].length; i++) { if (hasClass(incrementals[snum][i], 'current')) incpos = i + 1; else addClass(incrementals[snum][i], 'incremental'); } } if (incrementals[snum].length > 0 && incpos > 0) addClass(incrementals[snum][incpos - 1], 'current'); ce.style.visibility = 'hidden'; ne.style.visibility = 'visible'; jl.selectedIndex = snum; currentSlide(); number = 0; } function goTo(target) { if (target >= smax || target == snum) return; go(target - snum); } function subgo(step) { if (step > 0) { removeClass(incrementals[snum][incpos - 1],'current'); removeClass(incrementals[snum][incpos], 'incremental'); addClass(incrementals[snum][incpos],'current'); incpos++; } else { incpos--; removeClass(incrementals[snum][incpos],'current'); addClass(incrementals[snum][incpos], 'incremental'); addClass(incrementals[snum][incpos - 1],'current'); } } function toggle() { var slideColl = GetElementsWithClassName('*','slide'); var slides = document.getElementById('slideProj'); var outline = document.getElementById('outlineStyle'); if (!slides.disabled) { slides.disabled = true; outline.disabled = false; s5mode = false; fontSize('1em'); for (var n = 0; n < smax; n++) { var slide = slideColl[n]; slide.style.visibility = 'visible'; } } else { slides.disabled = false; outline.disabled = true; s5mode = true; fontScale(); for (var n = 0; n < smax; n++) { var slide = slideColl[n]; slide.style.visibility = 'hidden'; } slideColl[snum].style.visibility = 'visible'; } } function showHide(action) { var obj = GetElementsWithClassName('*','hideme')[0]; switch (action) { case 's': obj.style.visibility = 'visible'; break; case 'h': obj.style.visibility = 'hidden'; break; case 'k': if (obj.style.visibility != 'visible') { obj.style.visibility = 'visible'; } else { obj.style.visibility = 'hidden'; } break; } } // 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/) function keys(key) { if (!key) { key = event; key.which = key.keyCode; } if (key.which == 84) { toggle(); return; } if (s5mode) { switch (key.which) { case 10: // return case 13: // enter if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; if (key.target && isParentOrSelf(key.target, 'controls')) return; if(number != undef) { goTo(number); break; } case 32: // spacebar case 34: // page down case 39: // rightkey case 40: // downkey if(number != undef) { go(number); } else if (!incrementals[snum] || incpos >= incrementals[snum].length) { go(1); } else { subgo(1); } break; case 33: // page up case 37: // leftkey case 38: // upkey if(number != undef) { go(-1 * number); } else if (!incrementals[snum] || incpos <= 0) { go(-1); } else { subgo(-1); } break; case 36: // home goTo(0); break; case 35: // end goTo(smax-1); break; case 67: // c showHide('k'); break; } if (key.which < 48 || key.which > 57) { number = undef; } else { if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; if (key.target && isParentOrSelf(key.target, 'controls')) return; number = (((number != undef) ? number : 0) * 10) + (key.which - 48); } } return false; } function clicker(e) { number = undef; var target; if (window.event) { target = window.event.srcElement; e = window.event; } else target = e.target; if (target.getAttribute('href') != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object')) return true; if (!e.which || e.which == 1) { if (!incrementals[snum] || incpos >= incrementals[snum].length) { go(1); } else { subgo(1); } } } function findSlide(hash) { var target = null; var slides = GetElementsWithClassName('*','slide'); for (var i = 0; i < slides.length; i++) { var targetSlide = slides[i]; if ( (targetSlide.name && targetSlide.name == hash) || (targetSlide.id && targetSlide.id == hash) ) { target = targetSlide; break; } } while(target != null && target.nodeName != 'BODY') { if (hasClass(target, 'slide')) { return parseInt(target.id.slice(5)); } target = target.parentNode; } return null; } function slideJump() { if (window.location.hash == null) return; var sregex = /^#slide(\d+)$/; var matches = sregex.exec(window.location.hash); var dest = null; if (matches != null) { dest = parseInt(matches[1]); } else { dest = findSlide(window.location.hash.slice(1)); } if (dest != null) go(dest - snum); } function fixLinks() { var thisUri = window.location.href; thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length); var aelements = document.getElementsByTagName('A'); for (var i = 0; i < aelements.length; i++) { var a = aelements[i].href; var slideID = a.match('\#slide[0-9]{1,2}'); if ((slideID) && (slideID[0].slice(0,1) == '#')) { var dest = findSlide(slideID[0].slice(1)); if (dest != null) { if (aelements[i].addEventListener) { aelements[i].addEventListener("click", new Function("e", "if (document.getElementById('slideProj').disabled) return;" + "go("+dest+" - snum); " + "if (e.preventDefault) e.preventDefault();"), true); } else if (aelements[i].attachEvent) { aelements[i].attachEvent("onclick", new Function("", "if (document.getElementById('slideProj').disabled) return;" + "go("+dest+" - snum); " + "event.returnValue = false;")); } } } } } function externalLinks() { if (!document.getElementsByTagName) return; var anchors = document.getElementsByTagName('a'); for (var i=0; i' + '