Pyrex-0.9.8.5/.hgtags0000644001243100001200000000036311055216101014334 0ustar00gregadmin00000000000000588a14055d1691eb3d0a14d69be108c6110fcee7 0.9.8 66ff407aae9ec4fba986bfdbc6686f1eb7016dce 0.9.8.2 37554acbb702072bdefef51980be33c551e38895 0.9.8.3 ac76d2c45aa1f7055b6101064eac30cfb648a350 0.9.8.4 ac4da2723c96ef0ffc792d9a763638a62e103426 0.9.8.5 Pyrex-0.9.8.5/bin/pyrexc0000755001243100001200000000017010556551457015107 0ustar00gregadmin00000000000000#!/usr/bin/env python # # Pyrex -- Main Program, Unix # from Pyrex.Compiler.Main import main main(command_line = 1) Pyrex-0.9.8.5/bin/pyrexc2.50000755001243100001200000000017310676711275015336 0ustar00gregadmin00000000000000#!/usr/bin/env python2.5 # # Pyrex -- Main Program, Unix # from Pyrex.Compiler.Main import main main(command_line = 1) Pyrex-0.9.8.5/bin/run_tests_2.50000755001243100001200000000016710702360311016171 0ustar00gregadmin00000000000000#!/usr/bin/env python2.5 # # runtests -- Run all the tests. # from Pyrex.Testing import Testing Testing.run_tests() Pyrex-0.9.8.5/bin/update_references0000755001243100001200000000250310556551457017262 0ustar00gregadmin00000000000000#!/usr/bin/env python # # Go through the Tests directory and its subdirectories # copying the latest versions of the test outputs into # the Reference directories. # import os, sys ignore_names = [".DS_Store", "Icon\r"] def copy_file(from_path, to_path): # We copy the contents from one file to the other # so as to preserve metadata on the Mac. #print from_path, "-->", to_path f = open(from_path) g = open(to_path, "w+") g.write(f.read()) f.close() g.close() def update_references(out_dir, ref_dir): for name in os.listdir(ref_dir): if name not in ignore_names: out_file = os.path.join(out_dir, name) ref_file = os.path.join(ref_dir, name) if os.path.isfile(out_file): print "Updating", name copy_file(out_file, ref_file) def update_references_in_dir(dir): print "Updating references in", dir for name in os.listdir(dir): if name <> "Reference" and not name.startswith("("): item_path = os.path.join(dir, name) if os.path.isdir(item_path): update_references_in_dir(item_path) ref_dir = os.path.join(dir, "Reference") if os.path.isdir(ref_dir): update_references(dir, ref_dir) def main(): bin_dir = os.path.dirname(sys.argv[0]) source_dir = os.path.dirname(bin_dir) tests_dir = os.path.join(source_dir, "Tests") update_references_in_dir(tests_dir) if __name__ == "__main__": main() Pyrex-0.9.8.5/CHANGES.txt0000644001243100001200000014773311055176247014724 0ustar00gregadmin000000000000000.9.8.5 ------- Bug fixes: - Function export code was erroneously generated for 'extern' functions declared in a .pxd file. [Sebastian Sable] - The 'api' option was not recognised with 'ctypedef public class'. [Lisandro Dalcin] - MACOSX_DEPLOYMENT_TARGET is no longer set unless the undocumented -X option is being used. Hopefully this will prevent complaints about it from distutils. [Martin Field] - Recognize MS_WINDOWS as well as WIN32. [Alexander Belchenko] - Hexadecimal compile-time constants did not work. [Devan] Enhancements: - Dependency files (.dep) are only created when compiling with timestamp checking or recursion enabled. Deprecations: - The features introducted in 0.9.8 and 0.9.8.1 for cross-forward-declaring extension types between .pxd files turn out to be unnecessary, since the circular import problems they are aimed at can be avoided using ordinary forward delcarations in the .pxd files ahead of any cimports. 0.9.8.4 ------- Bug fixes: - Incorrect code generated for Python indexing with an unsigned int. [Christopher Williams] 0.9.8.3 ------- Bug fixes: - Compiling multiple source files at once should work as advertised now. - Assignment of a nogil function to a non-nogil function pointer is now allowed. - Applying += or -= to a pointer and an integer did not work. [Arc Riley] - Compiling a .pyx file whose name is not a valid module name now reports an error instead of generating invalid C code. [Robert Bradshaw] - Integer indexing optimisation now performed only for signed index types, to avoid change of semantics with index values greater than the maximum positive signed int value. [Robert Bradshaw] - Non-void function declared 'except *' could produce C compiler warning about uninitialised variable. [Lisandro Dalcin] 0.9.8.2 ------- Enhancements: - A block of external functions can be declared nogil at once. cdef extern from "somewhere.h" nogil: ... Bug fixes: - The nogil attribute was not being checked for a match when comparing function signatures. - Improved error message for C method signature mismatch between a class and its base class. Bug workarounds: - Multiple source files passed to Main.compile are being compiled in separate contexts for the time being until I can sort out a problem. You probably won't notice any difference except that there will be no speed advantage over compiling them separately. 0.9.8.1 ------- Enhancements: - It is no longer necessary to specify the base class of an extension type in a forward declaration. Also, if the class is defined in a .pxd file, the base class only needs to be specified in the .pxd file, not the .pyx file. [Arc Riley] - There's now an even easier way to forward-declare a struct, union or extension type in another module: from blarg cimport class Foo This simultaneously cimports the name Foo and forward-declares it as an extension type. As well as 'class', you can also use 'struct' or 'union'. Modifications: - Casting a non-Python pointer type to a Python type no longer generates an incref, unless one is required for other reasons. [Arc Riley] - More checks added for gil-requiring operations performed without holding the gil. 0.9.8 ----- New features: * Augmented assignment operators (+=, etc.) are now supported. * Package directories Modules in packages no longer need to have dotted names. Instead, a Python-like package directory structure can be used, with package dirs marked by containing an __init__.py or __init__.pyx. Top-level package directories are found by searching the include directories specified by -I options (analogous to PYTHONPATH). * Dependency tracking The Pyrex compiler records information about other source files cimported or included, and can automatically compile all the modules a given module depends on, with timestamp checking. This is enabled by a -r (recursive) option to the compiler, e.g. pyrexc -r mainmodule.pyx There are also two other new command-line options: -t Enable timestamp checking. This is implied with -r. -f Overrides implied -t when using -r and forces all dependent modules to be compiled regardless of timestamps. * Nogil restrictions relaxed C functions declared nogil can now have Python objects as arguments. The argument names are read-only inside the function when this is done. Among other things, this allows C methods to be declared nogil (this couldn't be done before because 'self' is always an object argument). * Circular cimports There is now a way of forward-declaring a struct, union or extension type into another module. This allows two .pxd files to define extension types that refer to each other without running into circular import problems. For example: cimport blarg cdef class blarg.Blarg # Forward declaration cdef class Foo: cdef blarg.Blarg blg 0.9.7.2 ------- Bug fixes: - Another integer indexing problem fixed. 0.9.7.1 ------- Bug fixes: - The optimisation for indexing using a C int failed when the object being indexed was a mapping rather than a sequence. [Arc Riley] Modifications: - Old integer for-loop syntax is no longer deprecated. 0.9.7 ----- New features: - Builtin constants and types are known, and are referenced directly with no dictionary lookup. - Direct calls are made to certain methods of lists and dicts when their type is statically known. - New builtin functions 'typecheck' and 'issubtype' added, providing safer type checking than isinstance and issubclass (which can be overridden). Enhancements: - Redundant type test eliminated when assigning the result of an extension type constructor call to a variable of the same type. - No tp_traverse and tp_clear functions generated for types without Python attributes. - Safer code generated in tp_clear. [Stefan Behnel] - Indexing with a C int type generates calls to PySequence_GetItem and PySequence_SetItem. - Integer for-loop syntax streamlined to 'for x < i < y'. - Appropriate C code generated for compile-time expressions evaluating to float nan, inf and -inf. [Stefan Behnel] Bug fixes: - Value raised by assert statement now only evaluated if the assertion fails. [Stefan Behnel] - Comparing a value of an enum type with another value of a type which is ctypedefed to the same enum type gave a spurious type error. [Matt Hammond] - Comparing an int with a float resulted in the float being cast to an int before comparison. [Robin Becker] - Compiler crashed on an invalid argument to a 'with nogil' statement. [Stefan Behnel] - Incorrect code generated for function with keyword only args and no * or ** args. [Stefan Behnel] - GC type with non-GC base type caused crash due to trying to call non-existent base tp_traverse and tp_clear functions. [Stefan Behnel] - Compile-time IF with no ELSE clause crashed compiler. [Kirk McDonald] - Values in enum declaration were not being checked for appropriate type. [Simon Burton] - Improved the error message from attempting to declare a struct or union member as a function. [Yong Sun] - Referring to an undefined name in a compile-time constant crashed the compiler. [Stefan Behnel] 0.9.6.4 ------- Bug fixes: - Errors in setup.py corrected. - Incorrect error checking code generated for builtin functions and type slots with return type Py_ssize_t. [Robert Bradshaw] - A counted reference was not kept to the module, so if the entry in sys.modules was replaced, the module was freed prematurely. [Franck Pommerau] - A cimport statement inside a function crashed the compiler. [Robert Bradshaw] - __Pyx_ImportModule routine wasn't protected from multiple definition when including _api.h files. [Stefan Behnel] - Temp variables holding exception values were not being set to NULL after use in an except clause. [Robert Bradshaw] - Protect __stdcall and __cdecl from redefinition. [Jim Kleckner] - A temp var was not being set to NULL after api function import code. [Stefan Behnel] - __Pyx_ImportFunction was incorrectly decrefing a borrowed reference. [Stefan Behnel] Enhancements: - Functions declared with_gil and external functions declared nogil are now allowed to have Python arguments and return types. 0.9.6.3 ------- Enhancements: - C API now only uses a single name in the module namespace instead of one for each exported C function. [Stefan Behnel] - Multiple declarations with the same visibility and api options can now be grouped into a 'cdef' block. - The 'api' keyword can now be used on extension types to cause generation of an api.h file when there are no exported C functions. - Added a getattr3() builtin for the three-argument form of getattr. Bug fixes: - Setup.py no longer uses an import to get the version number being installed, to avoid a problem with setuptools. - If a struct or union was forward-declared, certain types of error message misleadingly referenced the source location of the forward declaration rather than the definition. - Calling convention specifier was being emitted in function prototypes but not the corresponding definitions. [Atsuo Ishimoto] - Added support for the --force option to Pyrex.Distutils. [Alexander Belchenko] - Compile-time "==" operator did not work. [Simon King] - Header files generated for public and api declarations now only contain types declared as 'public', instead of all types defined in the module. [Stefan Behnel] 0.9.6.2 ------- Bug fixes: - Corrected a problem with declaration ordering in generated C code involving forward-declared struct, union or extension types. - New distutils extension: Only compile .pyx if it is newer than the corresponding .c file. 0.9.6.1 ------- Bug fixes: - Changed os.uname to platform.uname for portability. [Alexander Belchenko] - Fixed C compiler warning about incompatible types in 2.5. [Alexander Belchenko] - Also fixed a few other 2.5 problems. - Fixed problem with the Extension class in the new Pyrex.Distutils module. 0.9.6 ----- New Features: - Top-level C functions defined in one module can now be used in another via cimport, and a C API can be produced to allow them to be used from C code without linking to the extension module. See "Interfacing with External C Code" and "Sharing Declarations between Pyrex Modules" in the Language Overview. [Stefan Behnel] - Facilities added for releasing the GIL around a section of code and acquiring it on entry to a C function. See "Acquiring and Releasing the GIL under "Interfacing with External C Code" in the Language Overview. [Ulisses Furquim, Stefan Behnel] - Some conditional compilation facilities have been added. See "Conditional Compilation" under "Language Basics" in the Language Overview. [Sam Rushing] Language Changes: - The __new__ special method of extension types is being renamed to "__cinit__". For now, you will get a warning whenever you declare a __new__ method for an extension type, and it will automatically be renamed to __cinit__ for you. In the next release, the warning will become an error and no renaming will occur. In some later release, the __new__ method may be re-introduced with different semantics. It is recommended that you begin updating your sources now to use __cinit__. - A 'raise' statement with no arguments (i.e. to re-raise the last exception caught) is now required to be lexically within the 'except' clause which caught the exception. This change was necessary to efficiently support preserving the exception if an intervening call raises and catches a different exception. - The following new reserved words have been added: with, DEF, IF, ELIF, ELSE Enhancements: - Calls to many of the builtin functions are now compiled as direct calls to Python/C API routines. - A C type explicitly declared as 'signed' is represented as such in the generated code, to acommodate platforms where 'char' is unsigned by default. [Francesc Altet] - Python function can now have an argument of type "unsigned char". [Alexander Belchenko] - A new Pyrex.Distutils implementation has been added, which exports an Extension type supporting the following options: pyrex_include_dirs - list of dirs to search for Pyrex header files pyrex_create_listing_file - bool - write errs to listing file pyrex_cplus - bool - generate C++ code pyrex_c_in_temp - bool - put generated C files in temp dir pyrex_gen_pxi - bool - generate .pxi file for public declarations [Contributed by Billie G. Allie] - Assert statements can be compiled out by arranging for PYREX_WITHOUT_ASSERTIONS to be #defined at C compilation time. [Contributed by Stefan Behnel] - Support for __index__ slot added to extension types. [William Stein] - Exception types now properly checked according to pre or post 2.5 rules as appropriate. - Py_ssize_t support added. [Stefan Behnel] - Windows __stdcall and __cdecl qualifiers now supported. [Suggested by Eric Devolder] - Keyword-only argument support added. [Suggested by Stefan Behnel] - An 'include' statement can now appear anywhere that another kind of statement or declaration can appear, instead of being restricted to the top level. [Caio Marcelo] - Unnecessary PyErr_Occurred() call to check result of PyString_AsString() no longer made. - Complicated C types are displayed more readably in error messages. Modifications: - A Python function argument declared as "char" or "unsigned char" now expects a Python integer rather than a string of length 1, for consistency with the way automatic conversions are done elsewhere. - Support for string and tuple exceptions dropped. Bug fixes: - If an external ctypedef type was used as the type of an argument to a Python function, a declaration was generated using the underlying type rather than the typedef name. [Francesc Altet] - Some problems with int/enum and pointer/array compatibility fixed. [Eric Huss, Stefan Behnel, Jiba] - Eliminated C compiler warning when comparing an extension type reference to None using 'is' or 'is not' - Eliminated C compiler warnings about docstrings of C functions and special methods being unused. [Francesc Altet] - When compiling with -O, raising an exception in a C function that couldn't propagate exceptions produced a compiler warning about the return value possibly being uninitialised. - Fixed warning about function declaration not being a prototype caused by C method table initialisation code. - Spurious initialisation was generated for unused local variable. [Helmut Jarausch] - Declaration of a non-extern C function without definition was not detected. [Lenard Lindstrom] - Applying ** directly to two C int types is now disallowed due to ambiguity (it's not clear whether to use C pow() or convert to Python ints). [Didier Deshommes] - Traverse and clear code was being inadvertently generated for the __weakref__ slot of a weakly-referenceable extension type. [Peter Johnson] - Statements other than def inside a property declaration were crashing the compiler. [Sven Berkvens] - Defining an extension type with different visibility from its declaration in a .pxd file crashed the compiler. [Alex Coventry] - Instantiating an exception type whose base class __new__ method raises an exception caused a segfault. [Gustavo Sverzut Barbieri] - The 'import pkg.module as name' form of import statement did not work correctly. [Dan] - Fixed error-checking typo in __Pyx_GetStarArgs(). [Eric Huss] - Trailing comma now allowed on argument list. [Jim Kleckner] - Behaviour of reraise made to match Python more closely. [Eric Huss] - An empty C variable declaration crashed the compiler. - Now includes math.h instead of generating own declaration of pow(). [Leif Strand] - Missing import of sys in LinuxSystem.py added. [Scott Jackson] - Typecasts using a ctypedef type were not using the ctypedef name. [Alexander Belchenko] - Workaround added to setup.py for a problem with bdist_wininst. [Alexander Belchenko] - Subtle error in parsing empty function declarators corrected. - Checks added for some type combinations that are illegal in C: array of functions, function returning function or array, cast to a function. 0.9.5.1a -------- Bug fixes: - Package list now calculated dynamically in setup.py so that it will work with or without the testing framework installed. 0.9.5.1 ------- Bug fixes: - Comparing two values of the same enum type incorrectly produced an error. [Anders Gustafsson] - Compiler crash caused by assigning a Python value to a variable of an enum type. [Peter Johnson] - Comparison between pointer and array incorrectly produced a type mismatch error. [Helmut Jarausch] - Unused local Python variable had spurious init/cleanup code generated for it, causing C compilation errors. [Helmut Jarausch] - Updated list of packages in setup.py. Modifications: - NULL in Pyrex source now translated into NULL instead of 0 in C code, to allow for the possibility of calling something not defined with a prototype in an external header. [Adapted Cat] 0.9.5 ----- Enhancements: - Exception return values may now be specified by arbitrary constant expressions of appropriate type, not just literals. [Stefan Behnel] - Redundant type check now omitted when passing a literal None to a function expecting an extension type. [Patch by Sam Rushing] - New-style classes now allowed as exceptions for compatibility with Python 2.5 (inheritance from BaseException not currently checked). [Stefan Behnel] - Sequence unpacking is now done using the iterator protocol instead of indexing. - Allocation of an empty tuple is avoided when making a Python call with no arguments. [Stefan Behnel] - Most warnings about unused variables and labels have been eliminated. - Support for running the test suite on Linux added but not yet fully tested. [Based in part on patch by Eric Wald]. - Makefile included for compiling the patched Carbon File module used by the MacOSX test code. Modifications: - Type rules for enums tightened for compatibility with C++. - Direct assignment from float to int disallowed to prevent C++ compilation warnings. - Hex literals left as hex in C code to avoid warnings from the C compiler about decimal constants becoming unsigned. Bug fixes: - Exception raised during argument conversion could cause crash due to uninitialised local variables. [Konrad Hinsen] - Assignment to a C attribute of an extension type from a different type could generate C code with a pointer type mismatch. [Atsuo Ishimoto] - Backslash in a string literal before a non-special character was not handled correctly. [Yuan Mang] - Temporary vars used by del statement not being properly released, sometimes leading to double decrefs. [Jiba] - A return statement whose expression raises an exception inside a try-except that catches the exception could cause a crash. [Anders Gustafsson] - Fixed type compatibility checking problem between pointers and arrays. [Lenard Lindstrom] - Circular imports between modules defining extension types caused unresolvable import order conflicts. [Mike Wyatt] - Cimporting multiple submodules from the same package caused a redefined name error for the top level name. [Martin Albrecht] - Incorrect reference counting when assigning to an element of an array that is a C attribute of an extension type. [Igor Khavkine] - Weak-referenceable extension types were not implemented properly. [Chris Perkins, Peter Johnson] - Crash if C variable declared readonly outside an extension type definition. [Eric Huss] Doc updates: - Expanded discussion of the need for type declarations to enable access to attributes of extension types. - Added a section "Source Files and Compilation" explaining the rules for naming of source files of modules residing in packages, and instructions for using the compiler and distutils extension. 0.9.4.1 ------- Bug fixes: - Fixed indentation problem in Pyrex.Distutils.build_ext. [Oliver Grisel] 0.9.4 ----- Improvements: - All use of lvalue casts has been eliminated, for compatibility with gcc4. - PyMODINIT_FUNC now used to declare the module init function. - Generated code should be compilable as either C or C++. When compiling as C++, "extern C" is used where appropriate to preserve linkage semantics. - An extension type can be made weak-referenceable by giving it a C attribute of type object called __weakref__. - Source files opened in universal newlines mode. - Support for public extension type C attributes of type long long and unsigned long long added (but not tested). [Sam Rushing] - Distutils include directories now passed to Pyrex compiler. [Konrad Hinsen] - Integer constants with an "L" suffix are now allowed and are converted to Python long integers. [Rainer Deyke] - A broken .c file is no longer left behind if there are compilation errors. - Using the result of a Python indexing or attribute access operation as a char * is no longer considered an error in most cases, as the former behaviour proved to be more annoying than helpful. Bug fixes: - Fixed problems with conversion from Python integers to C unsigned longs. Now use PyInt_AsUnsignedLongMask and PyInt_AsUnsignedLongLongMask instead of the PyLong_* functions (which only work on Python longs). [Wim Vree] - C unsigned ints now converted to/from Python longs intead of Python ints to avoid overflow problems. [Heiko Wundram] - Correct PyArg_ParseTuple format characters now used for unsigned types. [Jeff Bowden] - Nonzero return value from a base class tp_traverse call is handled. - Taking sizeof an incomplete type caused a crash while producing an error message. [Drew Perttula] - If a module cimported itself, definitions of global variables were generated twice. [Parzival Herzog] - Distutils extension updated to handle changed signature of swig_sources(). [David M. Cooke] - Incorrect C code generated for a raw string containing a double quote preceded by a backslash. [Thomas Drake] - Declaration of public C function with an exception value written to generated .pxi file without the except clause. [Robby Dermody] - __delitem__ method of an extension type with no __setitem__ did not get called. [Richard Boulton] - A spurious Py_INCREF was generated when a return statement required a type test. [Jonathan Doda] - Casting a value to a function pointer and then immediately calling it generated a cast to a function instead of a cast to a function pointer. [Simon Burton] - Py_TPFLAGS_HAVE_GC was not being set on an extension type that inherited from an external extension type that used GC but did not itself have any PyObject* attributes. [Michael Hordijk] - A return statement inside a for statement leaked a reference to the loop's iterator. [Jürgen Kartnaller] - Full module name now appears in __module__ attribute of classes and extension types, provided a correct dotted name is used for the .pyx file. [Giovanni Bajo] - Public extension type with no C attributes produced an invalid .pxi file. [Simon Burton] - Using a dict constructor as the second operand of a boolean expression crashed the Pyrex compiler. [Stefan Behnel] - A C declaration list ending with a comma resulted in invalid C code being generated. [Alex Coventry] - A raw string containing two consecutive backslashes produced incorrect C code. [Helmut Jarausch] - An error is reported if you attempt to declare a special method of an extension type using 'cdef' instead of 'def'. [Sam Rushing] 0.9.3 ----- Enhancements: - Types defined with a ctypedef in a 'cdef extern from' block are now referred to by the typedef name in generated C code, so it is no longer necessary to match the type in the C header file exactly. - Conversion to/from unsigned long now done with PyLong_AsUnsignedLong and PyLong_FromUnsignedLong. [Dug Song] - A struct, union or enum definition in a 'cdef extern from' block may now be left empty (using 'pass'). This can be useful if you need to declare a variable of that type, but don't need to refer to any of its members. - More flexible about ordering of qualifiers such as 'long' and 'unsigned'. ["John (J5) Palmieri"] Bug fixes: - Non-interned string literals used in a Python class definition did not work. [Atsuo Ishimoto, Andreas Kostyrka] - Return types of the buffer interface functions for extension types have been corrected. [Dug Song] - Added 'static' to declarations of string literals. [Phil Frost] - Float literals are now copied directly to the C code as written, to avoid problems with loss of precision. [Mario Pernici] - Inheriting from an extension type with C methods defined in another Pyrex module did not work. [Itamar Shtull-Trauring] 0.9.2.1 ------- Bug fixes: - Corrected an import statement setup.py, and made it check for a unix platform in a more reliable way. 0.9.2 ----- Enhancements: - Names of Python global variables and attributes are now interned, and PyObject_GetAttr/SetAttr are used instead of PyObject_GetAttrString/SetAttrString. String literals which resemble Python identifiers are also interned. - String literals are now converted to Python objects only once instead of every time they are used. - NUL characters are now allowed in Python string literals. - Added some missing error checking code to the beginning of module init functions. It's unlikely the operations involved would ever fail, but you never know. Bug fixes: - Corrected some problems introduced by moving the Plex package. 0.9.1.1 ------- Bug fixes: - Corrected a problem in the setup.py (pyrexc script incorrectly named). - Updated the distutils extension to match changes in the Pyrex compiler calling interface. - Doing 'make clean' in Demos/callback was removing a little too much (that's why cheesefinder.c kept disappearing). 0.9.1 ----- Enhancements: - A C method can now call an inherited C method by the usual Python technique. [Jiba] - The __modname__ of a Python class is now set correctly. [Paul Prescod] - A MANIFEST.in file has been added to the distribution to facilitate building rpms. [contributed by Konrad Hinsen] Bug fixes: - Conditional code now generated to allow for the renaming of LONG_LONG to PY_LONG_LONG that occurred between Python 2.2 and 2.3. - Header files referenced in cimported modules were not being included. [Tom Popovich] - References to C functions and variables in a cimported module were not being recognised if made from within a local scope. [Tom Popovich] - Spurious declarations in code generated for a "finally" block. [Brandon Long] - Attempting to return a value from a __contains__ method didn't work. [Andreas Kostyrka] - Incorrect code generated for an extension type with C methods inheriting from a base type with no C methods. [Robin Becker] - Failure to report an error if a C method was defined in the implementation part of an extension type that was not declared in the corresponding definition part. Documentation also updated to explain that this is necessary. [Jiba] - Made it an error to forward-declare an extension type with a different base class specification from its subsequent definition. [Jiba] - C attributes of an extension type were not being propagated through more than one level of inheritance. [Jiba] - If a garbage collection occurred early enough in the __new__ method of an extension type with Python-valued C attributes, a crash could occur in its tp_traverse function. [reported by Jiba, fix suggested by Paul Prescod] - An empty vtable struct is no longer generated for extension types with no C methods. [Robin Becker] - Memory was leaked in the sq_item function of an extension type with a __getitem__ method. [Atsuo Ishimoto] - Code generated to work around a bug in some versions of Python 2.2 which fails to initialise the tp_free slot correctly in some circumstances. [Matthias Baas] - Compiler crash when defining an extension type with a base class specified by a dotted name. [Alain Pointdexter] - Referencing an extension type defined in a cimported module at run time did not work correctly. [Alain Pointdexter] - Incorrect object struct code generated for an extension type whose base class was defined in a .pxd file. [Alain Pointdexter] - Redeclaring a type that wasn't previously an extension type as an extension type caused a compiler crash. [Scott Robinson] - Incorrect code was generated for return statements in a special method with no return value. [Gary Bishop] - Single-line def statement did not work. [Francois Pinard] Modifications: - Only the last pathname component of the .pyx file is reported in backtraces now. [Bryan Weingarten] - Documentation corrected to remove the erroneous statement that extension classes can have a __del__ method. [Bryan Weingarten] - Note added to documentation explaining that it is not possible for an extension type's __new__ method to explicitly call the inherited __new__ method. - The version of Plex included with Pyrex is now installed as a subpackage of the Pyrex package, rather than as a top-level package, so as not to interfere with any other version of Plex the user may have installed. 0.9 --- New features: - Extension types can have properties. See the new "Properties" section in the "Extension Types" page. - An extension type can inherit from a builtin type or another extension type. See "Subclassing" in the "Extension Types" page. - Extension types can have C methods, which can be overridden in derived extension types. See "C Methods" in the "Extension Types" page. Enhancements: - Conversion is now performed between C long longs and Python long integers without chopping to the size of a C long. Also the Python PY_LONG_LONG type is now used for long longs for greater portability. Bug fixes: - Names were sometimes being generated that were insufficiently unique in the presence of cimported declarations. - Changed the way the included filename table is declared from char *[] to char **, to stop MSVC from complaining about it having an unknown size. [Alexander A Naanou] - Second argument of assert statement was not being coerced to a Python value. [Francois Pinard] - Return statement without value wasn't accepted in some extension type special methods when it should have been. [Francois Pinard] - Attempting to call a non-function C value crashed the compiler. [John J Lee] - Functions declared as "except *" were not returning exceptions. [John J Lee] - A syntax warning from Plex about assignment to None has been eliminated. [Gordon Williams] - Public function declaration with empty argument list was producing (void) in .pxi file. [Michael P. Dubner] - Incorrect error signalling code was being generated in the __hash__ special method of an extension type. 0.8.1 ----- Bug fixes: - Names of structs, unions and enums in external header files were getting mangled when they shouldn't have been. [Norman Shelley] - Modified distutils extension so that it will stop before compiling the C file if the Pyrex compiler reports errors. [John J Lee] 0.8 --- New features: - INCOMPATIBLE CHANGE: The type object of an external extension type is now imported at run time using the Python import mechanism. To make this possible, an 'extern' extension type declaration must DECLARE THE MODULE from which the extension type originates. See the new version of the "Extension Types" documentation for details. This change was made to eliminate the need for Pyrex to be told the C name of the type object, or for the Pyrex module to be linked against the object code providing the type object. You will have to update any existing external extension type declarations that you are using. I'm sorry about that, but it was too hard to support both the old and new ways. - Compile-time importing: A Pyrex module can now import declarations from another Pyrex module using the new 'cimport' statement. See the new section on "Sharing Declarations Between Pyrex Modules" in the documentation. Minor improvements: - An error is reported if you declare a struct, union or extension type using 'cdef' in one place and 'ctypedef' in another. - Struct, union and extension types can only be forward- declared using 'cdef', not 'ctypedef' (otherwise invalid C code would be generated). - The 'global' statement can be used at the module level to declare that a name is a module-level name rather than a builtin. This can be used to access module attributes such as __name__ that would otherwise be assumed to be builtins. [Pat Maupin] - The 'assert' statement now accepts a second argument. [Francois Pinard] Bug fixes: - When using Python 2.3, "True" or "False" could sometimes turn up in generated code instead of "1" or "0". [Adam Hixson] - Function return value not always converted to or from a Python object when it should have been. - Certain kinds of error in a function call expression could crash the compiler. ["Edward C. Jones"] - Fixed memory leak in functions with * or ** args. [Alexander A Naanou] 0.7.1 ----- Bug fixes: - Calling a function declared as returning an extension type could crash the compiler. - A function call with type errors in the argument list could crash the compiler. - An 'else' clause on a for-from statement could crash the compiler. - Incorrect casting code was generated when a generic object argument of a special method was declared as being of an extension type. [Phillip J. Eby] - A blank line that couldn't be interpreted wholly as a valid indentation sequence caused a syntax error. In particular, a formfeed character on an otherwise blank line wasn't accepted. [Francois Pinard] - Parallel assignments were incorrectly optimised. - A bare tuple constructor with an extra comma at the end of a line caused a syntax error. 0.7 --- New features: - Attributes of extension types can be exposed to Python code, either read/write or read-only. - Different internal and external names can be specified for C entities. - None is a compile-time constant, and more efficient code is generated to reference it. - Command line options for specifying directories to search for include files. Enhancements: - More efficient code is generated for access to Python valued C attributes of extension types. - Cosmetic code improvement: Less casting back and forth between extension types and PyObject * when referencing C members of the object struct. - C arguments and variables declared as an extension type can take the value None. - Form feed characters are accepted as whitespace. - Function names in tracebacks are qualified with module name and class name. Bug fixes: - A sufficiently complex expression in a boolean context could cause code to be generated twice for the same subexpression. - Incorrect casting code was generated when passing an extension type to a function expecting a generic Python object. - Executable statements are now disallowed inside a cdef class block (previously they silently caused crazy C code to be generated). - Tracebacks should now report the correct filename for functions defined in files included with the 'include' statement. - The documentation incorrectly claimed that an extension type can't have a __del__ method. In fact, it can, and it behaves as expected. 0.6.1 ----- Bug fixes: - Fixed broken distutils extension. 0.6 --- New features: - Command line options for reporting version number, requesting a listing file and specifying the name of the generated C file. - An 'include' statement allows inclusion of declarations from other Pyrex source files. - If there are any public declarations, a Pyrex include file is generated (as well as a .h file) containing declarations for them. - Extension types can be declared public, so their C attributes are visible to other Pyrex and C code. - Try-except statements can now have an 'else' clause. [Francois Pinard] - Multiple simple statements can be placed on one line separated by semicolons. - A suite consisting of a simple statement list can now be placed on the same line after the colon in most cases. [Francois Pinard] - The automatic coercion of a C string to a C char has been removed (it proved to be too error-prone). Instead, there is a new form of literal for C character constants: c'X' - The __get__ special method (used by descriptor objects) now allows for the possibility of the 2nd or 3rd arguments being NULL. Also the __set__ method has been split into two methods, __set__ and __delete__. [Phillip J. Eby] Bug fixes: - Values unpacked into a non-Python destination variable were not being converted before assignment. [Gareth Watts] - Hex constants greater than 0x7fffffff caused compiler to crash. [Gareth Watts] - Type slots are no longer statically initialised with extern function pointers, to avoid problems with some compilers. The hack in the distutils extension to work around this by compiling as C++ has been disabled. [Phillip J. Eby] - Fixed several more instances of the error-reporting routine being called with arguments in the wrong order. Hoping I've *finally* got all of them now... - Nested for-from loops used the same control variable. [Sebastien de Menten] - Fixed some other error message related bugs. [Francois Pinard] - Assigning to slice didn't work. [Francois Pinard] - Temp variables were being declared as extension types and then being assigned PyObject *'s. All Python temp vars are now declared as PyObject *. [Francois Pinard] 0.5 --- Bug fixes: - Algorithm for allocating temp variables redesigned to fix various errors concerning temp variable re-use. [Mark Rowe] - Memory leak occured sometimes when an implicit type test was applied to the result of an expression. [Christoph Wiedemann] - __set__ method of extension types had wrong signature. [Josh Littlefield] 0.4.6 ----- Bug fixes: - Indexing multi-dimensional C arrays didn't work. [Gary Dietachmayer] 0.4.5 ----- New features: - There is now a 'public' declaration for making Pyrex-defined variables and functions available to external C code. A .h file is also generated if there are any public declarations. Enhancements: - Defining __len__/__getitem__ methods in an extension class fills sq_length/sq_item slots as well as mp_length/mp_subscript. [Matthias Baas] - The Distutils extension now allows .c files to be incorporated along with .pyx files. [Modification to Distutils extension contributed by Darrell Gallion] Bug fixes: - Float literals without a decimal point work again now. [Mike Rovner, Peter Lepage] - Compiler crashed if exception value didn't match function return type. [Michael JasonSmith] - The setup.py file should now install the Lexicon.pickle file in the right place. [Patch supplied by David M. Cooke] - Compiler crashed when compiling a C function that returned an extension type. [David M. Cooke] - Anonymous enum types did not have C code suppressed inside an extern-from block. [Matthew Mueller] 0.4.4 ----- Enhancements: - Tracebacks now extend into Pyrex function calls and show line numbers in the Pyrex source file. - Syntax for float literals made more lenient (no longer requires digits both before and after the point). [Peter Lepage] - Method calls can be made on string literals (e.g. ",".join(x)). [Pedro Rodriguez] Bug fixes: - Incorrect refcount code generated when a Python function needing argument type tests had local Python variables. [Matthias Baas] - 'self' parameter of __getitem__ method of extension type had wrong implicit type. [Peter Lepage] - Repaired breakage introduced by trying to allow an empty parameter list to be written as (void). No longer attempting to allow this (too hard to parse correctly). [Peter Lepage] - Found bug in Plex 1.1.2 which was the *real* cause of the two-newlines-in-a-row problem. Removed the Opt(Eol)+Str("\n") hacks in the scanner which were working around this before. [Pedro Rodriguez] - __call__ special method of extension types had wrong signature. [Peter Lepage] 0.4.3 ----- New language features: - For-from loop for iterating over integer ranges, using pure C loop where possible. Enhancements: - sizeof() can now be applied to types as well as variables. - Improved handling of forward-declared extension types. Bug fixes: - Two newlines in a row in a triple quoted string caused a parse error on some platforms. [Matthias Baas] - Fixed problem with break and continue in the else-clause of a loop. 0.4.2 ----- New language features: - C functions can be declared as having an exception return value, which is checked whenever the function is called. If an exception is detected inside a C function for which no exception value is declared, a warning message is printed and the exception is cleared. - Cascaded assignments (i.e. a = b = c are now supported. - Anonymous enum declarations are allowed, for when you just want to declare constants. - The C types "long long" and "long double" are now understood. Also, "int" is optional after "short" or "long". Enhancements: - A * argument in a function call can now be any sequence, not just a tuple. - A C char* or char[] will be turned into a char by taking its first character if used in a context where a char is required, thus allowing a string literal to be used as a char literal. - C string * C int or vice versa is now interpreted as Python string replication. - Function arguments are checked for void or incomplete type. Bug fixes: - Non-external extension types show up in the module dict once more (this got broken in 0.4.1). - A spurious decref has been removed from the runtime support code for the "import" statement. Hopefully this will prevent the crashes some people have been experiencing when importing builtin modules. [Mathew Yeates] 0.4.1 ----- New language features: - "ctypedef struct/union/enum/class" statements added, for use in extern-from blocks when a header file uses a ctypedef to declare a tagless struct, union or enum type. - "pass" allowed in an extern-from block. - "cdef extern from *" for when you don't want to specify an include file name. - Argument names may be omitted in function signatures when they're not needed. - New reserved word NULL for the null C pointer. Compiler enhancements: - Lexicon is now picked in binary format, so startup should be much faster on slower machines. - If Pyrex decides to rebuild the lexicon and then finds that it can't write a pickle file, it now prints a warning and carries on instead of crashing. - Chat about hash codes and lexicon pickling now turned off by default except when creating a new lexicon (which ought never happen now unless you change the scanner). Bug fixes: - Modified the runtime support code for "import" statements, hopefully fixing problem with using a Pyrex module in conjunction with py2exe. - DL_EXPORT now used in both the prototype and definition of the module init function. - Exception state is now saved and restored around calls to an extension type __dealloc__ method, to avoid screwing up if the object is deallocated while an exception is being propagated. - Making an attribute reference to a method of an extension type caused a compiler crash. - Doc string in new-style class definition caused a run-time error. - Insufficient parentheses were put around C type casts. - Constructors for extension types are now read-only C global variables instead of entries in the module dict. This change was needed to prevent Numeric from blowing up due to touching its typeobject before import_numeric() could be called. 0.4 --- New features: - "cdef extern from" statement allows inclusion of C header files to be specified, solving a number of problems including: - Clashes between Pyrex and C declarations, due to "const" and other reasons - Windows-specific features required in function declarations - Helping deal with types such as "size_t" - Helping deal with functions defined as macros - Access to internals of pre-existing extension types is now possible by placing an extension type declaration inside a "cdef extern from" block. Bug fixes: - Error not reported properly when passing wrong number of args to certain special methods of extension types. [Mitch Chapman] - Compile-time crash when defining an extension type with a __hash__ method. Minor enhancements: - Hashing of the scanner source file made more platform-independent, making spurious regeneration of the pickle less likely. 0.3.4 ----- Bug fixes: - Runtime crash when using * or ** args in a method of an extension type fixed. [Matthew Mueller] - Compiler crash when using default argument values in a method of a Python class. [Mike Rovner] Enhancements: - Type slots filled with functions from outside the extension module are now initialised dynamically, which should eliminate at least some of the "initialiser is not constant" problems experienced on Windows. [Marek Baczek] - On Windows, __declspec(dllexport) is now used for the module init func declaration (or should be -- I haven't tested this). [Marek Baczek] - The compiler shouldn't attempt to rewrite the Lexicon.pickle file unless the source has been changed (hashing is used now instead of comparing timestamps). So there should be no problem any more with installing Pyrex read-only. 0.3.3 ----- Bug fixes: * A void * can be assigned from any other pointer type. * File names in error messages no longer quoted (this was apparently confusing some editors). [Matthew Mueller] * Reference to a struct member which is an array is coerced to a pointer. [Matthew Mueller] * Default argument values did not work in methods of an extension type. [Matthew Mueller] * Single or double quote characters in a triple-quoted string didn't work. [Matthew Mueller] * Using *args in a function definition sometimes caused a crash at runtime. [Matthew Mueller] * A hack is included which tries to make functions in Python.h which use 'const' accessible from Pyrex. But it doesn't work on all platforms. Thinking about a better solution. New features: * Comment containing Pyrex version number and date/time at top of generated C file. [Matthias Baas] 0.3.2 ----- Bug fixes: * The & operator works again. [Matthias Baas] * The & operator had incorrect precedence. * "SystemError: 'finally' pops bad exception" under some circumstances when raising an exception. [Matthias Baas] * Calling a Python function sometimes leaked a reference. * Crash under some circumstances when casting a Python object reference to a C pointer type. [Michael JasonSmith] * Crash when redeclaring a function. [Matthias Baas] * Crash when using a string constant inside a Python class definition. [Mike Rovner] * 2-element slice indexing expressions. [Mike Rovner] * Crash when encountering mixed tabs and spaces. [Mike Rovner] New features: * A wider variety of constant expressions is now accepted for enum values, array dimensions, etc. [Mike Rovner] 0.3.1 ----- New features: * More special methods for extension types: __delitem__, __delslice__, __getattr__, __setattr__, __delattr__ * Module-level variable of a Python object type declared with 'cdef' is private to the module, and held in a C variable instead of the module dict. * External C functions with variable argument lists can be declared and called. * Pyrex-defined Python functions can have default argument values and * and ** arguments, and can be called with keyword arguments. * Pointer-to-function types can be declared. * Pyrex now supports a declaration syntax that C doesn't! Example: cdef (int (*)()) foo() # function returning a function ptr * There is now a ctypedef statement. * Extension types can now be forward-declared. * All permutations of (non-Unicode) string literals and escape codes should work now. * Hex and octal integer literals. * Imaginary number literals. * Docstrings are now supported. Bug fixes: * Type tests are performed when using a Python object in a context requiring a particular extension type. * Module-level variable holding the type object of an extension type had incorrect type. 0.3 --- New features: * Extension types! Yay! 0.2.2 ----- Bug fixes: * Fixed error message generation again after a previous bug was accidentally re-indroduced. * Removed the declaration of isspace() from the code generated for print statement support (it's not needed and was conflicting with the system-supplied one on some platforms). 0.2 --- New features: * Executable statements are now allowed at the top level of a module. * Python class definitions are now supported, with the following limitations: - Class definitions are only allowed at the top level of a module, not inside a control structure or function or another class definition. - Assigning a Pyrex-defined Python function to a class attribute outside of the class definition will not create a method (because it's not an interpreted Python function and therefore won't trigger the bound-method creation magic). - The __metaclass__ mechanism and the creation of new-style classes is not (yet) supported. * Casting between Python and non-Python types is better supported. Bug fixes: * Fixed bug preventing for-loops from working. 0.1.1 ----- * I've discovered a flaw in my algorithm for releasing temp variables. Fixing this properly will require some extensive reworking; I've put in a hack in the meantime which should work at the cost of using more temp variables than are strictly necessary. * Fixed bug preventing access to builtin names from working. This should also have fixed the import statement, but I haven't tested it. * Fixed some errors in __Pyx_GetExcValue. * Fixed bug causing boolean expressions to malfunction sometimes. Pyrex-0.9.8.5/CHECKLIST.txt0000644001243100001200000000037711023676353015153 0ustar00gregadmin00000000000000Release Checklist ================= # Update CHANGES.txt * Ensure all tests pass * cd Demos; make test * make test_setup * Check version number in Makefile * Update news in web page * Commit changes * Tag release * cd ..; make tar * make upload Pyrex-0.9.8.5/Demos/callback/cheese.pyx0000644001243100001200000000050410556551457017701 0ustar00gregadmin00000000000000# # Pyrex 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) Pyrex-0.9.8.5/Demos/callback/cheesefinder.c0000644001243100001200000000050310702077004020452 0ustar00gregadmin00000000000000/* * 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; } } Pyrex-0.9.8.5/Demos/callback/cheesefinder.h0000644001243100001200000000016310556551457020501 0ustar00gregadmin00000000000000typedef void (*cheesefunc)(char *name, void *user_data); void find_cheeses(cheesefunc user_func, void *user_data); Pyrex-0.9.8.5/Demos/callback/Makefile0000644001243100001200000000024310556551457017343 0ustar00gregadmin00000000000000all: 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 Pyrex-0.9.8.5/Demos/callback/Makefile.nodistutils0000644001243100001200000000050310556551457021722 0ustar00gregadmin00000000000000PYHOME = $(HOME)/pkg/python/version PYINCLUDE = \ -I$(PYHOME)/include/python2.2 \ -I$(PYHOME)/$(ARCH)/include/python2.2 %.c: %.pyx ../../bin/pyrexc $< %.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.* Pyrex-0.9.8.5/Demos/callback/README.txt0000644001243100001200000000052710556551457017406 0ustar00gregadmin00000000000000This 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. Pyrex-0.9.8.5/Demos/callback/run_cheese.py0000644001243100001200000000014510556551457020376 0ustar00gregadmin00000000000000import cheese def report_cheese(name): print "Found cheese:", name cheese.find(report_cheese) Pyrex-0.9.8.5/Demos/callback/Setup.py0000644001243100001200000000041110702071265017335 0ustar00gregadmin00000000000000from distutils.core import setup from distutils.extension import Extension from Pyrex.Distutils import build_ext setup( name = 'callback', ext_modules=[ Extension("cheese", ["cheese.pyx", "cheesefinder.c"]), ], cmdclass = {'build_ext': build_ext} ) Pyrex-0.9.8.5/Demos/embed/embedded.pyx0000644001243100001200000000012207702770133017503 0ustar00gregadmin00000000000000cdef public void spam(): praise() def praise(): print "Spam, glorious spam!" Pyrex-0.9.8.5/Demos/embed/main.c0000644001243100001200000000021607702770133016304 0ustar00gregadmin00000000000000#include "Python.h" #include "embedded.h" int main(int argc, char *argv) { Py_Initialize(); initembedded(); spam(); Py_Finalize(); } Pyrex-0.9.8.5/Demos/embed/Makefile0000755001243100001200000000000010556551452021272 2Makefile.unixustar00gregadmin00000000000000Pyrex-0.9.8.5/Demos/embed/Makefile.msc0000644001243100001200000000175510556551457017455 0ustar00gregadmin00000000000000# 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 ../../pyrexc.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 Pyrex-0.9.8.5/Demos/embed/Makefile.msc.static0000644001243100001200000000076410556551457020742 0ustar00gregadmin00000000000000# 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 ../../pyrexc.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 Pyrex-0.9.8.5/Demos/embed/Makefile.unix0000644001243100001200000000114210556551457017644 0ustar00gregadmin00000000000000PYVERSION = 2.2 PYHOME = $(HOME)/pkg/python/$(PYVERSION) PYARCH = $(PYHOME)/$(ARCH) PYINCLUDE = \ -I$(PYHOME)/include/python$(PYVERSION) \ -I$(PYARCH)/include/python$(PYVERSION) PYLIB = -L$(PYARCH)/lib/python$(PYVERSION)/config \ -lpython$(PYVERSION) \ -ldl -lpthread -lutil -lm %.c: %.pyx ../../bin/pyrexc $< %.o: %.c gcc -c -fPIC $(PYINCLUDE) $< #%.so: %.o # gcc -shared $< -lm -o $@ all: main main: main.o embedded.o gcc main.o embedded.o $(PYLIB) -o main clean: @echo Cleaning Demos/embed @rm -f *~ *.o *.so core core.* embedded.h embedded.c main embedded.h: embedded.c main.o: embedded.h Pyrex-0.9.8.5/Demos/embed/README0000644001243100001200000000067410556551457016113 0ustar00gregadmin00000000000000This example demonstrates how Pyrex-generated code can be called directly from a main program written in C. In this example, the module's initialisation function (called "initembedded", since the module is called "embedded") is called explicitly. This is necessary because the module is not being imported using the normal Python import mechanism. The Windows makefiles were contributed by Duncan Booth . Pyrex-0.9.8.5/Demos/Makefile0000644001243100001200000000043210556551457015607 0ustar00gregadmin00000000000000all: 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 Pyrex-0.9.8.5/Demos/Makefile.nodistutils0000644001243100001200000000060610556551457020172 0ustar00gregadmin00000000000000PYHOME = $(HOME)/pkg/python/version PYINCLUDE = \ -I$(PYHOME)/include/python2.2 \ -I$(PYHOME)/$(ARCH)/include/python2.2 %.c: %.pyx ../bin/pyrexc $< %.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 Pyrex-0.9.8.5/Demos/numeric_demo.pyx0000644001243100001200000000170210556551457017360 0ustar00gregadmin00000000000000# # This example demonstrates how to access the internals # of a Numeric array object. # 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 def print_2d_array(ArrayType a): print "Type:", chr(a.descr.type) if chr(a.descr.type) <> "f": raise TypeError("Float array required") if a.nd <> 2: raise ValueError("2 dimensional array required") cdef int nrows, ncols cdef float *elems, x nrows = a.dimensions[0] ncols = a.dimensions[1] elems = a.data hyphen = "-" divider = ("+" + 10 * hyphen) * ncols + "+" print divider for row in range(nrows): for col in range(ncols): x = elems[row * ncols + col] print "| %8f" % x, print "|" print divider Pyrex-0.9.8.5/Demos/primes.pyx0000644001243100001200000000055210556551457016213 0ustar00gregadmin00000000000000def 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 Pyrex-0.9.8.5/Demos/pyprimes.py0000644001243100001200000000036010556551457016371 0ustar00gregadmin00000000000000def 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 Pyrex-0.9.8.5/Demos/run_numeric_demo.py0000644001243100001200000000017607702770133020051 0ustar00gregadmin00000000000000import 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) Pyrex-0.9.8.5/Demos/run_primes.py0000644001243100001200000000017010556551457016703 0ustar00gregadmin00000000000000import sys from primes import primes if len(sys.argv) >= 2: n = int(sys.argv[1]) else: n = 1000 print primes(n) Pyrex-0.9.8.5/Demos/run_spam.py0000644001243100001200000000017607702770133016343 0ustar00gregadmin00000000000000from spam import Spam s = Spam() print "Created:", s s.set_amount(42) print "Amount =", s.get_amount() s.describe() s = None Pyrex-0.9.8.5/Demos/Setup.py0000644001243100001200000000061511012755537015615 0ustar00gregadmin00000000000000from distutils.core import setup #from distutils.extension import Extension from Pyrex.Distutils.extension import Extension from Pyrex.Distutils import build_ext setup( name = 'Demos', ext_modules=[ Extension("primes", ["primes.pyx"]), Extension("spam", ["spam.pyx"]), Extension("numeric_demo", ["numeric_demo.pyx"]), ], cmdclass = {'build_ext': build_ext} ) Pyrex-0.9.8.5/Demos/spam.pyx0000644001243100001200000000056007702770133015644 0ustar00gregadmin00000000000000# # Example of an extension type. # cdef class Spam: cdef int amount def __new__(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!" Pyrex-0.9.8.5/Doc/About.html0000644001243100001200000002141610700563577015547 0ustar00gregadmin00000000000000 About Pyrex


Pyrex

A language for writing Python extension modules

What is Pyrex all about?

Pyrex 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.

Pyrex aims to go far beyond what any of these previous tools provides. Pyrex 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, Pyrex 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 Pyrex

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

Pyrex is Python: Almost any piece of Python code is also valid Pyrex code. (There are a few limitations, but this approximation will serve for now.) The Pyrex compiler will convert it into C code which makes equivalent calls to the Python/C API. In this respect, Pyrex 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 Pyrex 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 Pyrex 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 Pyrex has saved you, take a look at the C code generated for this module .

Language Details

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

Future Plans

Pyrex 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 Pyrex declarations, possibly with some manual intervention.
Pyrex-0.9.8.5/Doc/FAQ.html0000644001243100001200000001075210700563755015103 0ustar00gregadmin00000000000000 FAQ.html


Pyrex 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.

Pyrex 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 Pyrex thinks is a generic Python object. You need to tell Pyrex 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.

--- Pyrex-0.9.8.5/Doc/index.html0000644001243100001200000000571310700623673015600 0ustar00gregadmin00000000000000 Pyrex - Front Page  
Pyrex A smooth blend of the finest Python 
with the unsurpassed power  of raw C.
Welcome to Pyrex, a language for writing Python extension modules. Pyrex makes creating an extension module almost as easy as creating a Python module.

Documentation

About Pyrex

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

Language Overview

A comined tutorial and reference manual describing of all the features of the Pyrex language.

FAQ

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

Other Resources

Michael's Quick Guide to Pyrex

This tutorial-style presentation will take you through the steps of creating some Pyrex 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 Pyrex, feel free to email me: greg.ewing@canterbury.ac.nz
Pyrex-0.9.8.5/Doc/LanguageOverview.html0000644001243100001200000000207011022635154017727 0ustar00gregadmin00000000000000 Pyrex Language Overview


Overview of the Pyrex Language 

This is a combined tutorial and reference manual that describes the extensions to the Python language made by Pyrex.

Contents

---Pyrex-0.9.8.5/Doc/Manual/basics.html0000644001243100001200000012316611013250160017136 0ustar00gregadmin00000000000000 Language Basics


Language Basics

This section describes the basic features of the Pyrex 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 Pyrex modules.

Python functions vs. C functions

There are two kinds of function definition in Pyrex:

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 Pyrex 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 Pyrex 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

Forward Declarations

If you have two struct or union types containing pointers that refer to each other, you will need to use a forward declaration for at least one of them. This is simply the header of a struct or union without the colon or body, for example,

cdef struct Sandwich

cdef struct Lunchbox:
Sandwich *lunch

cdef struct Sandwich:
Lunchbox *container

You can also forward-declare C functions, but there should be little need to do this. Pyrex processes all declarations in a module before analysing any executable statements, so calling a function defined further down in the source file is usually not a problem.

Grouping multiple C declarations

If you have a series of declarations that all begin with cdef, you can group them into a cdef block like this:
cdef:

struct Spam:
int tons

int i
float f
Spam *p

void f(Spam *s):
print s.tons, "Tons of spam"

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.

Pyrex detects and prevents some mistakes of this kind. For instance, if you attempt something like
cdef char *s
s = pystring1 + pystring2
then Pyrex 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 Pyrex 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, Pyrex 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 Pyrex 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

Pyrex 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.

This can result in some odd things happening under rare circumstances, for example

print __name__

In Pyrex, instead of printing the name of the current module, this prints the name of the builtins module. The reason is that because Pyrex hasn't seen a declaration of anything called __name__ in the module, it's assumed to reside in the builtins. The solution is to use a global statement to declare __name__ as a module-level name:

global __name__
print __name__

Another 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 Pyrex:
try:
  x = True
except NameError:
  True = 1
because, due to the assignment in the last line, 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 Pyrex expressions

There are some differences in syntax and semantics between C expressions and Pyrex 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 Pyrex. Instead of p->x, use p.x
  •  
  • There is no * operator in Pyrex. 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 Pyrex to perform the conversion automatically.

Operator Precedence

Keep in mind that there are some differences in operator precedence between Python and C, and that Pyrex uses the Python precedences, not the C ones.

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, Pyrex has another form of for-loop:
for 0 <= i < n:
    ...
Provided the loop variable and the lower and upper bounds are all C integers, this form of loop will be much faster, because Pyrex will translate it into pure C code.

Some things to note about the integer for-loop:

  • The target expression (the middle one) must be a variable 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, Pyrex generates a call to PyErr_Occurred if 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 Pyrex 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:

  • Exception values can only declared for functions returning an integer, enum, float or pointer type, and the value must be a constant expression. 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-Pyrex 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 Pyrex 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

A Pyrex source file can include material from other files 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 statements or declarations that are valid in the context where the include statement appears, including other include statements. The contents of the included file should begin at an indentation level of zero, and will be treated as though they were indented to the level of the include statement that is including the file.

Note that there are other mechanisms available for splitting Pyrex code into separate parts that may be more appropriate in many cases. See Sharing Declarations Between Pyrex Modules.

Keyword-only arguments

Python functions can have keyword-only arguments listed after the * parameter and before the ** paramter if any, e.g.

def f(a, b, *args, c, d = 42, e, **kwds):
...
Here c, d and e cannot be passed as position arguments and must be passed as keyword arguments. Furthermore, c and e are required keyword arguments, since they do not have a default value.

If the parameter name after the * is omitted, the function will not accept any extra positional arguments, e.g.

def g(a, b, *, c, d):
...
takes exactly two positional parameters and has two required keyword parameters.


Built-in Names

Pyrex knows about many of the names in the builtin namespace, and treats them specially in the interests of generating efficient code.

Built-in Constants

Pyrex knows the following built-in constant and type names, and references their values directly instead of using a dictionary lookup.

Type objects (type type)Exceptions (type type)
buffer
enumerate
file
float
int
long
open
property
str
tuple
xrange
Exception
StopIteration
StandardError
ArithmeticError
LookupError
AsssertionError
EOFError
FloatingPointError
EnvironmentError
IOError
OSError
ImportError
IndexError
KeyError
KeyboardInterrupt
MemoryError
NameError
OverflowError
RuntimeError
NotImplementedError
SyntaxError
IndentationError
TabError
ReferenceError
SystemError
SystemExit
TypeError
UnboundLocalError
UnicodeError
UnicodeEncodeError
UnicodeDecodeError
UnicodeTranslateError
ValueError
ZeroDivisionError
Warning
UserWarning
DeprecationWarning
PendingDeprecationWarning
SyntaxWarning
OverflowWarning
RuntimeWarning
FutureWarning
Constants (type object)
True
False
Ellipsis

Note that although some of the above names refer to type objects, they are not Pyrex type names and therefore can't be used to declare the type of a variable. Only the names listed under Built-in Types below can be used as type names in declarations.

Built-in Functions

Pyrex compiles calls to the following built-in functions into direct calls to the corresponding Python/C API routines, making them particularly fast.

Function and argumentsReturn typePython/C API Equivalent
abs(obj)objectPyNumber_Absolute
bool(obj)   (Note 3)intPyObject_IsTrue
delattr(obj, name)intPyObject_DelAttr
dir(obj)objectPyObject_Dir
divmod(x, y)objectPyNumber_Divmod
getattr(obj, name)   (Note 1)
getattr3(obj, name, default)
objectPyObject_GetAttr
hasattr(obj, name)intPyObject_HasAttr
hash(obj)intPyObject_Hash
intern(obj)objectPyString_InternFromString
isinstance(obj, type)intPyObject_IsInstance
issubclass(obj, type)intPyObject_IsSubclass
issubtype(type, type)   (Note 4)intPyType_IsSubType
iter(obj)objectPyObject_GetIter
len(obj)Py_ssize_tPyObject_Length
pow(x, y, z)   (Note 2)objectPyNumber_Power
reload(obj)objectPyImport_ReloadModule
repr(obj)objectPyObject_Repr
setattr(obj, name)voidPyObject_SetAttr
typecheck(obj, type)   (Note 4)intPyObject_TypeCheck

Note 1: There are two different functions corresponding to the Python getattr depending on whether a third argument is used. In a non-call context, they both evaluate to the Python getattr function.

Note 2: Only the three-argument form of pow() is supported. Use the ** operator otherwise.

Note 3: In a non-call context, the name bool refers to the Python built-in bool type.

Note 4: The functions typecheck and issubtype have no exact Python equivalent. They are included for fast, safe type checking of extension types. They are safer than using isinstance and issubclass for this purpose, because the behaviour of the latter functions can be overridden, so they don't necessarily reflect the true C types of the objects involved.

Only direct function calls using these names are optimised. If you do something else with one of these names that assumes it's a Python object, such as assign it to a Python variable, and later call it, the call will be made as a Python function call.

Built-in Types

Pyrex knows about the following builtin types:

dict
list
object
slice
type

If you declare a variable as being of one of these types, then calls to the methods in the table below will be compiled to direct Python/C API calls, avoiding the overhead of a Python attribute lookup and function call. In the case of attributes, they will be accessed directly from the object's C struct.

Referring to the types themselves is also slightly more efficient, because the relevant type object is accessed directly rather than via a global variable lookup.

Method or AttributeReturn typePython/C API EquivalentNotes
Type dict
clear()PyDict_Clear
copy()PyDict_Copy
items()objectPyDict_Items
keys()objectPyDict_Keys
values()objectPyDict_Values
merge(obj, override)PyDict_MergeMerge items from a mapping
update(obj)PyDict_Update
merge_pairs(obj, override)PyDict_MergeFromSeq2Merge (key, value) pairs from a sequence
Type list
insert(int, obj)PyList_Insert
append(obj)PyList_Append
sort()PyList_Sort
reverse()PyList_Reverse
as_tuple()objectPyList_AsTuple
Type slice
indices()objectPySlice_Indices
startobject
stopobject
stepobject

Some of the above methods have no direct Python equivalent, but are there to provide access to routines that exist in the Python/C API.

As an example, the following compiles into code containing no Python attribute lookups or function calls.

cdef list cheeses
cheeses = []
cheeses.append("camembert")
cheeses.append("cheddar")
cheeses.insert(1, "something runny")


Conditional Compilation

Some features are available for conditional compilation and compile-time constants within a Pyrex source file.

Compile-Time Definitions

A compile-time constant can be defined using the DEF statement:
DEF FavouriteFood = "spam"
DEF ArraySize = 42
DEF OtherArraySize = 2 * ArraySize + 17
The right-hand side of the DEF must be a valid compile-time expression. Such expressions are made up of literal values and names defined using DEF statements, combined using any of the Python expression syntax.

The following compile-time names are predefined, corresponding to the values returned by os.uname().
UNAME_SYSNAME, UNAME_NODENAME, UNAME_RELEASE,
UNAME_VERSION, UNAME_MACHINE
The following selection of builtin constants and functions are also available:
None, True, False,
abs, bool, chr, cmp, complex, dict, divmod, enumerate,
float, hash, hex, int, len, list, long, map, max, min,
oct, ord, pow, range, reduce, repr, round, slice, str,
sum, tuple, xrange, zip
A name defined using DEF can be used anywhere an identifier can appear, and it is replaced with its compile-time value as though it were written into the source at that point as a literal. For this to work, the compile-time expression must evaluate to a Python value of type int, long, float or str.
cdef int a1[ArraySize]
cdef int a2[OtherArraySize]
print "I like", FavouriteFood

Conditional Statements

The IF statement can be used to conditionally include or exclude sections of code at compile time. It works in a similar way to the #if preprocessor directive in C.
IF UNAME_SYSNAME == "Windows":
include "icky_definitions.pxi"
ELIF UNAME_SYSNAME == "Darwin":
include "nice_definitions.pxi"
ELIF UNAME_SYSNAME == "Linux":
include "penguin_definitions.pxi"
ELSE:
include "other_definitions.pxi"
The ELIF and ELSE clauses are optional. An IF statement can appear anywhere that a normal statement or declaration can appear, and it can contain any statements or declarations that would be valid in that context, including DEF statements and other IF statements.

The expressions in the IF and ELIF clauses must be valid compile-time expressions as for the DEF statement, although they can evaluate to any Python value, and the truth of the result is determined in the usual Python way.

---Pyrex-0.9.8.5/Doc/Manual/extension_types.html0000644001243100001200000006441311022636621021143 0ustar00gregadmin00000000000000 Extension Types


Extension Types

Contents

Introduction

As well as creating normal user-defined classes with the Python class statement, Pyrex also lets you create new built-in Python types, known as extension types.

WARNING: There are substantial differences in the way many of the special methods work in extension types compared to Python classes. Before attempting to define any __xxx__ methods, read the section on Special Methods of 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 Pyrex 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 Pyrex code. Python code is only able to access attributes of an extension type by the first method, but Pyrex 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.

Type declarations

Before you can directly access the attributes of an extension type, the Pyrex 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 use a type declaration.

For example, in the following function,

cdef widen_shrubbery(sh, extra_width): # BAD
    sh.width = sh.width + extra_width

because the sh parameter hasn't been given a type, the width attribute will be accessed by a Python attribute lookup. If the attribute has been declared public or readonly then this will work, but it will be very inefficient. If the attribute is private, it will not work at all -- the code will compile, but an attribute error will be raised at run time.

The solution is to declare sh as being of type Shrubbery, as follows:

cdef widen_shrubbery(Shrubbery sh, extra_width):
    sh.width = sh.width + extra_width
Now the Pyrex compiler knows that sh has a C attribute called width and will generate code to access it directly and efficiently. The same consideration applies to local variables, for example,

cdef Shrubbery another_shrubbery(Shrubbery sh1):
    cdef Shrubbery sh2
    sh2 = Shrubbery()
    sh2.width = sh1.width
    sh2.height = sh1.height
    return sh2

Extension types and None

When you declare a parameter or C variable as being of an extension type, Pyrex 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, Pyrex 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, Pyrex 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 __cinit__(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 Pyrex, 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 Pyrex 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).

Pyrex 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

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 Pyrex module. A public extension type declaration makes an extension type defined in a Pyrex 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-Pyrex extension module.
NOTE: In Pyrex versions before 0.8, extern extension types were also used to reference extension types defined in another Pyrex module. While you can still do that, Pyrex 0.8 and later provides a better mechanism for this. See Sharing C Declarations Between Pyrex 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 Pyrex 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.
Pyrex 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 Pyrex 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 Pyrex 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 Pyrex must be able to generate code that is compatible with external C code.



Back to the Language Overview
 

Pyrex-0.9.8.5/Doc/Manual/external.html0000644001243100001200000005763711013717552017542 0ustar00gregadmin00000000000000 Interfacing with External C Code


Interfacing with External C Code

One of the main uses of Pyrex 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 Pyrex 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 Pyrex 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, Pyrex 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 Pyrex 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 Pyrex to place a #include statement for the named header file in the generated C code.
  2.  
  3. It prevents Pyrex 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 Pyrex does not itself read the C header file, so you still need to provide Pyrex versions of any declarations from it that you use. However, the Pyrex 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. Pyrex 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 Pyrex declarations match the style used in the header file, so that Pyrex can emit the right sort of references to the type in the code it generates. To make this possible, Pyrex 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 Pyrex 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 Pyrex code simply as Foo, not struct Foo.

  C code Possibilities for corresponding Pyrex code Comments
1 struct Foo {
  ...
};
cdef struct Foo:
  ...
Pyrex will refer to the type as struct Foo in the generated C code.
2 typedef struct {
  ...
} Foo;
ctypedef struct Foo:
  ...
Pyrex 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 Pyrex (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, Py_ssize_t len)
will allow you to create Python strings containing null bytes.

Special Types

Pyrex predefines the name Py_ssize_t for use with Python/C API routines. To make your extensions compatible with 64-bit systems, you should always use this type where it is specified in the documentation of Python/C API routines.

Windows Calling Conventions

The __stdcall and __cdecl calling convention specifiers can be used in Pyrex, with the same syntax as used by C compilers on Windows, for example,

cdef extern int __stdcall FrobnicateWindow(long handle)

cdef void (__stdcall *callback)(void *)
If __stdcall is used, the function is only considered compatible with other __stdcall functions of the same signature.


Resolving naming conflicts - C name specifications

Each Pyrex 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.

Pyrex 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 Pyrex modules.

The other way is to use a c name specification to give different Pyrex 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 Pyrex 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 Pyrex keywords. For example, if you want to call an external function called print, you can rename it to something else in your Pyrex 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

Using Pyrex Declarations from C

Pyrex provides two methods for making C declarations from a Pyrex module available for use by external C code – public declarations and C API declarations.

NOTE: You do not need to use either of these to make declarations from one Pyrex module available to another Pyrex module – you should use the cimport statement for that. Sharing Declarations Between Pyrex Modules.

Public Declarations

You can make C types, variables and functions defined in a Pyrex module accessible to C code that is linked with the module, by declaring them with the public keyword:
cdef public struct Bunny: # public type declaration
    int vorpalness

cdef public int spam # public variable declaration

cdef public void grail(Bunny *): # public function declaration
    ...

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

Any C code wanting to make use of these declarations will need to be linked, either statically or dynamically, with the extension module.

If the Pyrex module resides within a package, then the name of the .h file consists of the full dotted name of the module, e.g. a module called foo.spam would have a header file called foo.spam.h.

C API Declarations

The other way of making declarations available to C code is to declare them with the api keyword. You can use this keyword with C functions and extension types. A header file called "modulename_api.h" is produced containing declarations of the functions and extension types, and a function called import_modulename().

C code wanting to use these functions or extension types needs to include the header and call the import_modulename() function. The other functions can then be called and the extension types used as usual.

Any public C type or extension type declarations in the Pyrex module are also made available when you include modulename_api.h.

delorean.pyx
marty.c
cdef public struct Vehicle:
int speed
float power

cdef api void activate(Vehicle *v):
if v.speed >= 88 \
and v.power >= 1.21:
print "Time travel achieved"
#include "delorean_api.h"

Vehicle car;

int main(int argc, char *argv[]) {
import_delorean();
car.speed = atoi(argv[1]);
car.power = atof(argv[2]); 
activate(&car);
}

Note that any types defined in the Pyrex module that are used as argument or return types of the exported functions will need to be declared public, otherwise they won't be included in the generated header file, and you will get errors when you try to compile a C file that uses the header.

Using the api method does not require the C code using the declarations to be linked with the extension module in any way, as the Python import machinery is used to make the connection dynamically. However, only functions can be accessed this way, not variables.

You can use both public and api on the same function to make it available by both methods, e.g.
cdef public api void belt_and_braces():
...
However, note that you should include either modulename.h or modulename_api.h in a given C file, not both, otherwise you may get conflicting dual definitions.

If the Pyrex module resides within a package, then:
  • The name of the header file contains of the full dotted name of the module.
  • The name of the importing function contains the full name with dots replaced by double underscores.
E.g. a module called foo.spam would have an API header file called foo.spam_api.h and an importing function called import_foo__spam().

Multiple public and api declarations

You can declare a whole group of items as public and/or api all at once by enclosing them in a cdef block, for example,
cdef public api:
void order_spam(int tons)
char *get_lunch(float tomato_size)
This can be a useful thing to do in a .pxd file (see Sharing Declarations Between Pyrex Modules) to make the module's public interface available by all three methods.


Acquiring and Releasing the GIL

Pyrex provides facilities for releasing the Global Interpreter Lock (GIL) before calling C code, and for acquiring the GIL in functions that are to be called back from C code that is executed without the GIL.

Releasing the GIL

You can release the GIL around a section of code using the with nogil statement:
with nogil:
<code to be executed with the GIL released>
Code in the body of the statement must not manipulate Python objects, and must not call anything that manipulates Python objects without first re-acquiring the GIL. Pyrex attempts to check that these restrictions are being followed as far as it can, but it may not catch all possible forms of violation.

Any external C functions called inside the block must be declared as nogil (see below).

Note: It may be safe to do some things with Python objects under some circumstances. Provided steps are taken (such as adequate locking) to ensure that the objects involved cannot be deallocated by Python code running in another thread, it is probably safe to access non-Python C attributes of an extension type, and to pass references to Python objects to another function that is safe to call with the GIL released.

However, in the absence of such locking, it is not safe to do anything with Python objects with the GIL released -- not even look at them.

Acquiring the GIL

A C function that is to be used as a callback from C code that is executed without the GIL needs to acquire the GIL before it can manipulate Python objects. This can be done by specifying with gil in the function header:
cdef void my_callback(void *data) with gil:
...

Declaring a function as callable without the GIL

You can specify nogil in a C function header or function type to declare that it is safe to call without the GIL.

cdef extern int swizzle_the_knob() nogil

A block of external functions can be declared nogil at once.

cdef extern from "somewhere.h" nogil:
...

Note that declaring a function nogil does not cause the GIL to be released before calling the function. It simply allows the function to be called in situations where the GIL is not held.

You can also declare a function implemented in Pyrex as nogil.
cdef void my_gil_free_func(int spam) nogil:
...
Such a function cannot have any Python local variables, it cannot return a Python type, and the same restrictions apply to the body of the function as for a with nogil block.

Declaring a function with gil also implicitly makes its signature nogil.


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)  
---Pyrex-0.9.8.5/Doc/Manual/Limitations.html0000644001243100001200000000633211012030055020157 0ustar00gregadmin00000000000000 Limitations


Limitations

Unsupported Python features

Pyrex 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 Pyrex.

  • 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 Pyrex'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.
  •  
  • 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 they are not accepted in places where executable statements are not allowed.

  • Semantic differences between Python and Pyrex

    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 Pyrex it yields an unbound method1. 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 Pyrex. 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. The reason for the different behaviour of class scopes is that Pyrex-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, Pyrex wraps each method in an unbound method object itself before storing it in the class's dictionary.

    --- Pyrex-0.9.8.5/Doc/Manual/sharing.html0000644001243100001200000003517611055142272017342 0ustar00gregadmin00000000000000 Sharing Declarations Between Pyrex Modules


    Sharing Declarations Between Pyrex Modules

    This section describes a new set of facilities introduced in Pyrex 0.8 for making C declarations, functions and extension types in one Pyrex module available for use in another Pyrex module. These facilities are closely modelled on the Python import mechanism, and can be thought of as a compile-time version of it.

    Contents

    Definition and Implementation files

    A Pyrex module can be split into two parts: a definition file with a .pxd suffix, containing C declarations that are to be available to other Pyrex modules, and an implementation file with a .pyx suffix, containing everything else. When a module wants to use something declared in another module's definition file, it imports it using the cimport statement.

    What a Definition File contains

    A definition file can contain:
    • Any kind of C type declaration.
    • extern C function or variable declarations.
    • Declarations of C functions defined in the module.
    • The definition part of an extension type (see below).
    It cannot contain any non-extern C variable declarations.

    It cannot contain the implementations of any C or Python functions, or any Python class definitions, or any executable statements.

    NOTE: You don't need to (and shouldn't) declare anything in a declaration file public in order to make it available to other Pyrex modules; its mere presence in a definition file does that. You only need a public declaration if you want to make something available to external C code.

    What an Implementation File contains

    An implementation file can contain any kind of Pyrex statement, although there are some restrictions on the implementation part of an extension type if the corresponding definition file also defines that type (see below).

    The cimport statement

    The cimport statement is used in a definition or implementation file to gain access to names declared in another definition file. Its syntax exactly parallels that of the normal Python import statement:
    cimport module [, module...]
    from module cimport name [as name] [, name [as name] ...]
    Here is an example. The file on the left is a definition file which exports a C data type. The file on the right is an implementation file which imports and uses it.
     
    dishes.pxd restaurant.pyx
    cdef enum otherstuff:
        sausage, eggs, lettuce

    cdef struct spamdish:
        int oz_of_spam
        otherstuff filler

    cimport dishes
    from dishes cimport spamdish

    cdef void prepare(spamdish *d):
        d.oz_of_spam = 42
        d.filler = dishes.sausage

    def serve():
        spamdish d
        prepare(&d)
        print "%d oz spam, filler no. %d" % \
             (d->oz_of_spam, d->otherstuff)

    It is important to understand that the cimport statement can only be used to import C data types, C functions and variables, and extension types. It cannot be used to import any Python objects, and (with one exception) it doesn't imply any Python import at run time. If you want to refer to any Python names from a module that you have cimported, you will have to include a regular import statement for it as well.

    The exception is that when you use cimport to import an extension type, its type object is imported at run time and made available by the name under which you imported it. Using cimport to import extension types is covered in more detail below.

    Search paths for definition files

    When you cimport a module called modulename, the Pyrex compiler searches for a file called modulename.pxd along the search path for include files, as specified by -I command line options.

    Also, whenever you compile a file modulename.pyx, the corresponding definition file modulename.pxd is first searched for along the same path, and if found, it is processed before processing the .pyx file.

    Using cimport to resolve naming conflicts

    The cimport mechanism provides a clean and simple way to solve the problem of wrapping external C functions with Python functions of the same name. All you need to do is put the extern C declarations into a .pxd file for an imaginary module, and cimport that module. You can then refer to the C functions by qualifying them with the name of the module. Here's an example:
     
    c_lunch.pxd lunch.pyx
    cdef extern from "lunch.h":
        void eject_tomato(float)
    cimport c_lunch

    def eject_tomato(float speed):
        c_lunch.eject_tomato(speed)

    You don't need any c_lunch.pyx file, because the only things defined in c_lunch.pxd are extern C entities. There won't be any actual c_lunch module at run time, but that doesn't matter; the c_lunch.pxd file has done its job of providing an additional namespace at compile time.

    Sharing C Functions

    C functions defined at the top level of a module can be made available via cimport by putting headers for them in the .pxd file, for example,

    volume.pxd
    spammery.pyx
    cdef float cube(float)
    from volume cimport cube

    def menu(description, size):
        print description, ":", cube(size), \
    "cubic metres of spam"

    menu("Entree", 1)
    menu("Main course", 3)
    menu("Dessert", 2)
    volume.pyx
    cdef float cube(float x):
        return x * x * x

    Sharing Extension Types

    An extension type can be made available via cimport by splitting its definition into two parts, one in a definition file and the other in the corresponding implementation file.

    The definition part of the extension type can only declare C attributes and C methods, not Python methods, and it must declare all of that type's C attributes and C methods.

    The implementation part must implement all of the C methods declared in the definition part, and may not add any further C attributes or methods. It may also define Python methods.

    Here is an example of a module which defines and exports an extension type, and another module which uses it.
     
    Shrubbing.pxd Shrubbing.pyx
    cdef class Shrubbery:
        cdef int width
        cdef int length
    cdef class Shrubbery:
        def __cinit__(self, int w, int l):
            self.width = w
            self.length = l

    def standard_shrubbery():
        return Shrubbery(3, 7)

    Landscaping.pyx
    cimport Shrubbing
    import Shrubbing

    cdef Shrubbing.Shrubbery sh
    sh = Shrubbing.standard_shrubbery()
    print "Shrubbery size is %d x %d" % (sh.width, sh.height)
     

    Some things to note about this example:

    • There is a cdef class Shrubbery declaration in both Shrubbing.pxd and Shrubbing.pyx. When the Shrubbing module is compiled, these two declarations are combined into one.
    •  
    • In Landscaping.pyx, the cimport Shrubbing declaration allows us to refer to the Shrubbery type as Shrubbing.Shrubbery. But it doesn't bind the name Shrubbing in Landscaping's module namespace at run time, so to access Shrubbing.standard_shrubbery we also need to import Shrubbing.
    If you are exporting an extension type that has a base class, the base class must be declared in the definition part. Repeating the base class in the implementation part is not necessary, but if you do, it must match the base class in the definition part.

    Circular cimports

    If you have two structs, unions or extension types defined in different .pxd files, and they need to refer to each other, there is a potential for problems with circular imports. These problems can be avoided by placing forward declarations of all the structs, unions and extension types defined in the .pxd file before the first cimport statement.

    For example:

    foo.pxdblarg.pxd
    cdef struct Spam

    from blarg cimport Eggs

    cdef struct Spam:
        Eggs *eggs
    cdef struct Eggs

    from foo cimport Spam

    cdef struct Eggs:
        Spam *spam

    If the forward declarations weren't present, a circular import problem would occur, analogous to that which arises in Python when two modules try to import names from each other. Placing the forward declarations before the cimport statements ensures that all type names are known to the Pyrex compiler sufficiently far in advance.

    Note that any .pyx file is free to cimport anything it wants from any .pxd file without needing this precaution. It's only when two .pxd files import each other that circular import issues arise.
    Back to the Language Overview

    Pyrex-0.9.8.5/Doc/Manual/source_files.html0000644001243100001200000004061211013423515020354 0ustar00gregadmin00000000000000 Source Files and Compilation


    Source Files and Compilation

    File Names and Extensions

    Pyrex source file names consist of the name of the module followed by a .pyx extension, for example a module called primes would have a source file named primes.pyx.

    Modules in Packages

    If your module is destined to live in a package, the Pyrex compiler needs to know the fully-qualified name that the module will eventually have.

    There are currently two ways to give it this information:
    1. Name the source file with the full dotted name of the module. For example, a module called primes to be installed in a package called numbers would have a source file called numbers.primes.pyx.

    2. Place the source file in a package directory. To Pyrex, a package directory is one that contains a file called either __init__.py or __init__.pyx. For example, a package called numbers containing a module called primes would have the source files laid out like this:
    numbers
    __init__.py
    primes.pyx

    This will ensure that the __name__ properties of the module and any classes defined in it are set correctly. If you don't do this, you may find that pickling doesn't work, among other problems. It also ensures that the Pyrex compiler has the right idea about the layout of the module namespace, which can be important when accessing extension types defined in other modules.

    Building an Extension

    There are two steps involved in creating an extension module from Pyres sources:
    1. Use the Pyrex compiler to translate the .pyx file into a .c file.
    2. Compile the .c file with a C compiler and link it with whatever libraries it needs, to produce an extension module.
    There are a variety of ways of accomplishing these steps, either separately or together. One way is to compile the Pyrex source manually from the command line with the Pyrex compiler, e.g.

    pyrexc -r primes.pyx

    This will compile primes.pyx and any other source files that it depends on, if any of them have changed since the last compilation, and produce a file called primes.c, which then needs to be compiled with the C compiler using whatever options are appropriate on your platform for generating an extension module.

    You can perform the C compilation using distutils and a setup.py file, or with a conventional Makefile. There's a Makefile in the Demos directory (called Makefile.nodistutils) that shows how to do this for Linux.

    Another approach is to put code at the beginning of your setup.py file to import the Pyrex compiler and call it from Python. You can then follow this with a normal call to setup() to compile the resulting .c files.

    You can also perform both steps at once in a setup.py file using the distutils extension provided with Pyrex. See the Setup.py file in the Demos directory for an example of how to use it. A disadvantage of this method is that you won't be able to take advantage of Pyrex's own dependency checking features to compile only the Pyrex sources which have changed.

    Command Line

    You can run the Pyrex compiler from the command line using either the pyrexc shell command or the Python version of it, pyrexc.py.

    The following command line options exist:

    ShortLongDescription
    -v--versionDisplay the version number of the Pyrex compiler
    -l--create-listingProduces a .lis file for each compiled .pyx file containing error messages
    -I--include-dirSpecifies a directory to be searched for included files and top-level package directories. Multiple -I options may be given, each specifying one directory.
    -o--output-fileSpecifies name of generated C file. Only meaningful when a single .pyx file is being compiled.
    -r--recursiveCompile the given .pyx files, plus those of any modules it depends on directly or indirectly via cimport statements. The include path specified by -I options is used to find the .pyx files of dependent modules.
    -t--timestampsUse modification times of files to decide whether to compile a .pyx file. This is the default when -r is used, unless -f is also used.
    -f--forceCompile all .pyx files regardless of modification times. This is the default when -r is not given.
    -q--quietWhen -r is given, don't display the names of source files being compiled.

    Calling the Pyrex compiler from Python

    The module Pyrex.Compiler.Main exports the following classes and functions to facilitate invoking the compiler from another Python program.

    compile(source [, options] [,  option  = value ]...)

    Compiles one or more Pyrex source files, which should be .pyx files. The source argument may be either a single filename or a list of filenames.

    Depending on the recursive option, it may compile just the specified source files, or the specified source files plus those of other modules that they depend on via cimport statements. The options may be given either as keyword arguments or a CompilationOptions instance. If both are used, keyword arguments take precedence.

    The return value depends on whether a list of sources was specifed and whether the recursive option is in effect. If a single source file is specified and the recursive option is false, the return value is a CompilationResult instance. Otherwise, the return value is a CompilationResultSet containing a CompilationResult for each of the modules which were actually compiled (which may or may not include ones corresponding to the specified source files).

    Note: If you have more than one source file to compile, it is more efficient to do so with a single call to compile rather than one call for each source file. This is because, if more than one source cimports the same .pxd file, the .pxd file is parsed only once instead of being parsed each time it is cimported.

    compile_single(source_path [, options] [,  option  = value ]...)

    Compiles just a single .pyx source file, specified as a string, with no dependency or timestamp checking (the recursive and timestamps options are ignored). Always returns a CompilationResult.

    compile_multiple(source_list [, options] [,  option  = value ]...)

    Compiles a list of .pyx source files, with optional dependency and timestamp checking as for compile. Always takes a list of source pathnames, and always returns a CompilationResultSet.

    class CompilationOptions


    A collection of options to be passed to the compile() function. The following options may be specified as keyword arguments to either the CompilationOptions constructor or the compile() function.
    show_version
    Display the version number of the Pyrex compiler.
    use_listing_file
    Produce a .lis file for each .pyx file containing compilation errors.
    include_path
    A list of directories to search for included files and top-level package directories.
    output_file
    Use the given name for the generated .c file (only in non-recursive mode).
    recursive
    Compile the .pyx files of any cimported modules in addition to the one specified.
    timestamps
    Only compile modified sources as determined by file modification times. This may be true, false or None. If None, timestamps are used if and only if recursive mode is in effect.
    quiet
    Don't display names of sources being compiled in recursive mode.
    class CompilationResult

    An object providing information about the result of compiling a .pyx file. It has the following attributes:
    c_file
    Pathname of the generated C source file.
    h_file
    Pathname of the generated C header file, if any.
    api_file
    Pathname of the generated C API header file, if any.
    listing_file
    Pathname of the generated error message file, if any.
    num_errors
    Number of compilation errors.
    class CompilationResultSet
    This is a mapping object whose keys are the pathnames of .pyx files and whose values are the corresponding CompilationResult instances. It also has the following additional attributes:
    num_errors
    Total number of compilation errors.

    Using the distutils extension

    The distutils extension provided with Pyrex allows you to pass .pyx files directly to the Extension constructor in your setup file.

    To use it, you need to put the following at the top of your setup.py file:

    from Pyrex.Distutils.extension import Extension
    from Pyrex.Distutils import build_ext

    and you need to specify the Pyrex version of the build_ext command class in your setup() call:

    setup(
        ...
        cmdclass = {'build_ext': build_ext}
    )

    Using the distutils extension is not currently recommended, because it's unable to automatically find cimported modules or check the timestamps of .pxd files and included sources. It also makes it harder to turn off the use of Pyrex for people who are only installing your module and not modifying the sources.

    Distributing Pyrex modules

    It is strongly recommended that you distribute the generated .c files as well as your Pyrex sources, so that users can install your module without needing to have Pyrex available.

    It is also recommended that Pyrex compilation not be enabled by default in the version you distribute. Even if the user has Pyrex installed, he probably doesn't want to use it just to install your module. Also, the version he has may not be the same one you used, and may not compile your sources correctly.

    ---
    Pyrex-0.9.8.5/Doc/Manual/special_methods.html0000644001243100001200000005337211012764052021047 0ustar00gregadmin00000000000000 Special Methods of Extenstion Types


    Special Methods of Extension Types

    This page describes the special methods currently supported by Pyrex extension types. A complete list of all the special methods appears in the table at the bottom. Some of these methods behave differently from their Python counterparts or have no direct Python counterparts, and require special mention.

    Note: Everything said on this page applies only to extension types, defined with the cdef class statement. It doesn't apply to classes defined with the Python class statement, where the normal Python rules apply.

    Declaration

    Special methods of extension types must be declared with def, not cdef.

    Docstrings

    Currently, docstrings are not fully supported in special methods of extension types. You can place a docstring in the source to serve as a comment, but it won't show up in the corresponding __doc__ attribute at run time. (This is a Python limitation -- there's nowhere in the PyTypeObject data structure to put such docstrings.)

    Initialisation methods: __cinit__ and __init__

    There are two methods concerned with initialising the object.

    The __cinit__ method is where you should perform basic C-level initialisation of the object, including allocation of any C data structures that your object will own. You need to be careful what you do in the __cinit__ method, because the object may not yet be a valid Python object when it is called. Therefore, you must not invoke any Python operations which might touch the object; in particular, do not try to call any of its methods.

    By the time your __cinit__ method is called, memory has been allocated for the object and any C attributes it has have been initialised to 0 or null. (Any Python attributes have also been initialised to None, but you probably shouldn't rely on that.) Your __cinit__ method is guaranteed to be called exactly once.

    If your extension type has a base type, the __cinit__ method of the base type is automatically called before your __cinit__ method is called; you cannot explicitly call the inherited __cinit__ method. If you need to pass a modified argument list to the base type, you will have to do the relevant part of the initialisation in the __init__ method instead (where the normal rules for calling inherited methods apply).

    Any initialisation which cannot safely be done in the __cinit__ method should be done in the __init__ method. By the time __init__ is called, the object is a fully valid Python object and all operations are safe. Under some circumstances it is possible for __init__ to be called more than once or not to be called at all, so your other methods should be designed to be robust in such situations.

    Any arguments passed to the constructor will be passed to both the __cinit__ method and the __init__ method. If you anticipate subclassing your extension type in Python, you may find it useful to give the __cinit__ method * and ** arguments so that it can accept and ignore extra arguments. Otherwise, any Python subclass which has an __init__ with a different signature will have to override __new__ as well as __init__, which the writer of a Python class wouldn't expect to have to do.

    Finalization method: __dealloc__

    The counterpart to the __cinit__ method is the __dealloc__ method, which should perform the inverse of the __cinit__ method. Any C data structures that you allocated in your __cinit__ method should be freed in your __dealloc__ method.

    You need to be careful what you do in a __dealloc__ method. By the time your __dealloc__ method is called, the object may already have been partially destroyed and may not be in a valid state as far as Python is concerned, so you should avoid invoking any Python operations which might touch the object. In particular, don't call any other methods of the object or do anything which might cause the object to be resurrected. It's best if you stick to just deallocating C data.

    You don't need to worry about deallocating Python attributes of your object, because that will be done for you by Pyrex after your __dealloc__ method returns.

    Note: There is no __del__ method for extension types.

    Arithmetic methods

    Arithmetic operator methods, such as __add__, behave differently from their Python counterparts. There are no separate "reversed" versions of these methods (__radd__, etc.) Instead, if the first operand cannot perform the operation, the same method of the second operand is called, with the operands in the same order.

    This means that you can't rely on the first parameter of these methods being "self", and you should test the types of both operands before deciding what to do. If you can't handle the combination of types you've been given, you should return NotImplemented.

    This also applies to the in-place arithmetic method __ipow__. It doesn't apply to any of the other in-place methods (__iadd__, etc.) which always take self as the first argument.

    Rich comparisons

    There are no separate methods for the individual rich comparison operations (__eq__, __le__, etc.) Instead there is a single method __richcmp__ which takes an integer indicating which operation is to be performed, as follows:
         
        <
        0
        ==
        2
        >
        4
        <=
        1
        !=
        3
        >=
        5

    The __next__ method

    Extension types wishing to implement the iterator interface should define a method called __next__, not next. The Python system will automatically supply a next method which calls your __next__. Do NOT explicitly give your type a next method, or bad things could happen.

    Type Testing in Special Methods (New in 0.9.7)

    When testing the types of operands to your special methods, the obvious way might appear to be to use the isinstance function. However, this is not completely safe, because it's possible for a class to override what gets returned by isinstance tests on its instances. This is not a great problem in Python code, but in Pyrex it could be disastrous, as we are relying on knowing the C layout of the objects we're dealing with.

    Pyrex provides an alternative function, typecheck, which corresponds to PyObject_TypeCheck in the Python/C API. This is safe to use, as it always tests the actual C type of the object.

    Similarly, there is an issubtype function, corresponding to PyType_IsSubType, as a safe alternative to issubclass.

    As an example, here's how you might write an __add__ method for an extension type called MyNumber:

    def __add__(x, y):
        if typecheck(x, MyNumber):
            # we are the left operand
            if typecheck(y, MyNumber):
                # add ourselves to another MyNumber and return result
            if typecheck(y, int):
                # add ourselves to an int and return result
        elseif typecheck(y, MyNumber):
            # we are the right operand
            if typecheck(x, int):
                # add an int to ourselves and return the result
        # Get here if unknown combination
        return NotImplemented

    Special Method Table

    This table lists all of the special methods together with their parameter and return types. In the table below, a parameter name of self is used to indicate that the parameter has the type that the method belongs to. Other parameters with no type specified in the table are generic Python objects.

    You don't have to declare your method as taking these parameter types. If you declare different types, conversions will be performed as necessary.
     
    Name Parameters Return type Description
    General
    __cinit__ self, ...   Basic initialisation (no direct Python equivalent)
    __init__ self, ...   Further initialisation
    __dealloc__ self   Basic deallocation (no direct Python equivalent)
    __cmp__ x, y int 3-way comparison
    __richcmp__ x, y, int op object Rich comparison (no direct Python equivalent)
    __str__ self object str(self)
    __repr__ self object repr(self)
    __hash__ self int Hash function
    __call__ self, ... object self(...)
    __iter__ self object Return iterator for sequence
    __getattr__ self, name object Get attribute
    __setattr__ self, name, val   Set attribute
    __delattr__ self, name   Delete attribute
    Arithmetic operators
    __add__ x, y object binary + operator
    __sub__ x, y object binary - operator
    __mul__ x, y object * operator
    __div__ x, y object /  operator for old-style division
    __floordiv__ x, y object //  operator
    __truediv__ x, y object /  operator for new-style division
    __mod__ x, y object % operator
    __divmod__ x, y object combined div and mod
    __pow__ x, y, z object ** operator or pow(x, y, z)
    __neg__ self object unary - operator
    __pos__ self object unary + operator
    __abs__ self object absolute value
    __nonzero__ self int convert to boolean
    __invert__ self object ~ operator
    __lshift__ x, y object << operator
    __rshift__ x, y object >> operator
    __and__ x, y object & operator
    __or__ x, y object | operator
    __xor__ x, y object ^ operator
    Numeric conversions
    __int__ self object Convert to integer
    __long__ self object Convert to long integer
    __float__ self object Convert to float
    __oct__ self object Convert to octal
    __hex__ self object Convert to hexadecimal
    __index__ (2.5+ only)selfobjectConvert to sequence index
    In-place arithmetic operators
    __iadd__ self, x object += operator
    __isub__ self, x object -= operator
    __imul__ self, x object *= operator
    __idiv__ self, x object /= operator for old-style division
    __ifloordiv__ self, x object //= operator
    __itruediv__ self, x object /= operator for new-style division
    __imod__ self, x object %= operator
    __ipow__ x, y, z object **= operator
    __ilshift__ self, x object <<= operator
    __irshift__ self, x object >>= operator
    __iand__ self, x object &= operator
    __ior__ self, x object |= operator
    __ixor__ self, x object ^= operator
    Sequences and mappings
    __len__ self int len(self)
    __getitem__ self, x object self[x]
    __setitem__ self, x, y   self[x] = y
    __delitem__ self, x   del self[x]
    __getslice__ self, Py_ssize_t i, Py_ssize_t j object self[i:j]
    __setslice__ self, Py_ssize_t i, Py_ssize_t j, x   self[i:j] = x
    __delslice__ self, Py_ssize_t i, Py_ssize_t j   del self[i:j]
    __contains__ self, x int x in self
    Iterators
    __next__ self object Get next item (called next in Python)
    Buffer interface  (no Python equivalents - see note 1)
    __getreadbuffer__ self, int i, void **p    
    __getwritebuffer__ self, int i, void **p    
    __getsegcount__ self, int *p    
    __getcharbuffer__ self, int i, char **p    
    Descriptor objects  (see note 2)
    __get__ self, instance, class object Get value of attribute
    __set__ self, instance, value   Set value of attribute
    __delete__ self, instance   Delete attribute

    Note 1: The buffer interface is intended for use by C code and is not directly accessible from Python. It is described in the Python/C API Reference Manual under sections 6.6 and 10.6.

    Note 2: Descriptor objects are part of the support mechanism for new-style Python classes. See the discussion of descriptors in the Python documentation. See also PEP 252, "Making Types Look More Like Classes", and PEP 253, "Subtyping Built-In Types".


    Pyrex-0.9.8.5/Doc/primes.c0000644001243100001200000000773507516451245015261 0ustar00gregadmin00000000000000#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 */ Pyrex-0.9.8.5/hgignore0000644001243100001200000000015311015707530014607 0ustar00gregadmin00000000000000glob:*.pyc glob:*.o glob:*.so glob:.DS_Store glob:*.pickle glob:*.dep glob:*.orig glob:*.new glob:*_copy.c Pyrex-0.9.8.5/INSTALL.txt0000644001243100001200000000103510556551457014747 0ustar00gregadmin00000000000000Pyrex - Installation Instructions ================================= You have two installation options: (1) Run the setup.py script in this directory as follows: python setup.py install This will install the Pyrex package into your Python system. OR (2) If you prefer not to modify your Python installation, arrange for the directory containing this file (INSTALL.txt) to be in your PYTHONPATH. On unix, also put the bin directory on your PATH. See README.txt for pointers to other documentation. Pyrex-0.9.8.5/Makefile0000644001243100001200000000046611055215202014523 0ustar00gregadmin00000000000000VERSION = 0.9.8.5 version: @echo "Setting version to $(VERSION)" @echo "version = '$(VERSION)'" > Pyrex/Compiler/Version.py clean: @echo Cleaning Source @rm -f *.pyc */*.pyc */*/*.pyc @rm -f *~ */*~ */*/*~ @rm -f core */core @(cd Demos; $(MAKE) clean) test_setup: python setup.py --dry-run install Pyrex-0.9.8.5/MANIFEST.in0000644001243100001200000000030410556551457014634 0ustar00gregadmin00000000000000include MANIFEST.in README.txt INSTALL.txt CHANGES.txt ToDo.txt USAGE.txt include setup.py include bin/pyrexc include pyrexc.py include Pyrex/Compiler/Lexicon.pickle include Doc/* include Demos/* Pyrex-0.9.8.5/Obsolete/overview.html0000644001243100001200000014273610700140177017406 0ustar00gregadmin00000000000000 Pyrex Language Overview


    Overview of the Pyrex Language 

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

    Contents


    Source Files and Compilation



    Pyrex source file names consist of the name of the module followed by a .pyx extension, for example a module called primes would have a source file named primes.pyx.

    If your module is destined to live in a package, the source file name should include the full dotted name that the module will eventually have. For example, a module called primes that will be installed in a package called numbers should have a source file called numbers.primes.pyx. This will ensure that the __name__ properties of the module and any classes defined in it are set correctly. If you don't do this, you may find that pickling doesn't work, among other problems. It also ensures that the Pyrex compiler has the right idea about the layout of the module namespace, which can be important when accessing extension types defined in other modules.

    Once you have written your .pyx file, there are a couple of ways of turning it into an extension module. One way is to compile it manually with the Pyrex compiler, e.g.

    pyrexc primes.pyx

    This will produce a file called primes.c, which then needs to be compiled with the C compiler using whatever options are appropriate on your platform for generating an extension module. There's a Makefile in the Demos directory (called Makefile.nodistutils) that shows how to do this for Linux.

    The other, and probably better, way is to use the distutils extension provided with Pyrex. See the Setup.py file in the Demos directory for an example of how to use it. This method has the advantage of being cross-platform -- the same setup file should work on any platform where distutils can compile an extension module.


    Language Basics

    This section describes the basic features of the Pyrex 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 Pyrex modules.

    Python functions vs. C functions

    There are two kinds of function definition in Pyrex:

    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 Pyrex 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 Pyrex 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.

    Pyrex detects and prevents some mistakes of this kind. For instance, if you attempt something like
    cdef char *s
    s = pystring1 + pystring2
    then Pyrex 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 Pyrex 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, Pyrex 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 Pyrex 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

    Pyrex 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 Pyrex:
    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 Pyrex expressions

    There are some differences in syntax and semantics between C expressions and Pyrex 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 Pyrex. Instead of p->x, use p.x
    •  
    • There is no * operator in Pyrex. 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 Pyrex 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, Pyrex 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 Pyrex 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, Pyrex generates a call to PyErr_Occurred if 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 Pyrex 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:

    • Exception values can only declared for functions returning an integer, enum, float or pointer type, and the value must be a constant expression. 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-Pyrex 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 Pyrex 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 Pyrex 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 Pyrex 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 Pyrex module accessible to another. However, note that some of these uses have been superseded by the facilities described in Sharing Declarations Between Pyrex Modules, and it is expected that use of the include statement for this purpose will be phased out altogether in future versions.


    Keyword-only arguments

    Python functions can have keyword-only arguments listed after the * parameter and before the ** paramter if any, e.g.

    def f(a, b, *args, c, d = 42, e, **kwds):
    ...
    Here c, d and e cannot be passed as position arguments and must be passed as keyword arguments. Furthermore, c and e are required keyword arguments, since they do not have a default value.

    If the parameter name after the * is omitted, the function will not accept any extra positional arguments, e.g.

    def g(a, b, *, c, d):
    ...
    takes exactly two positional parameters and has two required keyword parameters.


    Interfacing with External C Code

    One of the main uses of Pyrex 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 Pyrex 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 Pyrex 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, Pyrex 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 Pyrex 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 Pyrex to place a #include statement for the named header file in the generated C code.
    2.  
    3. It prevents Pyrex 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 Pyrex does not itself read the C header file, so you still need to provide Pyrex versions of any declarations from it that you use. However, the Pyrex 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. Pyrex 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 Pyrex declarations match the style used in the header file, so that Pyrex can emit the right sort of references to the type in the code it generates. To make this possible, Pyrex 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 Pyrex 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 Pyrex code simply as Foo, not struct Foo.
     
      C code Possibilities for corresponding Pyrex code Comments
    1 struct Foo {
      ...
    };
    cdef struct Foo:
      ...
    Pyrex will refer to the type as struct Foo in the generated C code.
    2 typedef struct {
      ...
    } Foo;
    ctypedef struct Foo:
      ...
    Pyrex 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 Pyrex (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, Py_ssize_t len)
    will allow you to create Python strings containing null bytes.

    Special Types

    Pyrex predefines the name Py_ssize_t for use with Python/C API routines. To make your extensions compatible with 64-bit systems, you should always use this type where it is specified in the documentation of Python/C API routines.

    Windows Calling Conventions

    The __stdcall and __cdecl calling convention specifiers can be used in Pyrex, with the same syntax as used by C compilers on Windows, for example,

    cdef extern int __stdcall FrobnicateWindow(long handle)

    cdef void (__stdcall *callback)(void *)
    If __stdcall is used, the function is only considered compatible with other __stdcall functions of the same signature.

    Resolving naming conflicts - C name specifications

    Each Pyrex 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.

    Pyrex 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 Pyrex modules.

    The other way is to use a c name specification to give different Pyrex 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 Pyrex 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 Pyrex keywords. For example, if you want to call an external function called print, you can rename it to something else in your Pyrex 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

    Using Pyrex Declarations from C

    Pyrex provides two methods for making C declarations from a Pyrex module available for use by external C code – public declarations and C API declarations.

    NOTE: You do not need to use either of these to make declarations from one Pyrex module available to another Pyrex module – you should use the cimport statement for that. Sharing Declarations Between Pyrex Modules.

    Public Declarations

    You can make C types, variables and functions defined in a Pyrex module accessible to C code that is linked with the module, by declaring them with the public keyword:
    cdef public struct Bunny: # public type declaration
        int vorpalness

    cdef public int spam # public variable declaration

    cdef public void grail(Bunny *): # public function declaration
        ...

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

    Any C code wanting to make use of these declarations will need to be linked, either statically or dynamically, with the extension module.

    If the Pyrex module resides within a package, then the name of the .h file consists of the full dotted name of the module, e.g. a module called foo.spam would have a header file called foo.spam.h.

    C API Declarations

    The other way of making functions available to C code is by declaring them with the api keyword. A header file called "modulename_api.h" is produced containing declarations of the functions, and a function called import_modulename().

    C code wanting to use the functions needs to include the header and call the import_modulename() function. The other functions can then be called as usual.

    Any public type declarations in the Pyrex module are also made available when you include modulename_api.h.

    delorean.pyx
    marty.c
    cdef public struct Vehicle:
    int speed
    float power

    cdef api void activate(Vehicle *v):
    if v.speed >= 88 \
    and v.power >= 1.21:
    print "Time travel achieved"
    #include "delorean_api.h"

    Vehicle car;

    int main(int argc, char *argv[]) {
    import_delorean();
    car.speed = atoi(argv[1]);
    car.power = atof(argv[2]); 
    activate(&car);
    }

    This method does not require the C code using the functions to be linked with the extension module in any way, as the Python import machinery is used to make the connection dynamically. However, only functions can be accessed this way, not variables.You can use both public and api on the same function to make it available by both methods, e.g.
    cdef public api void belt_and_braces():
    ...
    However, note that you should include either modulename.h or modulename_api.h in a given C file, not both, otherwise you may get conflicting dual definitions.

    If the Pyrex module resides within a package, then:
    • The name of the header file contains of the full dotted name of the module.
    • The name of the importing function contains the full name with dots replaced by double underscores.
    E.g. a module called foo.spam would have an API header file called foo.spam_api.h and an importing function called import_foo__spam().


    Extension Types

    One of the most powerful features of Pyrex 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 Pyrex Modules

    Pyrex 0.8 introduces a substantial new set of facilities allowing a Pyrex module to easily import and use C declarations and extension types from another Pyrex module. You can now create a set of co-operating Pyrex 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

    Pyrex 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 Pyrex.

  • 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 Pyrex'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 Pyrex doesn't optimize them away, and won't even accept them in places where executable statements are not allowed.
  • Semantic differences between Python and Pyrex

    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 Pyrex 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 Pyrex. 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 Pyrex-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, Pyrex wraps each method in an unbound method object itself before storing it in the class's dictionary.
     

    Pyrex-0.9.8.5/Obsolete/PyrexTypes.py.old0000644001243100001200000006220110571502650020125 0ustar00gregadmin00000000000000# # Pyrex - Types # import string import Naming class PyrexType: # # Base class for all Pyrex types. # # is_pyobject boolean Is a Python object type # is_extension_type boolean Is a Python extension type # is_numeric boolean Is a C numeric type # is_int boolean Is a C integer type # is_float boolean Is a C floating point type # is_void boolean Is the C void type # is_array boolean Is a C array type # is_ptr boolean Is a C pointer type # is_null_ptr boolean Is the type of NULL # is_cfunction boolean Is a C function type # is_struct_or_union boolean Is a C struct or union type # is_enum boolean Is a C enum type # is_string boolean Is a C char * type # is_returncode boolean Is used only to signal exceptions # is_error boolean Is the dummy error type # has_attributes boolean Has C dot-selectable attributes # default_value string Initial value # parsetuple_format string Format char for PyArg_ParseTuple # pymemberdef_typecode string Type code for PyMemberDef struct # # declaration_code(entity_code, # for_display = 0, dll_linkage = None, pyrex = 0) # Returns a code fragment for the declaration of an entity # of this type, given a code fragment for the entity. # * If for_display, this is for reading by a human in an error # message; otherwise it must be valid C code. # * If dll_linkage is not None, it must be 'DL_EXPORT' or # 'DL_IMPORT', and will be added to the base type part of # the declaration. # * If pyrex = 1, this is for use in a 'cdef extern' # statement of a Pyrex include file. # # assignable_from(src_type) # Tests whether a variable of this type can be # assigned a value of type src_type. # # same_as(other_type) # Tests whether this type represents the same type # as other_type. # # as_argument_type(): # Coerces array type into pointer type for use as # a formal argument type. # is_pyobject = 0 is_extension_type = 0 is_numeric = 0 is_int = 0 is_float = 0 is_void = 0 is_array = 0 is_ptr = 0 is_null_ptr = 0 is_cfunction = 0 is_struct_or_union = 0 is_enum = 0 is_string = 0 is_returncode = 0 is_error = 0 has_attributes = 0 default_value = "" parsetuple_format = "" pymemberdef_typecode = None def resolve(self): # If a typedef, returns the base type. return self def literal_code(self, value): # Returns a C code fragment representing a literal # value of this type. return str(value) def __str__(self): return string.strip(self.declaration_code("", for_display = 1)) def same_as(self, other_type, **kwds): return self.same_as_resolved_type(other_type.resolve(), **kwds) def same_as_resolved_type(self, other_type): return self is other_type or other_type is error_type def subtype_of(self, other_type): return self.subtype_of_resolved_type(other_type.resolve()) def subtype_of_resolved_type(self, other_type): return self.same_as(other_type) def assignable_from(self, src_type): return self.assignable_from_resolved_type(src_type.resolve()) def assignable_from_resolved_type(self, src_type): return self.same_as(src_type) def as_argument_type(self): return self def is_complete(self): # A type is incomplete if it is an unsized array, # a struct whose attributes are not defined, etc. return 1 def cast_code(self, expr_code): return "((%s)%s)" % (self.declaration_code(""), expr_code) class CTypedefType: # # Type defined with a ctypedef statement in a # 'cdef extern from' block. Delegates most attribute # lookups to the base type. # def __init__(self, cname, base_type): self.typedef_cname = cname self.typedef_base_type = base_type def resolve(self): return self.typedef_base_type.resolve() def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): return "%s %s" % (self.typedef_cname, entity_code) def as_argument_type(self): return self def __str__(self): return self.typedef_cname def __getattr__(self, name): return getattr(self.typedef_base_type, name) class PyObjectType(PyrexType): # # Base class for all Python object types (reference-counted). # is_pyobject = 1 default_value = "0" parsetuple_format = "O" pymemberdef_typecode = "T_OBJECT" def __str__(self): return "Python object" def __repr__(self): return "PyObjectType" def assignable_from(self, src_type): return 1 # Conversion will be attempted def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): if pyrex: return "object %s" % entity_code else: return "%s *%s" % (public_decl("PyObject", dll_linkage), entity_code) class PyExtensionType(PyObjectType): # # A Python extension type. # # name string # scope CClassScope Attribute namespace # visibility string # typedef_flag boolean # base_type PyExtensionType or None # module_name string or None Qualified name of defining module # objstruct_cname string Name of PyObject struct # typeobj_cname string or None C code fragment referring to type object # typeptr_cname string or None Name of pointer to external type object # vtabslot_cname string Name of C method table member # vtabstruct_cname string Name of C method table struct # vtabptr_cname string Name of pointer to C method table # vtable_cname string Name of C method table definition is_extension_type = 1 has_attributes = 1 def __init__(self, name, typedef_flag, base_type): self.name = name self.scope = None self.typedef_flag = typedef_flag self.base_type = base_type self.module_name = None self.objstruct_cname = None self.typeobj_cname = None self.typeptr_cname = None self.vtabslot_cname = None self.vtabstruct_cname = None self.vtabptr_cname = None self.vtable_cname = None def set_scope(self, scope): self.scope = scope if scope: scope.parent_type = self def subtype_of_resolved_type(self, other_type): if other_type.is_extension_type: return self is other_type or ( self.base_type and self.base_type.subtype_of(other_type)) else: return other_type is py_object_type def typeobj_is_available(self): # Do we have a pointer to the type object? return self.typeptr_cname def typeobj_is_imported(self): # If we don't know the C name of the type object but we do # know which module it's defined in, it will be imported. return self.typeobj_cname is None and self.module_name is not None def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): if pyrex: return "%s %s" % (self.name, entity_code) else: if self.typedef_flag: base_format = "%s" else: base_format = "struct %s" base = public_decl(base_format % self.objstruct_cname, dll_linkage) return "%s *%s" % (base, entity_code) def attributes_known(self): return self.scope is not None def __str__(self): return self.name def __repr__(self): return "PyExtensionType(%s%s)" % (self.scope.class_name, ("", ".typedef_flag=1")[self.typedef_flag]) class CType(PyrexType): # # Base class for all C types (non-reference-counted). # # to_py_function string C function for converting to Python object # from_py_function string C function for constructing from Python object # to_py_function = None from_py_function = None #class CSimpleType(CType): # # # # Base class for all unstructured C types. # # # pass class CVoidType(CType): is_void = 1 def __repr__(self): return "" def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): base = public_decl("void", dll_linkage) return "%s %s" % (base, entity_code) def is_complete(self): return 0 class CNumericType(CType): # # Base class for all C numeric types. # # rank integer Relative size # signed boolean # is_numeric = 1 default_value = "0" parsetuple_formats = ( # rank -> format "?HIkK???", # unsigned "chilLfd?", # signed ) def __init__(self, rank, signed = 1, pymemberdef_typecode = None): self.rank = rank self.signed = signed ptf = self.parsetuple_formats[signed][rank] if ptf == '?': ptf = None self.parsetuple_format = ptf self.pymemberdef_typecode = pymemberdef_typecode def __repr__(self): if self.signed: u = "" else: u = "unsigned " return "" % (u, rank_to_type_name[self.rank]) def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): if self.signed: u = "" else: u = "unsigned " base = public_decl(u + rank_to_type_name[self.rank], dll_linkage) return "%s %s" % (base, entity_code) class CIntType(CNumericType): is_int = 1 typedef_flag = 0 to_py_function = "PyInt_FromLong" from_py_function = "PyInt_AsLong" def __init__(self, rank, signed, pymemberdef_typecode = None, is_returncode = 0): CNumericType.__init__(self, rank, signed, pymemberdef_typecode) self.is_returncode = is_returncode def assignable_from_resolved_type(self, src_type): return src_type.is_int or src_type.is_enum or src_type is error_type class CUIntType(CIntType): to_py_function = "PyLong_FromUnsignedLong" from_py_function = "PyInt_AsUnsignedLongMask" class CULongType(CIntType): to_py_function = "PyLong_FromUnsignedLong" from_py_function = "PyInt_AsUnsignedLongMask" class CLongLongType(CIntType): to_py_function = "PyLong_FromLongLong" from_py_function = "PyInt_AsUnsignedLongLongMask" class CULongLongType(CIntType): to_py_function = "PyLong_FromUnsignedLongLong" from_py_function = "PyInt_AsUnsignedLongLongMask" class CFloatType(CNumericType): is_float = 1 to_py_function = "PyFloat_FromDouble" from_py_function = "PyFloat_AsDouble" def __init__(self, rank, pymemberdef_typecode = None): CNumericType.__init__(self, rank, 1, pymemberdef_typecode) def assignable_from_resolved_type(self, src_type): return src_type.is_numeric or src_type is error_type class CArrayType(CType): # base_type CType Element type # size integer or None Number of elements is_array = 1 def __init__(self, base_type, size): self.base_type = base_type self.size = size if base_type is c_char_type: self.is_string = 1 def __repr__(self): return "CArrayType(%s,%s)" % (self.size, repr(self.base_type)) def same_as_resolved_type(self, other_type): return ((other_type.is_array and self.base_type.same_as(other_type.base_type)) or other_type is error_type) def assignable_from_resolved_type(self, src_type): # Can't assign to a variable of an array type return 0 def element_ptr_type(self): return c_ptr_type(self.base_type) def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): if self.size is not None: dimension_code = self.size else: dimension_code = "" return self.base_type.declaration_code( "(%s[%s])" % (entity_code, dimension_code), for_display, dll_linkage, pyrex) def as_argument_type(self): return c_ptr_type(self.base_type) def is_complete(self): return self.size is not None class CPtrType(CType): # base_type CType Referenced type is_ptr = 1 default_value = 0 def __init__(self, base_type): self.base_type = base_type def __repr__(self): return "CPtrType(%s)" % repr(self.base_type) def same_as_resolved_type(self, other_type): return ((other_type.is_ptr and self.base_type.same_as(other_type.base_type)) or other_type is error_type) def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): #print "CPtrType.declaration_code: pointer to", self.base_type ### return self.base_type.declaration_code( "(*%s)" % entity_code, for_display, dll_linkage, pyrex) def assignable_from_resolved_type(self, other_type): if other_type is error_type: return 1 elif self.base_type.is_cfunction and other_type.is_cfunction: return self.base_type.same_as(other_type) elif other_type.is_array: return self.base_type.same_as(other_type.base_type) elif not other_type.is_ptr: return 0 elif self.base_type.is_void: return 1 elif other_type.is_null_ptr: return 1 else: return self.base_type.same_as(other_type.base_type) class CNullPtrType(CPtrType): is_null_ptr = 1 class CFuncType(CType): # return_type CType # args [CFuncTypeArg] # has_varargs boolean # exception_value string # exception_check boolean True if PyErr_Occurred check needed is_cfunction = 1 def __init__(self, return_type, args, has_varargs, exception_value = None, exception_check = 0): self.return_type = return_type self.args = args self.has_varargs = has_varargs self.exception_value = exception_value self.exception_check = exception_check def __repr__(self): arg_reprs = map(repr, self.args) if self.has_varargs: arg_reprs.append("...") return "CFuncType(%s,[%s])" % ( repr(self.return_type), string.join(arg_reprs, ",")) def same_c_signature_as(self, other_type, as_cmethod = 0): return self.same_c_signature_as_resolved_type( other_type.resolve(), as_cmethod) def same_c_signature_as_resolved_type(self, other_type, as_cmethod): if other_type is error_type: return 1 if not other_type.is_cfunction: return 0 nargs = len(self.args) if nargs <> len(other_type.args): return 0 # When comparing C method signatures, the first argument # is exempt from compatibility checking (the proper check # is performed elsewhere). for i in range(as_cmethod, nargs): if not self.args[i].type.same_as( other_type.args[i].type): return 0 if self.has_varargs <> other_type.has_varargs: return 0 if not self.return_type.same_as(other_type.return_type): return 0 return 1 def same_exception_signature_as(self, other_type): return self.same_exception_signature_as_resolved_type( other_type.resolve()) def same_exception_signature_as_resolved_type(self, other_type): return self.exception_value == other_type.exception_value \ and self.exception_check == other_type.exception_check def same_as_resolved_type(self, other_type, as_cmethod = 0): return self.same_c_signature_as_resolved_type(other_type, as_cmethod) \ and self.same_exception_signature_as_resolved_type(other_type) def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): arg_decl_list = [] for arg in self.args: arg_decl_list.append( arg.type.declaration_code("", for_display, pyrex = pyrex)) if self.has_varargs: arg_decl_list.append("...") arg_decl_code = string.join(arg_decl_list, ",") if not arg_decl_code and not pyrex: arg_decl_code = "void" exc_clause = "" if pyrex or for_display: if self.exception_value and self.exception_check: exc_clause = " except? %s" % self.exception_value elif self.exception_value: exc_clause = " except %s" % self.exception_value elif self.exception_check: exc_clause = " except *" return self.return_type.declaration_code( "(%s(%s)%s)" % (entity_code, arg_decl_code, exc_clause), for_display, dll_linkage, pyrex) class CFuncTypeArg: # name string # cname string # type PyrexType # pos source file position def __init__(self, name, type, pos): self.name = name self.cname = Naming.var_prefix + name self.type = type self.pos = pos def __repr__(self): return "%s:%s" % (self.name, repr(self.type)) def declaration_code(self, for_display = 0): return self.type.declaration_code(self.cname, for_display) class CStructOrUnionType(CType): # name string # cname string # kind string "struct" or "union" # scope StructOrUnionScope, or None if incomplete # typedef_flag boolean is_struct_or_union = 1 has_attributes = 1 def __init__(self, name, kind, scope, typedef_flag, cname): self.name = name self.cname = cname self.kind = kind self.scope = scope self.typedef_flag = typedef_flag def __repr__(self): return "CStructOrUnionType(%s,%s%s)" % (self.name, self.cname, ("", ",typedef_flag=1")[self.typedef_flag]) def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): if pyrex: return "%s %s" % (self.name, entity_code) else: if for_display: base = self.name elif self.typedef_flag: base = self.cname else: base = "%s %s" % (self.kind, self.cname) return "%s %s" % (public_decl(base, dll_linkage), entity_code) def is_complete(self): return self.scope is not None def attributes_known(self): return self.is_complete() class CEnumType(CType): # name string # cname string or None # typedef_flag boolean is_enum = 1 #signed = 1 #rank = 2 to_py_function = "PyInt_FromLong" from_py_function = "PyInt_AsLong" def __init__(self, name, cname, typedef_flag): self.name = name self.cname = cname self.values = [] self.typedef_flag = typedef_flag def __repr__(self): return "CEnumType(%s,%s%s)" % (self.name, self.cname, ("", ",typedef_flag=1")[self.typedef_flag]) def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): if pyrex: return "%s %s" % (self.cname, entity_code) else: if self.typedef_flag: base = self.cname else: base = "enum %s" % self.cname return "%s %s" % (public_decl(base, dll_linkage), entity_code) class CStringType: # Mixin class for C string types. is_string = 1 to_py_function = "PyString_FromString" from_py_function = "PyString_AsString" def literal_code(self, value): return '"%s"' % value class CCharArrayType(CStringType, CArrayType): # C 'char []' type. parsetuple_format = "s" pymemberdef_typecode = "T_STRING_INPLACE" def __init__(self, size): CArrayType.__init__(self, c_char_type, size) class CCharPtrType(CStringType, CPtrType): # C 'char *' type. parsetuple_format = "s" pymemberdef_typecode = "T_STRING" def __init__(self): CPtrType.__init__(self, c_char_type) class ErrorType(PyrexType): # Used to prevent propagation of error messages. is_error = 1 exception_value = "0" exception_check = 0 to_py_function = "dummy" from_py_function = "dummy" def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): return "" def same_as_resolved_type(self, other_type): return 1 py_object_type = PyObjectType() c_void_type = CVoidType() c_void_ptr_type = CPtrType(c_void_type) c_void_ptr_ptr_type = CPtrType(c_void_ptr_type) c_char_type = CIntType(0, 1, "T_CHAR") c_short_type = CIntType(1, 1, "T_SHORT") c_int_type = CIntType(2, 1, "T_INT") c_long_type = CIntType(3, 1, "T_LONG") c_longlong_type = CLongLongType(4, 1, "T_LONGLONG") c_uchar_type = CIntType(0, 0, "T_UBYTE") c_ushort_type = CIntType(1, 0, "T_USHORT") c_uint_type = CUIntType(2, 0, "T_UINT") c_ulong_type = CULongType(3, 0, "T_ULONG") c_ulonglong_type = CULongLongType(4, 0, "T_ULONGLONG") c_float_type = CFloatType(5, "T_FLOAT") c_double_type = CFloatType(6, "T_DOUBLE") c_longdouble_type = CFloatType(7) c_null_ptr_type = CNullPtrType(c_void_type) c_char_array_type = CCharArrayType(None) c_char_ptr_type = CCharPtrType() c_char_ptr_ptr_type = CPtrType(c_char_ptr_type) c_int_ptr_type = CPtrType(c_int_type) c_returncode_type = CIntType(2, 1, "T_INT", is_returncode = 1) error_type = ErrorType() lowest_float_rank = 5 rank_to_type_name = ( "char", # 0 "short", # 1 "int", # 2 "long", # 3 "PY_LONG_LONG", # 4 "float", # 5 "double", # 6 "long double", # 7 ) sign_and_rank_to_type = { #(signed, rank) (0, 0, ): c_uchar_type, (0, 1): c_ushort_type, (0, 2): c_uint_type, (0, 3): c_ulong_type, (0, 4): c_ulonglong_type, (1, 0): c_char_type, (1, 1): c_short_type, (1, 2): c_int_type, (1, 3): c_long_type, (1, 4): c_longlong_type, (1, 5): c_float_type, (1, 6): c_double_type, (1, 7): c_longdouble_type, } modifiers_and_name_to_type = { #(signed, longness, name) (0, 0, "char"): c_uchar_type, (0, -1, "int"): c_ushort_type, (0, 0, "int"): c_uint_type, (0, 1, "int"): c_ulong_type, (0, 2, "int"): c_ulonglong_type, (1, 0, "void"): c_void_type, (1, 0, "char"): c_char_type, (1, -1, "int"): c_short_type, (1, 0, "int"): c_int_type, (1, 1, "int"): c_long_type, (1, 2, "int"): c_longlong_type, (1, 0, "float"): c_float_type, (1, 0, "double"): c_double_type, (1, 1, "double"): c_longdouble_type, (1, 0, "object"): py_object_type, } def widest_numeric_type(type1, type2): # Given two numeric types, return the narrowest type # encompassing both of them. signed = type1.signed rank = max(type1.rank, type2.rank) if rank >= lowest_float_rank: signed = 1 return sign_and_rank_to_type[signed, rank] def simple_c_type(signed, longness, name): # Find type descriptor for simple type given name and modifiers. # Returns None if arguments don't make sense. return modifiers_and_name_to_type.get((signed, longness, name)) def c_array_type(base_type, size): # Construct a C array type. if base_type is c_char_type: return CCharArrayType(size) else: return CArrayType(base_type, size) def c_ptr_type(base_type): # Construct a C pointer type. if base_type is c_char_type: return c_char_ptr_type else: return CPtrType(base_type) def public_decl(base, dll_linkage): if dll_linkage: return "%s(%s)" % (dll_linkage, base) else: return base def same_type(type1, type2): return type1.same_as(type2) def assignable_from(type1, type2): return type1.assignable_from(type2) def typecast(to_type, from_type, expr_code): # Return expr_code cast to a C type which can be # assigned to to_type, assuming its existing C type # is from_type. if to_type is from_type or \ (not to_type.is_pyobject and assignable_from(to_type, from_type)): return expr_code else: #print "typecast: to", to_type, "from", from_type ### return to_type.cast_code(expr_code) Pyrex-0.9.8.5/Pyrex/__init__.py0000644001243100001200000000000010556551457016307 0ustar00gregadmin00000000000000Pyrex-0.9.8.5/Pyrex/Compiler/__init__.py0000644001243100001200000000000010556551457020061 0ustar00gregadmin00000000000000Pyrex-0.9.8.5/Pyrex/Compiler/Builtin.py0000644001243100001200000002417510773327162017746 0ustar00gregadmin00000000000000# # Pyrex - Builtin Definitions # from Symtab import BuiltinScope from TypeSlots import Signature from PyrexTypes import py_type_type builtin_constant_table = [ # name, type/ctype, C API name ("buffer", "t", "(&PyBuffer_Type)"), ("enumerate", "t", "(&PyEnum_Type)"), ("file", "t", "(&PyFile_Type)"), ("float", "t", "(&PyFloat_Type)"), ("int", "t", "(&PyInt_Type)"), ("long", "t", "(&PyLong_Type)"), ("open", "t", "(&PyFile_Type)"), ("property", "t", "(&PyProperty_Type)"), ("str", "t", "(&PyString_Type)"), ("tuple", "t", "(&PyTuple_Type)"), ("xrange", "t", "(&PyRange_Type)"), ("True", "O", "Py_True"), ("False", "O", "Py_False"), ("Ellipsis", "O", "Py_Ellipsis"), ("Exception", "t/O", "PyExc_Exception"), ("StopIteration", "t/O", "PyExc_StopIteration"), ("StandardError", "t/O", "PyExc_StandardError"), ("ArithmeticError", "t/O", "PyExc_ArithmeticError"), ("LookupError", "t/O", "PyExc_LookupError"), ("AssertionError", "t/O", "PyExc_AssertionError"), ("EOFError", "t/O", "PyExc_EOFError"), ("FloatingPointError", "t/O", "PyExc_FloatingPointError"), ("EnvironmentError", "t/O", "PyExc_EnvironmentError"), ("IOError", "t/O", "PyExc_IOError"), ("OSError", "t/O", "PyExc_OSError"), ("ImportError", "t/O", "PyExc_ImportError"), ("IndexError", "t/O", "PyExc_IndexError"), ("KeyError", "t/O", "PyExc_KeyError"), ("KeyboardInterrupt", "t/O", "PyExc_KeyboardInterrupt"), ("MemoryError", "t/O", "PyExc_MemoryError"), ("NameError", "t/O", "PyExc_NameError"), ("OverflowError", "t/O", "PyExc_OverflowError"), ("RuntimeError", "t/O", "PyExc_RuntimeError"), ("NotImplementedError", "t/O", "PyExc_NotImplementedError"), ("SyntaxError", "t/O", "PyExc_SyntaxError"), ("IndentationError", "t/O", "PyExc_IndentationError"), ("TabError", "t/O", "PyExc_TabError"), ("ReferenceError", "t/O", "PyExc_ReferenceError"), ("SystemError", "t/O", "PyExc_SystemError"), ("SystemExit", "t/O", "PyExc_SystemExit"), ("TypeError", "t/O", "PyExc_TypeError"), ("UnboundLocalError", "t/O", "PyExc_UnboundLocalError"), ("UnicodeError", "t/O", "PyExc_UnicodeError"), ("UnicodeEncodeError", "t/O", "PyExc_UnicodeEncodeError"), ("UnicodeDecodeError", "t/O", "PyExc_UnicodeDecodeError"), ("UnicodeTranslateError", "t/O", "PyExc_UnicodeTranslateError"), ("ValueError", "t/O", "PyExc_ValueError"), ("ZeroDivisionError", "t/O", "PyExc_ZeroDivisionError"), # Not including these by default because they are platform-specific #("WindowsError", "t/O", "PyExc_WindowsError"), #("VMSError", "t/O", "PyExc_VMSError"), ("MemoryErrorInst", "t/O", "PyExc_MemoryErrorInst"), ("Warning", "t/O", "PyExc_Warning"), ("UserWarning", "t/O", "PyExc_UserWarning"), ("DeprecationWarning", "t/O", "PyExc_DeprecationWarning"), ("PendingDeprecationWarning", "t/O", "PyExc_PendingDeprecationWarning"), ("SyntaxWarning", "t/O", "PyExc_SyntaxWarning"), ("OverflowWarning", "t/O", "PyExc_OverflowWarning"), ("RuntimeWarning", "t/O", "PyExc_RuntimeWarning"), ("FutureWarning", "t/O", "PyExc_FutureWarning"), ] builtin_function_table = [ # name, args, return, C API func, py equiv = "*" ('abs', "O", "O", "PyNumber_Absolute"), ('bool', "O", "i", "PyObject_IsTrue"), #('chr', "", "", ""), #('cmp', "", "", "", ""), # int PyObject_Cmp(PyObject *o1, PyObject *o2, int *result) #('compile', "", "", ""), # PyObject* Py_CompileString( char *str, char *filename, int start) ('delattr', "OO", "r", "PyObject_DelAttr"), ('dir', "O", "O", "PyObject_Dir"), ('divmod', "OO", "O", "PyNumber_Divmod"), #('eval', "", "", ""), #('execfile', "", "", ""), #('filter', "", "", ""), ('getattr', "OO", "O", "PyObject_GetAttr"), ('getattr3', "OOO", "O", "__Pyx_GetAttr3", "getattr"), ('hasattr', "OO", "i", "PyObject_HasAttr"), ('hash', "O", "i", "PyObject_Hash"), #('hex', "", "", ""), #('id', "", "", ""), #('input', "", "", ""), ('intern', "s", "O", "PyString_InternFromString"), ('isinstance', "OO", "i", "PyObject_IsInstance"), ('issubclass', "OO", "i", "PyObject_IsSubclass"), ('iter', "O", "O", "PyObject_GetIter"), ('len', "O", "Z", "PyObject_Length"), #('map', "", "", ""), #('max', "", "", ""), #('min', "", "", ""), #('oct', "", "", ""), # Not worth doing open, when second argument would become mandatory #('open', "ss", "O", "PyFile_FromString"), #('ord', "", "", ""), ('pow', "OOO", "O", "PyNumber_Power"), #('range', "", "", ""), #('raw_input', "", "", ""), #('reduce', "", "", ""), ('reload', "O", "O", "PyImport_ReloadModule"), ('repr', "O", "O", "PyObject_Repr"), #('round', "", "", ""), ('setattr', "OOO", "r", "PyObject_SetAttr"), #('sum', "", "", ""), #('unichr', "", "", ""), #('unicode', "", "", ""), #('vars', "", "", ""), #('zip', "", "", ""), ('typecheck', "Ot", "b", "PyObject_TypeCheck", False), ('issubtype', "tt", "b", "PyType_IsSubtype", False), ] dict_methods = [ # name, args, return, C API func ("clear", "O", "v", "PyDict_Clear"), ("copy", "O", "O", "PyDict_Copy"), ("items", "O", "O", "PyDict_Items"), ("keys", "O", "O", "PyDict_Keys"), ("values", "O", "O", "PyDict_Values"), ("merge", "OOi", "r", "PyDict_Merge"), ("update", "OO", "r", "PyDict_Update"), ("merge_pairs", "OOi", "r", "PyDict_MergeFromSeq2"), ] list_methods = [ # name, args, return, C API func ("insert", "OiO", "r", "PyList_Insert"), ("append", "OO", "r", "PyList_Append"), ("sort", "O", "r", "PyList_Sort"), ("reverse", "O", "r", "PyList_Reverse"), ("as_tuple", "O", "O", "PyList_AsTuple"), ] slice_methods = [ # name, args, return, C API func ("indices", "O", "O", "PySlice_Indices"), ] slice_members = [ # name, type ("start", "O"), ("stop", "O"), ("step", "O"), ] builtin_type_table = [ # name, objstruct, typeobj, methods, members # bool - function # buffer - constant # classmethod ("dict", "PyDictObject", "PyDict_Type", dict_methods), # enumerate - constant # file - constant # float - constant # int - constant ("list", "PyListObject", "PyList_Type", list_methods), # long - constant # object # property - constant ("slice", "PySliceObject", "PySlice_Type", slice_methods, slice_members), # staticmethod # super # str - constant # tuple - constant ("type", "PyTypeObject", "PyType_Type", []), # xrange - constant ] # Builtin types # list getattr3_utility_code = [""" static PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *); /*proto*/ """,""" static PyObject *__Pyx_GetAttr3(PyObject *o, PyObject *n, PyObject *d) { PyObject *r = PyObject_GetAttr(o, n); if (!r) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; PyErr_Clear(); r = d; Py_INCREF(d); } return r; bad: return 0; } """] builtin_utility_code = { 'getattr3': getattr3_utility_code, } builtin_scope = BuiltinScope() def type_and_ctype(typecode, c_typecode = None): type = Signature.format_map[typecode] if c_typecode: ctype = Signature.format_map[c_typecode] else: ctype = None return type, ctype def declare_builtin_constant(name, typecode, cname): type, ctype = type_and_ctype(*typecode.split("/")) builtin_scope.declare_builtin_constant(name, type, cname, ctype) def declare_builtin_func(name, args, ret, cname, py_equiv = "*"): sig = Signature(args, ret) type = sig.function_type() utility = builtin_utility_code.get(name) builtin_scope.declare_builtin_cfunction(name, type, cname, py_equiv, utility) def declare_builtin_method(self_type, name, args, ret, cname): sig = Signature(args, ret) meth_type = sig.function_type(self_type) self_type.scope.declare_builtin_method(name, meth_type, cname) def declare_builtin_member(self_type, name, typecode, cname = None): member_type = Signature.format_map[typecode] self_type.scope.declare_builtin_var(name, member_type, cname) def declare_builtin_type(name, objstruct, typeobj, methods, members = []): entry = builtin_scope.declare_builtin_class(name, objstruct, typeobj) type = entry.type for desc in methods: declare_builtin_method(type, *desc) for desc in members: declare_builtin_member(type, *desc) def init_builtin_constants(): for desc in builtin_constant_table: declare_builtin_constant(*desc) def init_builtin_funcs(): for desc in builtin_function_table: declare_builtin_func(*desc) def init_builtin_types(): for desc in builtin_type_table: declare_builtin_type(*desc) py_type_type.define(builtin_scope.find_type("type")) def init_builtins(): init_builtin_constants() init_builtin_funcs() init_builtin_types() init_builtins() Pyrex-0.9.8.5/Pyrex/Compiler/CmdLine.py0000644001243100001200000000643111011310226017621 0ustar00gregadmin00000000000000# # Pyrex - Command Line Parsing # import sys usage = """\ Usage: pyrexc [options] sourcefile... Options: -v, --version Display version number of pyrex compiler -l, --create-listing Write error messages to a listing file -I, --include-dir Search for include files in named directory -o, --output-file Specify name of generated C file -r, --recursive Recursively find and compile dependencies -t, --timestamps Only compile newer source files (implied with -r) -f, --force Compile all source files (overrides implied -t) -q, --quiet Don't print module names in recursive mode The following experimental options are supported only on MacOSX: -C, --compile Compile generated .c file to .o file -X, --link Link .o file to produce extension module (implies -C) -+, --cplus Use C++ compiler for compiling and linking Additional .o files to link may be supplied when using -X.""" def bad_usage(): print >>sys.stderr, usage sys.exit(1) def parse_command_line(args): from Pyrex.Compiler.Main import \ CompilationOptions, default_options def pop_arg(): if args: return args.pop(0) else: bad_usage() def get_param(option): tail = option[2:] if tail: return tail else: return pop_arg() options = CompilationOptions(default_options) sources = [] while args: if args[0].startswith("-"): option = pop_arg() if option in ("-v", "--version"): options.show_version = 1 elif option in ("-l", "--create-listing"): options.use_listing_file = 1 elif option in ("-C", "--compile"): options.c_only = 0 elif option in ("-X", "--link"): options.c_only = 0 options.obj_only = 0 elif option in ("-+", "--cplus"): options.cplus = 1 elif option.startswith("-I"): options.include_path.append(get_param(option)) elif option == "--include-dir": options.include_path.append(pop_arg()) elif option in ("-o", "--output-file"): options.output_file = pop_arg() elif option in ("-r", "--recursive"): options.recursive = 1 elif option in ("-t", "--timestamps"): options.timestamps = 1 elif option in ("-f", "--force"): options.timestamps = 0 else: bad_usage() else: arg = pop_arg() if arg.endswith(".pyx"): sources.append(arg) elif arg.endswith(".o"): options.objects.append(arg) else: print >>sys.stderr, \ "pyrexc: %s: Unknown filename suffix" % arg if options.objects and len(sources) > 1: print >>sys.stderr, \ "pyrexc: Only one source file allowed together with .o files" if options.use_listing_file and len(sources) > 1: print >>sys.stderr, \ "pyrexc: Only one source file allowed when using -o" sys.exit(1) return options, sources Pyrex-0.9.8.5/Pyrex/Compiler/Code.py0000644001243100001200000004331511015516043017173 0ustar00gregadmin00000000000000########################################################################## # # Pyrex - Code output module # ########################################################################## import os, re import Naming from Pyrex.Utils import open_new_file from PyrexTypes import py_object_type, c_char_array_type, typecast identifier_pattern = re.compile(r"[A-Za-z_][A-Za-z0-9_]*$") max_intern_length = 30 class CCodeWriter: # f file output file # level int indentation level # bol bool beginning of line? # marker string comment to emit before next line def __init__(self, f): #self.f = open_new_file(outfile_name) self.f = f self.level = 0 self.bol = 1 self.marker = None def putln(self, code = ""): if self.marker and self.bol: self.emit_marker() if code: self.put(code) self.f.write("\n"); self.bol = 1 def emit_marker(self): self.f.write("\n"); self.indent() self.f.write("/* %s */\n" % self.marker) self.marker = None def put(self, code): dl = code.count("{") - code.count("}") if dl < 0: self.level += dl if self.bol: self.indent() self.f.write(code) self.bol = 0 if dl > 0: self.level += dl def increase_indent(self): self.level = self.level + 1 def decrease_indent(self): self.level = 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.f.write(" " * self.level) def mark_pos(self, pos): file, line, col = pos self.marker = '"%s":%s' % (file, line) def put_var_declarations(self, entries, static = 0, dll_linkage = None, definition = True): for entry in entries: if not entry.in_cinclude: self.put_var_declaration(entry, static, dll_linkage, definition) def put_var_declaration(self, entry, static = 0, dll_linkage = None, definition = True): #print "Code.put_var_declaration:", entry.name, repr(entry.type) ### visibility = entry.visibility if visibility == 'private' and not definition: #print "...private and not definition, skipping" ### return if not entry.used and visibility == "private": #print "not used and private, skipping" ### return storage_class = "" if visibility == 'extern': storage_class = Naming.extern_c_macro elif visibility == 'public': if not definition: storage_class = Naming.extern_c_macro elif visibility == 'private': if static: storage_class = "static" if storage_class: self.put("%s " % storage_class) if visibility <> 'public': dll_linkage = None self.put(entry.type.declaration_code(entry.cname, dll_linkage = dll_linkage)) if entry.init is not None: self.put(" = %s" % entry.type.literal_code(entry.init)) self.putln(";") 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 and entry.type.base_type): return "(PyObject *)" + entry.cname else: return entry.cname def as_pyobject(self, cname, type): if type: return typecast(py_object_type, type, cname) else: return cname def put_incref(self, cname, type = None): self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type)) def put_decref(self, cname, type = None): self.putln("Py_DECREF(%s);" % self.as_pyobject(cname, type)) def put_var_incref(self, entry): if entry.type.is_pyobject: self.putln("Py_INCREF(%s);" % self.entry_as_pyobject(entry)) def put_decref_clear(self, cname, type = None): self.putln("Py_DECREF(%s); %s = 0;" % ( self.as_pyobject(cname, type), cname)) # What was wrong with this? #typecast(py_object_type, type, cname), cname)) def put_xdecref(self, cname, type): self.putln("Py_XDECREF(%s);" % self.as_pyobject(cname, type)) def put_xdecref_clear(self, cname, type): self.putln("Py_XDECREF(%s); %s = 0;" % ( self.as_pyobject(cname, type), cname)) def put_var_decref(self, entry): if entry.type.is_pyobject: self.putln("Py_DECREF(%s);" % self.entry_as_pyobject(entry)) def put_var_decref_clear(self, entry): if entry.type.is_pyobject: self.putln("Py_DECREF(%s); %s = 0;" % ( self.entry_as_pyobject(entry), entry.cname)) def put_var_xdecref(self, entry): if entry.type.is_pyobject: self.putln("Py_XDECREF(%s);" % self.entry_as_pyobject(entry)) def put_var_xdecref_clear(self, entry): if entry.type.is_pyobject: self.putln("Py_XDECREF(%s); %s = 0;" % ( 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_init_to_py_none(self, cname, type): py_none = typecast(type, py_object_type, "Py_None") self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none)) def put_init_var_to_py_none(self, entry, template = "%s"): code = template % entry.cname self.put_init_to_py_none(code, entry.type) def put_pymethoddef(self, entry, term): if entry.doc: doc_code = entry.doc_cname else: doc_code = 0 self.putln( '{"%s", (PyCFunction)%s, METH_VARARGS|METH_KEYWORDS, %s}%s' % ( entry.name, entry.func_cname, doc_code, term)) def put_h_guard(self, guard): self.putln("#ifndef %s" % guard) self.putln("#define %s" % guard) #-------------------------------------------------------------------------- class MainCCodeWriter(CCodeWriter): # Code writer for executable C code. # # global_state GlobalCodeState module-wide state # 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 # label_counter integer counter for naming labels # in_try_finally boolean inside try of try...finally # exc_vars (string * 3) exception vars for reraise, or None in_try_finally = 0 def __init__(self, f, base = None): CCodeWriter.__init__(self, f) if base: self.global_state = base.global_state else: self.global_state = GlobalCodeState() self.label_counter = 1 self.error_label = None self.exc_vars = None def init_labels(self): self.label_counter = 0 self.labels_used = {} self.return_label = self.new_label() self.new_error_label() self.continue_label = None self.break_label = None def new_label(self): n = self.label_counter self.label_counter = n + 1 return "%s%d" % (Naming.label_prefix, n) def new_error_label(self): old_err_lbl = self.error_label self.error_label = self.new_label() 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(), self.new_label())) 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 in old_labels: if old_label: new_labels.append(self.new_label()) else: new_labels.append(old_label) self.set_all_labels(new_labels) return old_labels def use_label(self, lbl): self.labels_used[lbl] = 1 def put_label(self, lbl): if lbl in self.labels_used: self.putln("%s:;" % lbl) def put_goto(self, lbl): self.use_label(lbl) self.putln("goto %s;" % lbl) def error_goto(self, pos): lbl = self.error_label self.use_label(lbl) return "{%s = %s[%s]; %s = %s; goto %s;}" % ( Naming.filename_cname, Naming.filetable_cname, self.lookup_filename(pos[0]), Naming.lineno_cname, pos[1], lbl) def lookup_filename(self, filename): return self.global_state.lookup_filename(filename) def use_utility_code(self, uc): self.global_state.use_utility_code(uc) def get_string_const(self, text): # Get C name for a string constant, adding a new one # if necessary. return self.global_state.get_string_const(text).cname def new_const(self, type): # Get C name for a new precalculated value. return self.global_state.new_const(type).cname def get_py_string_const(self, text): # Get C name for a Python string constant, adding a new one # if necessary. If the string is name-like, it will be interned. return self.global_state.get_py_string_const(text).cname def intern(self, name): return self.get_py_string_const(name) #-------------------------------------------------------------------------- class StringConst: # Info held by GlobalCodeState about a string constant. # # cname string # text string # py_const Const Corresponding Python string py_const = None def __init__(self, cname, text): self.cname = cname self.text = text #-------------------------------------------------------------------------- class Const: # Info held by GlobalCodeState about a precalculated value. # # cname string # type PyrexType # intern boolean for Python strings intern = 0 def __init__(self, cname, type): self.cname = cname self.type = type #-------------------------------------------------------------------------- class GlobalCodeState: # State pertaining to code generation for a whole module. # # filename_table {string : int} for finding filename table indexes # filename_list [string] filenames in filename table order # utility_code {int : int} id to utility_list index # utility_list list utility code used # const_counter int for generating const names # string_index {string : String} string constant index # string_consts [StringConst] all string constants # other_consts [Const] other precalculated values def __init__(self): self.filename_table = {} self.filename_list = [] self.utility_code = {} self.utility_list = [] self.const_counter = 1 self.string_index = {} self.string_consts = [] self.other_consts = [] 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 generate_filename_table(self, code): code.putln("") code.putln("static char *%s[] = {" % Naming.filenames_cname) if self.filename_list: for filename in self.filename_list: filename = os.path.basename(filename) escaped_filename = filename.replace("\\", "\\\\").replace('"', r'\"') code.putln('"%s",' % escaped_filename) else: # Some C compilers don't like an empty array code.putln("0") code.putln("};") def use_utility_code(self, uc): i = id(uc) if i not in self.utility_code: self.utility_code[i] = len(self.utility_list) self.utility_list.append(uc) def generate_utility_functions(self, code): code.putln("") code.putln("/* Runtime support code */") code.putln("") code.putln("static void %s(void) {" % Naming.fileinit_cname) code.putln("%s = %s;" % (Naming.filetable_cname, Naming.filenames_cname)) code.putln("}") for utility_code in self.utility_list: code.h.put(utility_code[0]) code.put(utility_code[1]) def new_const_name(self): # Create a new globally-unique name for a constant. name = "%s%s" % (Naming.const_prefix, self.const_counter) self.const_counter += 1 return name def new_string_const(self, text): # Add a new C string constant. c = StringConst(self.new_const_name(), text) self.string_consts.append(c) self.string_index[text] = c return c def new_const(self, type, cname = None): if not cname: cname = self.new_const_name() c = Const(cname, type) self.other_consts.append(c) return c def new_py_const(self, cname = None, intern = 0): # Add a new Python constant. c = self.new_const(py_object_type, cname) if intern: c.intern = 1 return c def get_string_const(self, text): # Get a C string constant, adding a new one if necessary. c = self.string_index.get(text) if not c: c = self.new_string_const(text) return c def get_py_string_const(self, text): # Get a Python string constant, adding a new one if necessary. # If the string is name-like, it will be interned. s = self.get_string_const(text) if not s.py_const: intern = len(text) <= max_intern_length and identifier_pattern.match(text) if intern: cname = Naming.interned_prefix + text else: cname = s.cname + "p" s.py_const = self.new_py_const(cname, intern) return s.py_const def generate_const_declarations(self, code): self.generate_string_const_declarations(code) self.generate_other_const_declarations(code) self.generate_stringtab(code) def generate_string_const_declarations(self, code): code.putln("") for c in self.string_consts: code.putln('static char %s[] = "%s";' % (c.cname, c.text)) def generate_other_const_declarations(self, code): interned = [] uninterned = [] for c in self.other_consts: if c.intern: interned.append(c) else: uninterned.append(c) interned.sort(lambda c1, c2: cmp(c1.cname, c2.cname)) def put_consts(consts): code.putln("") for c in consts: decl = c.type.declaration_code(c.cname) code.putln("static %s;" % decl) put_consts(interned) put_consts(uninterned) def generate_stringtab(self, code): interned = [] uninterned = [] for s in self.string_consts: p = s.py_const if p: if p.intern: interned.append(s) else: uninterned.append(s) interned.sort(lambda c1, c2: cmp(c1.py_const.cname, c2.py_const.cname)) def put_stringtab(consts, intern): for c in consts: cname = c.cname code.putln("{&%s, %d, %s, sizeof(%s)}," % ( c.py_const.cname, intern, cname, cname)) code.putln("") code.putln("static __Pyx_StringTabEntry %s[] = {" % Naming.stringtab_cname) put_stringtab(interned, 1) put_stringtab(uninterned, 0) code.putln("{0, 0, 0, 0}") code.putln("};") #-------------------------------------------------------------------------- class PyrexCodeWriter: # f file output file # level int indentation level def __init__(self, outfile_name): self.f = 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 Pyrex-0.9.8.5/Pyrex/Compiler/DebugFlags.py0000644001243100001200000000010111015513305020304 0ustar00gregadmin00000000000000debug_disposal_code = 0 debug_temp_alloc = 0 debug_coercion = 0 Pyrex-0.9.8.5/Pyrex/Compiler/Errors.py0000644001243100001200000000323611015732107017574 0ustar00gregadmin00000000000000# # Pyrex - Errors # import sys from Pyrex.Utils import open_new_file class PyrexError(EnvironmentError): pass class CompileError(PyrexError): def __init__(self, position = None, message = ""): self.position = position self.message = message if position: pos_str = "%s:%d:%d: " % position else: pos_str = "" PyrexError.__init__(self, pos_str + message) class InternalError(Exception): # If this is ever raised, there is a bug in the compiler. def __init__(self, message): Exception.__init__(self, "Internal compiler error: %s" % message) 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(position, message): err = CompileError(position, message) line = "%s\n" % err if listing_file: listing_file.write(line) if echo_file: echo_file.write(line) return err def warning(position, message): return report(position, "Warning: %s" % message) def error(position, message): global num_errors num_errors = num_errors + 1 return report(position, message) Pyrex-0.9.8.5/Pyrex/Compiler/ExprNodes.py0000644001243100001200000040033611055176114020235 0ustar00gregadmin00000000000000# # Pyrex - Parse tree nodes for expressions # import operator from string import join from Errors import error, InternalError import Naming from Nodes import Node import PyrexTypes from PyrexTypes import py_object_type, c_long_type, typecast, error_type import Symtab import Options from Pyrex.Debugging import print_call_chain from DebugFlags import debug_disposal_code, debug_temp_alloc, \ debug_coercion 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 # inplace_result string Temp var holding in-place operation result # is_temp boolean Result is in a temporary variable # is_sequence_constructor # boolean Is a list or tuple constructor expression # saved_subexpr_nodes # [ExprNode or [ExprNode or None] or None] # Cached result of subexpr_nodes() result_ctype = None # 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. If coercion is needed, 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. # # allocate_temps # - Call allocate_temps for all sub-nodes. # - Call allocate_temp for this node. # - If a temporary was allocated, call release_temp on # all sub-expressions. # # allocate_target_temps # - Call allocate_temps on sub-nodes and allocate any other # temps used during assignment. # - Fill in result_code with a C lvalue if needed. # - If a rhs node is supplied, call release_temp on it. # - Call release_temp on sub-nodes and release any other # temps used during assignment. # # #calculate_result_code # # - Called during the Allocate Temps phase. Should return a # # C code fragment evaluating to the result. This is only # # called when the result is not a temporary. # # 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 # 1. Call generate_evaluation_code for sub-expressions. # 2. Generate any C statements necessary to calculate # the result of this node from the results of its # sub-expressions. If result is not in a temporary, record # any information that will be needed by this node's # implementation of calculate_result_code(). # 4. If result is in a temporary, call generate_disposal_code # on all sub-expressions. # # A default implementation of generate_evaluation_code # is provided which uses the folling abstract methods: # generate_result_code (for no. 2) # # 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. # # calculate_result_code # Return a C code fragment representing the result of this node. # This is only called if the result is not in a temporary. # is_sequence_constructor = 0 is_attribute = 0 saved_subexpr_nodes = None is_temp = 0 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_inplace_lvalue(self): return 0 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. if self.saved_subexpr_nodes is None: nodes = [] for name in self.subexprs: item = getattr(self, name) if item: if isinstance(item, ExprNode): nodes.append(item) else: nodes.extend(item) self.saved_subexpr_nodes = nodes return self.saved_subexpr_nodes def result(self): # Return a C code fragment for the result of this node. if self.is_temp: result_code = self.result_code else: result_code = self.calculate_result_code() return result_code def result_as(self, type = None): # Return the result code cast to the specified C type. 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. return self.result_ctype or self.type 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. self.analyse_types(env) self.allocate_temps(env) self.check_const() def analyse_expressions(self, env): # Convenience routine performing both the Type # Analysis and Temp Allocation phases for a whole # expression. self.analyse_types(env) self.allocate_temps(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. self.analyse_target_types(env) self.allocate_target_temps(env, rhs) def analyse_boolean_expression(self, env): # Analyse expression and coerce to a boolean. self.analyse_types(env) bool = self.coerce_to_boolean(env) bool.allocate_temps(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. self.analyse_types(env) bool = self.coerce_to_boolean(env) temp_bool = bool.coerce_to_temp(env) temp_bool.allocate_temps(env) return temp_bool # --------------- 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_extension_type(self, env): # If this node can be interpreted as a reference to an # extension type, return its type, else None. return None def analyse_types(self, env): self.not_implemented("analyse_types") def analyse_target_types(self, env): self.analyse_types(env) def analyse_inplace_types(self, env): if self.is_inplace_lvalue(): self.analyse_types(env) else: error(self.pos, "Invalid target for in-place operation") self.type = error_type 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() def not_const(self): error(self.pos, "Not allowed in a constant expression") def check_const_addr(self): self.addr_not_const() def addr_not_const(self): error(self.pos, "Address is not constant") def gil_check(self, env): if env.nogil and self.type.is_pyobject: self.gil_error() # ----------------- 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 allocate_target_temps(self, env, rhs, inplace = 0): # Perform temp allocation for the LHS of an assignment. if debug_temp_alloc: print self, "Allocating target temps" self.allocate_subexpr_temps(env) #self.result_code = self.target_code() if rhs: rhs.release_temp(env) self.release_subexpr_temps(env) def allocate_inplace_target_temps(self, env, rhs): if debug_temp_alloc: print self, "Allocating inplace target temps" self.allocate_subexpr_temps(env) #self.result_code = self.target_code() py_inplace = self.type.is_pyobject if py_inplace: self.allocate_temp(env) self.inplace_result = env.allocate_temp(py_object_type) self.release_temp(env) rhs.release_temp(env) if py_inplace: env.release_temp(self.inplace_result) self.release_subexpr_temps(env) def allocate_temps(self, env, result = None): # Allocate temporary variables for this node and # all its sub-expressions. If a result is specified, # this must be a temp node and the specified variable # is used as the result instead of allocating a new # one. if debug_temp_alloc: print self, "Allocating temps" self.allocate_subexpr_temps(env) self.allocate_temp(env, result) if self.is_temp: self.release_subexpr_temps(env) def allocate_subexpr_temps(self, env): # Allocate temporary variables for all sub-expressions # of this node. if debug_temp_alloc: print self, "Allocating temps for:", self.subexprs for node in self.subexpr_nodes(): if node: if debug_temp_alloc: print self, "Allocating temps for", node node.allocate_temps(env) def allocate_temp(self, env, result = None): # If this node requires a temporary variable for its # result, allocate one. If a result is specified, # this must be a temp node and the specified variable # is used as the result instead of allocating a new # one. if debug_temp_alloc: print self, "Allocating temp" if result: if not self.is_temp: raise InternalError("Result forced on non-temp node") self.result_code = result elif self.is_temp: type = self.type if not type.is_void: if type.is_pyobject: type = PyrexTypes.py_object_type self.result_code = env.allocate_temp(type) else: self.result_code = None if debug_temp_alloc: print self, "Allocated result", self.result_code #else: # self.result_code = self.calculate_result_code() 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_temp(self, env): # If this node owns a temporary result, release it, # otherwise release results of its sub-expressions. if self.is_temp: if debug_temp_alloc: print self, "Releasing result", self.result_code env.release_temp(self.result_code) else: self.release_subexpr_temps(env) def release_subexpr_temps(self, env): # Release the results of all sub-expressions of # this node. for node in self.subexpr_nodes(): if node: node.release_temp(env) # ---------------- Code Generation ----------------- def make_owned_reference(self, code): # If result is a pyobject, make sure we own # a reference to it. if self.type.is_pyobject and not self.result_in_temp(): code.put_incref(self.py_result()) 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) self.generate_result_code(code) if self.is_temp: self.generate_subexpr_disposal_code(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") inplace_functions = { "+=": "PyNumber_InPlaceAdd", "-=": "PyNumber_InPlaceSubtract", "*=": "PyNumber_InPlaceMultiply", "/=": "PyNumber_InPlaceDivide", "%=": "PyNumber_InPlaceRemainder", "**=": "PyNumber_InPlacePower", "<<=": "PyNumber_InPlaceLshift", ">>=": "PyNumber_InPlaceRshift", "&=": "PyNumber_InPlaceAnd", "^=": "PyNumber_InPlaceXor", "|=": "PyNumber_InPlaceOr", } def generate_inplace_operation_code(self, operator, rhs, code): args = (self.py_result(), rhs.py_result()) if operator == "**=": arg_code = "%s, %s, Py_None" % args else: arg_code = "%s, %s" % args code.putln("%s = %s(%s); if (!%s) %s" % ( self.inplace_result, self.inplace_functions[operator], arg_code, self.inplace_result, code.error_goto(self.pos))) if self.is_temp: code.put_decref_clear(self.py_result()) rhs.generate_disposal_code(code) if self.type.is_extension_type: code.putln( "if (!__Pyx_TypeTest(%s, %s)) %s" % ( self.inplace_result, self.type.typeptr_cname, code.error_goto(self.pos))) def generate_disposal_code(self, code): # If necessary, generate code to dispose of # temporary Python reference. if self.is_temp: if self.type.is_pyobject: code.put_decref_clear(self.py_result(), self.ctype()) else: 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): # Same as generate_disposal_code except that # assignment will have absorbed a reference to # the result if it is a Python object. if self.is_temp: if self.type.is_pyobject: code.putln("%s = 0;" % self.result()) else: self.generate_subexpr_disposal_code(code) def generate_inplace_result_disposal_code(self, code): code.put_decref_clear(self.inplace_result, py_object_type) 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): # Stub method for nodes that are not legal as # the argument of a del statement. An error # will have been reported earlier. pass # ----------------- 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. src = self src_type = self.type src_is_py_type = src_type.is_pyobject dst_is_py_type = dst_type.is_pyobject if dst_type.is_pyobject: if not src.type.is_pyobject: src = CoerceToPyTypeNode(src, env) if not src.type.subtype_of(dst_type): if not isinstance(src, NoneNode): src = PyTypeTestNode(src, dst_type, env) elif src.type.is_pyobject: src = CoerceFromPyTypeNode(dst_type, src, env) else: # neither src nor dst are py types if not dst_type.assignable_from(src_type): error(self.pos, "Cannot assign type '%s' to '%s'" % (src.type, dst_type)) return src 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. type = self.type if type.is_pyobject or type.is_ptr or type.is_float: return CoerceToBooleanNode(self, env) else: if not type.is_int and not type.is_error: 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() class AtomicExprNode(ExprNode): # Abstract base class for expression nodes which have # no sub-expressions. subexprs = [] class PyConstNode(AtomicExprNode): # Abstract base class for constant Python values. def is_simple(self): return 1 def analyse_types(self, env): self.type = py_object_type def calculate_result_code(self): return self.value def generate_result_code(self, code): pass class NoneNode(PyConstNode): # The constant value None value = "Py_None" def compile_time_value(self, denv): return None class EllipsisNode(PyConstNode): # '...' in a subscript list. value = "Py_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 def is_simple(self): return 1 def analyse_types(self, env): pass # Types are held in class variables def check_const(self): pass def calculate_result_code(self): return str(self.value) def generate_result_code(self, code): pass class NullNode(ConstNode): type = PyrexTypes.c_null_ptr_type value = "NULL" class CharNode(ConstNode): type = PyrexTypes.c_char_type def compile_time_value(self, denv): return ord(self.value) def calculate_result_code(self): return "'%s'" % self.value class IntNode(ConstNode): type = PyrexTypes.c_long_type def compile_time_value(self, denv): return int(self.value, 0) class FloatNode(ConstNode): type = PyrexTypes.c_double_type def compile_time_value(self, denv): return float(self.value) def calculate_result_code(self): strval = str(self.value) if strval == 'nan': return "NAN" elif strval == 'inf': return "INFINITY" elif strval == '-inf': return "(-INFINITY)" else: return strval class StringNode(ConstNode): # #entry Symtab.Entry type = PyrexTypes.c_char_ptr_type def compile_time_value(self, denv): return eval('"%s"' % self.value) # def analyse_types(self, env): # self.entry = env.add_string_const(self.value) def coerce_to(self, dst_type, env): # Arrange for a Python version of the string to be pre-allocated # when coercing to a Python type. if dst_type.is_pyobject and not self.type.is_pyobject: node = self.as_py_string_node(env) else: node = self # 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 as_py_string_node(self, env): # Return a new StringNode with the same value as this node # but whose type is a Python type instead of a C type. #entry = self.entry #env.add_py_string(entry) return StringNode(self.pos, type = py_object_type, value = self.value) 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 calculate_result_code(self): return self.result_code class LongNode(AtomicExprNode): # Python long integer literal # # value string def compile_time_value(self, denv): return long(self.value) gil_message = "Constructing Python long int" def analyse_types(self, env): self.type = py_object_type self.gil_check(env) self.is_temp = 1 def generate_evaluation_code(self, code): result = self.result() code.putln( '%s = PyLong_FromString("%s", 0, 0); if (!%s) %s' % ( self.result(), self.value, self.result(), code.error_goto(self.pos))) class ImagNode(AtomicExprNode): # Imaginary number literal # # value float imaginary part def compile_time_value(self, denv): return complex(0.0, self.value) gil_message = "Constructing complex number" def analyse_types(self, env): self.type = py_object_type self.gil_check(env) self.is_temp = 1 def generate_evaluation_code(self, code): result = self.result() code.putln( "%s = PyComplex_FromDoubles(0.0, %s); if (!%s) %s" % ( self.result(), self.value, self.result(), code.error_goto(self.pos))) 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 # interned_cname string is_name = 1 entry = None type_entry = None 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 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.is_cfunction: var_entry = entry.as_variable if var_entry: node = NameNode(self.pos, name = self.name) node.entry = var_entry node.analyse_rvalue_entry(env) return node return AtomicExprNode.coerce_to(self, 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 = env.lookup(self.name) if entry and entry.as_module: return entry.as_module 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 = env.lookup(self.name) if entry and entry.is_type and entry.type.is_extension_type: return entry.type else: return None def analyse_target_declaration(self, env): self.entry = env.lookup_here(self.name) if not self.entry: self.entry = env.declare_var(self.name, py_object_type, self.pos) def analyse_types(self, env): self.entry = env.lookup(self.name) if not self.entry: self.entry = env.declare_builtin(self.name, self.pos) self.analyse_rvalue_entry(env) def analyse_target_types(self, env): self.analyse_entry(env) self.finish_analysing_lvalue() def analyse_inplace_types(self, env): self.analyse_rvalue_entry(env) self.finish_analysing_lvalue() def finish_analysing_lvalue(self): if self.entry.is_readonly: error(self.pos, "Assignment to read-only name '%s'" % self.name) elif not self.is_lvalue(): error(self.pos, "Assignment to non-lvalue '%s'" % self.name) self.type = PyrexTypes.error_type self.entry.used = 1 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: self.is_temp = 1 self.gil_check(env) gil_message = "Accessing Python global or builtin" def analyse_entry(self, env): #print "NameNode.analyse_entry:", self.name ### self.check_identifier_kind() entry = self.entry type = entry.type ctype = entry.ctype self.type = type if ctype: self.result_ctype = ctype if entry.is_pyglobal or entry.is_builtin: assert type.is_pyobject, "Python global or builtin not a Python object" #self.interned_cname = env.intern(self.entry.name) 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): 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 calculate_target_results(self, env): pass def check_const(self): entry = self.entry if not (entry.is_const or entry.is_cfunction): self.not_const() def check_const_addr(self): entry = self.entry if not (entry.is_cglobal or entry.is_cfunction): self.addr_not_const() def is_lvalue(self): entry = self.entry return entry.is_variable and \ not entry.type.is_array and \ not entry.is_readonly def is_inplace_lvalue(self): return self.is_lvalue() def is_ephemeral(self): # Name nodes are never ephemeral, even if the # result is in a temporary. return 0 def allocate_temp(self, env, result = None): AtomicExprNode.allocate_temp(self, env, result) entry = self.entry if entry: entry.used = 1 # if entry.utility_code: # env.use_utility_code(entry.utility_code) 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.utility_code: code.use_utility_code(entry.utility_code) if entry.is_pyglobal or entry.is_builtin: if entry.is_builtin: namespace = Naming.builtins_cname else: # entry.is_pyglobal namespace = entry.namespace_cname result = self.result() cname = code.intern(self.entry.name) code.use_utility_code(get_name_interned_utility_code) code.putln( '%s = __Pyx_GetName(%s, %s); if (!%s) %s' % ( result, namespace, cname, result, code.error_goto(self.pos))) def generate_setattr_code(self, value_code, code): entry = self.entry namespace = self.entry.namespace_cname cname = code.intern(self.entry.name) code.putln( 'if (PyObject_SetAttr(%s, %s, %s) < 0) %s' % ( namespace, cname, value_code, code.error_goto(self.pos))) 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 entry.is_pyglobal: self.generate_setattr_code(rhs.py_result(), code) if debug_disposal_code: print "NameNode.generate_assignment_code:" print "...generating disposal code for", rhs rhs.generate_disposal_code(code) else: if self.type.is_pyobject: rhs.make_owned_reference(code) code.put_decref(self.py_result()) 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", rhs rhs.generate_post_assignment_code(code) def generate_inplace_assignment_code(self, operator, rhs, code): entry = self.entry if entry is None: return # There was an error earlier if self.type.is_pyobject: self.generate_result_code(code) self.generate_inplace_operation_code(operator, rhs, code) if entry.is_pyglobal: self.generate_setattr_code(self.inplace_result, code) self.generate_inplace_result_disposal_code(code) else: code.put_decref(self.py_result()) cast_inplace_result = typecast(self.ctype(), py_object_type, self.inplace_result) code.putln('%s = %s;' % (self.result(), cast_inplace_result)) else: code.putln("%s %s %s;" % (self.result(), operator, rhs.result())) rhs.generate_disposal_code(code) def generate_deletion_code(self, code): if self.entry is None: return # There was an error earlier if not self.entry.is_pyglobal: error(self.pos, "Deletion of local or C global name not supported") return cname = code.intern(self.entry.name) code.putln( 'if (PyObject_DelAttr(%s, %s) < 0) %s' % ( Naming.module_cname, cname, code.error_goto(self.pos))) class BackquoteNode(ExprNode): # `expr` # # arg ExprNode subexprs = ['arg'] def analyse_types(self, env): self.arg.analyse_types(env) self.arg = self.arg.coerce_to_pyobject(env) self.type = py_object_type self.gil_check(env) self.is_temp = 1 gil_message = "Backquote expression" def generate_result_code(self, code): result = self.result() code.putln( "%s = PyObject_Repr(%s); if (!%s) %s" % ( self.result(), self.arg.py_result(), self.result(), code.error_goto(self.pos))) class ImportNode(ExprNode): # Used as part of import statement implementation. # Implements result = # __import__(module_name, globals(), None, name_list) # # module_name StringNode dotted name of module # name_list ListNode or None list of names to be imported subexprs = ['module_name', 'name_list'] def analyse_types(self, env): self.module_name.analyse_types(env) self.module_name = self.module_name.coerce_to_pyobject(env) if self.name_list: self.name_list.analyse_types(env) self.type = py_object_type self.gil_check(env) self.is_temp = 1 # env.use_utility_code(import_utility_code) 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.use_utility_code(import_utility_code) result = self.result() code.putln( "%s = __Pyx_Import(%s, %s); if (!%s) %s" % ( result, self.module_name.py_result(), name_list_code, result, code.error_goto(self.pos))) class IteratorNode(ExprNode): # Used as part of for statement implementation. # Implements result = iter(sequence) # # sequence ExprNode subexprs = ['sequence'] def analyse_types(self, env): self.sequence.analyse_types(env) self.sequence = self.sequence.coerce_to_pyobject(env) self.type = py_object_type self.gil_check(env) self.is_temp = 1 gil_message = "Iterating over Python object" def generate_result_code(self, code): result = self.result() code.putln( "%s = PyObject_GetIter(%s); if (!%s) %s" % ( result, self.sequence.py_result(), result, code.error_goto(self.pos))) 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 ExprNode def __init__(self, iterator, env): self.pos = iterator.pos self.iterator = iterator self.type = py_object_type self.is_temp = 1 def generate_result_code(self, code): result = self.result() code.putln( "%s = PyIter_Next(%s);" % ( result, self.iterator.py_result())) code.putln( "if (!%s) {" % result) code.putln( "if (PyErr_Occurred()) %s" % code.error_goto(self.pos)) code.putln( "break;") code.putln( "}") class ExcValueNode(AtomicExprNode): # Node created during analyse_types phase # of an ExceptClauseNode to fetch the current # exception value. def __init__(self, pos, env, var): ExprNode.__init__(self, pos) self.type = py_object_type self.var = var def calculate_result_code(self): return self.var def generate_result_code(self, code): pass class TempNode(AtomicExprNode): # Node created during analyse_types phase # of some nodes to hold a temporary value. def __init__(self, pos, type, env): ExprNode.__init__(self, pos) self.type = type if type.is_pyobject: self.result_ctype = py_object_type self.is_temp = 1 def generate_result_code(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) #------------------------------------------------------------------- # # Trailer nodes # #------------------------------------------------------------------- class IndexNode(ExprNode): # Sequence indexing. # # base ExprNode # index ExprNode subexprs = ['base', 'index'] 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 analyse_target_declaration(self, env): pass def analyse_types(self, env): self.analyse_base_and_index_types(env, getting = 1) def analyse_target_types(self, env): self.analyse_base_and_index_types(env, setting = 1) def analyse_inplace_types(self, env): self.analyse_base_and_index_types(env, getting = 1, setting = 1) def analyse_base_and_index_types(self, env, getting = 0, setting = 0): self.base.analyse_types(env) self.index.analyse_types(env) if self.base.type.is_pyobject: itype = self.index.type if not (itype.is_int and itype.signed): self.index = self.index.coerce_to_pyobject(env) self.type = py_object_type self.gil_check(env) self.is_temp = 1 else: if self.base.type.is_ptr or self.base.type.is_array: self.type = self.base.type.base_type else: error(self.pos, "Attempting to index non-array type '%s'" % self.base.type) self.type = PyrexTypes.error_type if self.index.type.is_pyobject: self.index = self.index.coerce_to( PyrexTypes.c_py_ssize_t_type, env) if not self.index.type.is_int: error(self.pos, "Invalid index type '%s'" % self.index.type) gil_message = "Indexing Python object" def check_const_addr(self): self.base.check_const_addr() self.index.check_const() def is_lvalue(self): return 1 def is_inplace_lvalue(self): return 1 def calculate_result_code(self): return "(%s[%s])" % ( self.base.result(), self.index.result()) def generate_result_code(self, code): if self.type.is_pyobject: itype = self.index.type if itype.is_int and itype.signed: code.use_utility_code(getitem_int_utility_code) function = "__Pyx_GetItemInt" index_code = self.index.result() else: function = "PyObject_GetItem" index_code = self.index.py_result() result = self.result() code.putln( "%s = %s(%s, %s); if (!%s) %s" % ( result, function, self.base.py_result(), index_code, result, code.error_goto(self.pos))) def generate_setitem_code(self, value_code, code): itype = self.index.type if itype.is_int and itype.signed: code.use_utility_code(setitem_int_utility_code) function = "__Pyx_SetItemInt" index_code = self.index.result() else: function = "PyObject_SetItem" index_code = self.index.py_result() code.putln( "if (%s(%s, %s, %s) < 0) %s" % ( function, self.base.py_result(), index_code, value_code, code.error_goto(self.pos))) def generate_assignment_code(self, rhs, code): self.generate_subexpr_evaluation_code(code) if self.type.is_pyobject: self.generate_setitem_code(rhs.py_result(), code) else: code.putln( "%s = %s;" % ( self.result(), rhs.result())) self.generate_subexpr_disposal_code(code) rhs.generate_disposal_code(code) def generate_inplace_assignment_code(self, operator, rhs, code): self.generate_subexpr_evaluation_code(code) if self.type.is_pyobject: self.generate_result_code(code) self.generate_inplace_operation_code(operator, rhs, code) self.generate_setitem_code(self.inplace_result, code) self.generate_inplace_result_disposal_code(code) else: code.putln("%s %s %s;" % (self.result(), operator, rhs.result())) rhs.generate_disposal_code(code) self.generate_subexpr_disposal_code(code) def generate_deletion_code(self, code): self.generate_subexpr_evaluation_code(code) #if self.type.is_pyobject: if self.index.type.is_int: function = "PySequence_DelItem" index_code = self.index.result() else: function = "PyObject_DelItem" index_code = self.index.py_result() code.putln( "if (%s(%s, %s) < 0) %s" % ( function, self.base.py_result(), index_code, code.error_goto(self.pos))) #else: # error(self.pos, "Cannot delete non-Python variable") self.generate_subexpr_disposal_code(code) class SliceIndexNode(ExprNode): # 2-element slice indexing # # base ExprNode # start ExprNode or None # stop ExprNode or None subexprs = ['base', 'start', 'stop'] def is_inplace_lvalue(self): return 1 def compile_time_value(self, denv): base = self.base.compile_time_value(denv) start = self.start.compile_time_value(denv) 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_types(self, env): self.base.analyse_types(env) if self.start: self.start.analyse_types(env) if self.stop: self.stop.analyse_types(env) self.base = self.base.coerce_to_pyobject(env) 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.type = py_object_type self.gil_check(env) self.is_temp = 1 gil_message = "Slicing Python object" def generate_result_code(self, code): result = self.result() code.putln( "%s = PySequence_GetSlice(%s, %s, %s); if (!%s) %s" % ( result, self.base.py_result(), self.start_code(), self.stop_code(), result, code.error_goto(self.pos))) def generate_setslice_code(self, value_code, code): code.putln( "if (PySequence_SetSlice(%s, %s, %s, %s) < 0) %s" % ( self.base.py_result(), self.start_code(), self.stop_code(), value_code, code.error_goto(self.pos))) def generate_assignment_code(self, rhs, code): self.generate_subexpr_evaluation_code(code) self.generate_setslice_code(rhs.result(), code) self.generate_subexpr_disposal_code(code) rhs.generate_disposal_code(code) def generate_inplace_assignment_code(self, operator, rhs, code): self.generate_subexpr_evaluation_code(code) self.generate_result_code(code) self.generate_inplace_operation_code(operator, rhs, code) self.generate_setslice_code(self.inplace_result, code) self.generate_inplace_result_disposal_code(code) self.generate_subexpr_disposal_code(code) def generate_deletion_code(self, code): self.generate_subexpr_evaluation_code(code) code.putln( "if (PySequence_DelSlice(%s, %s, %s) < 0) %s" % ( self.base.py_result(), self.start_code(), self.stop_code(), code.error_goto(self.pos))) self.generate_subexpr_disposal_code(code) 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() else: return "PY_SSIZE_T_MAX" # def calculate_result_code(self): # # self.result_code is not used, but this method must exist # return "" class SliceNode(ExprNode): # start:stop:step in subscript list # # start ExprNode # stop ExprNode # step ExprNode def compile_time_value(self, denv): start = self.start.compile_time_value(denv) stop = self.stop.compile_time_value(denv) step = step.step.compile_time_value(denv) try: return slice(start, stop, step) except Exception, e: self.compile_time_value_error(e) subexprs = ['start', 'stop', 'step'] def analyse_types(self, env): self.start.analyse_types(env) self.stop.analyse_types(env) self.step.analyse_types(env) self.start = self.start.coerce_to_pyobject(env) self.stop = self.stop.coerce_to_pyobject(env) self.step = self.step.coerce_to_pyobject(env) self.type = py_object_type self.gil_check(env) self.is_temp = 1 gil_message = "Constructing Python slice object" def generate_result_code(self, code): result = self.result() code.putln( "%s = PySlice_New(%s, %s, %s); if (!%s) %s" % ( result, self.start.py_result(), self.stop.py_result(), self.step.py_result(), result, code.error_goto(self.pos))) class CallNode(ExprNode): def gil_check(self, env): # Make sure we're not in a nogil environment if env.nogil: error(self.pos, "Calling gil-requiring function without gil") 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 subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple'] self = None coerced_self = None arg_tuple = None 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_types(self, env): #print "SimpleCallNode.analyse_types:", self.pos ### function = self.function function.is_called = 1 function.analyse_types(env) if function.is_name or function.is_attribute: func_entry = function.entry if func_entry: if func_entry.is_cmethod or func_entry.is_builtin_method: # Take ownership of the object from which the attribute # was obtained, because we need to pass it as 'self'. #print "SimpleCallNode: Snarfing self argument" ### self.self = function.obj function.obj = CloneNode(self.self) func_type = self.function_type() if func_type.is_pyobject: if self.args: self.arg_tuple = TupleNode(self.pos, args = self.args) self.arg_tuple.analyse_types(env) else: self.arg_tuple = None self.args = None if function.is_name and function.type_entry: # We are calling an extension type constructor self.type = function.type_entry.type self.result_ctype = py_object_type else: self.type = py_object_type self.gil_check(env) self.is_temp = 1 else: for arg in self.args: arg.analyse_types(env) if self.self and func_type.args: #print "SimpleCallNode: Inserting self into argument list" ### # Coerce 'self' to the type expected by the method. expected_type = func_type.args[0].type self.coerced_self = CloneNode(self.self).coerce_to( expected_type, env) # Insert coerced 'self' argument into argument list. self.args.insert(0, self.coerced_self) self.analyse_c_function_call(env) def function_type(self): # Return the type of the function being called, coercing a function # pointer to a function if necessary. 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): func_type = self.function_type() # Check function type if not func_type.is_cfunction: if not func_type.is_error: error(self.pos, "Calling non-function type '%s'" % func_type) self.type = PyrexTypes.error_type #self.result_code = "" return # Check no. of args expected_nargs = len(func_type.args) actual_nargs = len(self.args) if actual_nargs < expected_nargs \ or (not func_type.has_varargs and actual_nargs > expected_nargs): expected_str = str(expected_nargs) if func_type.has_varargs: expected_str = "at least " + expected_str error(self.pos, "Call with wrong number of arguments (expected %s, got %s)" % (expected_str, actual_nargs)) self.args = None self.type = PyrexTypes.error_type #self.result_code = "" return # Coerce arguments for i in range(expected_nargs): formal_type = func_type.args[i].type self.args[i] = self.args[i].coerce_to(formal_type, env) for i in range(expected_nargs, actual_nargs): if self.args[i].type.is_pyobject: error(self.args[i].pos, "Python object cannot be passed as a varargs parameter") # Calc result type and code fragment self.type = func_type.return_type if self.type.is_pyobject \ or func_type.exception_value is not None \ or func_type.exception_check: self.is_temp = 1 if self.type.is_pyobject: self.result_ctype = py_object_type # Check gil if not func_type.nogil: self.gil_check(env) def calculate_result_code(self): return self.c_call_code() def c_call_code(self): func_type = self.function_type() if self.args is None or not func_type.is_cfunction: return "" formal_args = func_type.args arg_list_code = [] for (formal_arg, actual_arg) in zip(formal_args, self.args): arg_code = actual_arg.result_as(formal_arg.type) arg_list_code.append(arg_code) 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() result = self.result() if func_type.is_pyobject: if self.arg_tuple: arg_code = self.arg_tuple.py_result() else: arg_code = "0" code.putln( "%s = PyObject_CallObject(%s, %s); if (!%s) %s" % ( result, self.function.py_result(), arg_code, result, code.error_goto(self.pos))) elif func_type.is_cfunction: exc_checks = [] if self.type.is_pyobject: exc_checks.append("!%s" % 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: exc_checks.append("PyErr_Occurred()") if self.is_temp or exc_checks: rhs = self.c_call_code() result = self.result() if result: lhs = "%s = " % 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 = "" code.putln( "%s%s; if (%s) %s" % ( lhs, rhs, " && ".join(exc_checks), code.error_goto(self.pos))) 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 # starstar_arg ExprNode or None Dict of extra keyword args subexprs = ['function', 'positional_args', 'keyword_args', 'starstar_arg'] 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) starstar_arg = self.starstar_arg.compile_time_value(denv) try: keyword_args.update(starstar_arg) return function(*positional_args, **keyword_args) except Exception, e: self.compile_time_value_error(e) def analyse_types(self, env): function = self.function function.analyse_types(env) self.positional_args.analyse_types(env) if self.keyword_args: self.keyword_args.analyse_types(env) if self.starstar_arg: self.starstar_arg.analyse_types(env) self.function = self.function.coerce_to_pyobject(env) self.positional_args = \ self.positional_args.coerce_to_pyobject(env) if self.starstar_arg: self.starstar_arg = \ self.starstar_arg.coerce_to_pyobject(env) if function.is_name and function.type_entry: # We are calling an extension type constructor self.type = function.type_entry.type self.result_ctype = py_object_type else: self.type = py_object_type self.gil_check(env) self.is_temp = 1 def generate_result_code(self, code): if self.keyword_args and self.starstar_arg: code.putln( "if (PyDict_Update(%s, %s) < 0) %s" % ( self.keyword_args.py_result(), self.starstar_arg.py_result(), code.error_goto(self.pos))) keyword_code = self.keyword_args.py_result() elif self.keyword_args: keyword_code = self.keyword_args.py_result() elif self.starstar_arg: keyword_code = self.starstar_arg.py_result() else: keyword_code = None if not keyword_code: call_code = "PyObject_CallObject(%s, %s)" % ( self.function.py_result(), self.positional_args.py_result()) else: call_code = "PyEval_CallObjectWithKeywords(%s, %s, %s)" % ( self.function.py_result(), self.positional_args.py_result(), keyword_code) result = self.result() code.putln( "%s = %s; if (!%s) %s" % ( result, call_code, result, code.error_goto(self.pos))) class AsTupleNode(ExprNode): # Convert argument to tuple. Used for normalising # the * argument of a function call. # # arg ExprNode subexprs = ['arg'] 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.analyse_types(env) self.arg = self.arg.coerce_to_pyobject(env) self.type = py_object_type self.gil_check(env) self.is_temp = 1 gil_message = "Constructing Python tuple" def generate_result_code(self, code): result = self.result() code.putln( "%s = PySequence_Tuple(%s); if (!%s) %s" % ( result, self.arg.py_result(), result, code.error_goto(self.pos))) class AttributeNode(ExprNode): # obj.attribute # # obj ExprNode # attribute string # # 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 # interned_attr_cname string C name of interned attribute name is_attribute = 1 subexprs = ['obj'] type = PyrexTypes.error_type result_code = "" entry = None is_called = 0 def compile_time_value(self, denv): attr = self.attribute if attr.beginswith("__") and attr.endswith("__"): self.error("Invalid attribute name '%s' in compile-time expression" % attr) return None obj = self.arg.compile_time_value(denv) try: return getattr(obj, attr) except Exception, e: self.compile_time_value_error(e) def analyse_target_declaration(self, env): pass def analyse_target_types(self, env): self.analyse_types(env, target = 1) def analyse_types(self, env, target = 0): if self.analyse_as_cimported_attribute(env, target): return if not target and self.analyse_as_unbound_cmethod(env): return self.analyse_as_ordinary_attribute(env, target) def analyse_as_cimported_attribute(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): self.mutate_into_name_node(env, entry, target) return 1 return 0 def analyse_as_unbound_cmethod(self, env): # Try to interpret this as a reference to an unbound # C method of an extension type. If successful, mutates # this node into a NameNode and returns 1, otherwise # returns 0. type = self.obj.analyse_as_extension_type(env) if type: entry = type.scope.lookup_here(self.attribute) if entry and entry.is_cmethod: # 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 self.mutate_into_name_node(env, ubcm_entry, None) return 1 return 0 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 and entry.type.is_extension_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 mutate_into_name_node(self, env, entry, target): # Mutate this node into a NameNode and complete the # analyse_types phase. self.__class__ = NameNode self.name = self.attribute self.entry = entry del self.obj del self.attribute if target: NameNode.analyse_target_types(self, env) else: NameNode.analyse_rvalue_entry(self, env) def analyse_as_ordinary_attribute(self, env, target): 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") if self.is_py_attr: if not target: self.is_temp = 1 self.result_ctype = py_object_type def analyse_attribute(self, env): # Look up attribute and set self.type and self.member. self.is_py_attr = 0 self.member = self.attribute if self.obj.type.is_string: self.obj = self.obj.coerce_to_pyobject(env) obj_type = self.obj.type if obj_type.is_ptr: obj_type = obj_type.base_type self.op = "->" elif obj_type.is_extension_type: self.op = "->" else: self.op = "." if obj_type.has_attributes: entry = None if obj_type.attributes_known(): entry = obj_type.scope.lookup_here(self.attribute) else: error(self.pos, "Cannot select attribute of incomplete type '%s'" % obj_type) obj_type = PyrexTypes.error_type self.entry = entry if entry: if obj_type.is_extension_type and entry.name == "__weakref__": error(self.pos, "Illegal use of special attribute __weakref__") if entry.is_variable or entry.is_cmethod: self.type = entry.type self.member = entry.cname return if entry.is_builtin_method and self.is_called: # Mutate into NameNode referring to C function #print "AttributeNode: Mutating builtin method into NameNode" ### self.type = entry.type self.__class__ = NameNode 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. if obj_type.is_pyobject: self.type = py_object_type self.is_py_attr = 1 #self.interned_attr_cname = env.intern(self.attribute) self.gil_check(env) else: if not obj_type.is_error: error(self.pos, "Object of type '%s' has no attribute '%s'" % (obj_type, self.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 1 else: return NameNode.is_lvalue(self) def is_inplace_lvalue(self): return self.is_lvalue() def is_ephemeral(self): if self.obj: return self.obj.is_ephemeral() else: return NameNode.is_ephemeral(self) def calculate_result_code(self): obj = self.obj obj_code = obj.result_as(obj.type) if self.entry and self.entry.is_cmethod: return "((struct %s *)%s%s%s)->%s" % ( obj.type.vtabstruct_cname, obj_code, self.op, obj.type.vtabslot_cname, self.member) else: return "%s%s%s" % (obj_code, self.op, self.member) def generate_result_code(self, code): if self.is_py_attr: result = self.result() cname = code.intern(self.attribute) code.putln( '%s = PyObject_GetAttr(%s, %s); if (!%s) %s' % ( result, self.obj.py_result(), cname, result, code.error_goto(self.pos))) def generate_setattr_code(self, value_code, code): cname = code.intern(self.attribute) code.putln( 'if (PyObject_SetAttr(%s, %s, %s) < 0) %s' % ( self.obj.py_result(), cname, value_code, code.error_goto(self.pos))) def generate_assignment_code(self, rhs, code): self.obj.generate_evaluation_code(code) if self.is_py_attr: self.generate_setattr_code(rhs.py_result(), code) rhs.generate_disposal_code(code) else: select_code = self.result() if self.type.is_pyobject: rhs.make_owned_reference(code) code.put_decref(select_code, self.ctype()) code.putln( "%s = %s;" % ( select_code, rhs.result_as(self.ctype()))) rhs.generate_post_assignment_code(code) self.obj.generate_disposal_code(code) def generate_inplace_assignment_code(self, operator, rhs, code): self.obj.generate_evaluation_code(code) select_code = self.result() if self.type.is_pyobject: self.generate_result_code(code) self.generate_inplace_operation_code(operator, rhs, code) if self.is_py_attr: self.generate_setattr_code(self.inplace_result, code) self.generate_inplace_result_disposal_code(code) else: code.put_decref(select_code, self.ctype()) cast_inplace_result = typecast(self.ctype(), py_object_type, self.inplace_result) code.putln("%s = %s;" % (select_code, cast_inplace_result)) else: code.putln("%s %s %s;" % (select_code, operator, rhs.result())) rhs.generate_disposal_code(code) self.obj.generate_disposal_code(code) def generate_deletion_code(self, code): self.obj.generate_evaluation_code(code) if self.is_py_attr: cname = code.intern(self.attribute) code.putln( 'if (PyObject_DelAttr(%s, %s) < 0) %s' % ( self.obj.py_result(), cname, code.error_goto(self.pos))) else: error(self.pos, "Cannot delete C attribute of extension type") self.obj.generate_disposal_code(code) #------------------------------------------------------------------- # # Constructor nodes # #------------------------------------------------------------------- class SequenceNode(ExprNode): # Base class for list and tuple constructor nodes. # Contains common code for performing sequence unpacking. # # args [ExprNode] # iterator ExprNode # unpacked_items [ExprNode] or None # coerced_unpacked_items [ExprNode] or None subexprs = ['args'] is_sequence_constructor = 1 unpacked_items = None def compile_time_value_list(self, denv): return [arg.compile_time_value(denv) for arg in self.args] def analyse_target_declaration(self, env): for arg in self.args: arg.analyse_target_declaration(env) def analyse_types(self, env): for i in range(len(self.args)): arg = self.args[i] arg.analyse_types(env) self.args[i] = arg.coerce_to_pyobject(env) self.type = py_object_type self.gil_check(env) self.is_temp = 1 def analyse_target_types(self, env): self.iterator = PyTempNode(self.pos, env) self.unpacked_items = [] self.coerced_unpacked_items = [] for arg in self.args: arg.analyse_target_types(env) unpacked_item = PyTempNode(self.pos, env) coerced_unpacked_item = unpacked_item.coerce_to(arg.type, env) self.unpacked_items.append(unpacked_item) self.coerced_unpacked_items.append(coerced_unpacked_item) self.type = py_object_type # env.use_utility_code(unpacking_utility_code) def allocate_target_temps(self, env, rhs): self.iterator.allocate_temps(env) if rhs: rhs.release_temp(env) for arg, node in zip(self.args, self.coerced_unpacked_items): node.allocate_temps(env) arg.allocate_target_temps(env, node) #arg.release_target_temp(env) #node.release_temp(env) self.iterator.release_temp(env) # def release_target_temp(self, env): # #for arg in self.args: # # arg.release_target_temp(env) # #for node in self.coerced_unpacked_items: # # node.release_temp(env) # self.iterator.release_temp(env) def generate_result_code(self, code): self.generate_operation_code(code) def generate_assignment_code(self, rhs, code): iter_result = self.iterator.result() code.putln( "%s = PyObject_GetIter(%s); if (!%s) %s" % ( iter_result, rhs.py_result(), iter_result, code.error_goto(self.pos))) rhs.generate_disposal_code(code) for i in range(len(self.args)): item = self.unpacked_items[i] code.use_utility_code(unpacking_utility_code) unpack_code = "__Pyx_UnpackItem(%s)" % ( self.iterator.py_result()) item_result = item.result() code.putln( "%s = %s; if (!%s) %s" % ( item_result, typecast(item.ctype(), py_object_type, unpack_code), item_result, code.error_goto(self.pos))) value_node = self.coerced_unpacked_items[i] value_node.generate_evaluation_code(code) self.args[i].generate_assignment_code(value_node, code) code.putln( "if (__Pyx_EndUnpack(%s) < 0) %s" % ( self.iterator.py_result(), code.error_goto(self.pos))) if debug_disposal_code: print "UnpackNode.generate_assignment_code:" print "...generating disposal code for", rhs self.iterator.generate_disposal_code(code) class TupleNode(SequenceNode): # Tuple constructor. gil_message = "Constructing Python tuple" 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): result = self.result() code.putln( "%s = PyTuple_New(%s); if (!%s) %s" % ( result, len(self.args), result, code.error_goto(self.pos))) for i in range(len(self.args)): arg = self.args[i] arg_result = arg.py_result() # ??? Change this to use make_owned_reference? if not arg.result_in_temp(): code.put_incref(arg_result) code.putln( "PyTuple_SET_ITEM(%s, %s, %s);" % ( result, i, arg_result)) def generate_subexpr_disposal_code(self, code): # 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) class ListNode(SequenceNode): # List constructor. gil_message = "Constructing Python list" def compile_time_value(self, denv): return self.compile_time_value_list(denv) def generate_operation_code(self, code): result = self.result() code.putln("%s = PyList_New(%s); if (!%s) %s" % (result, len(self.args), result, code.error_goto(self.pos))) for i in range(len(self.args)): arg = self.args[i] arg_result = arg.py_result() #if not arg.is_temp: if not arg.result_in_temp(): code.put_incref(arg_result) code.putln("PyList_SET_ITEM(%s, %s, %s);" % (result, i, arg_result)) def generate_subexpr_disposal_code(self, code): # We call generate_post_assignment_code here instead # of generate_disposal_code, because values were stored # in the list using a reference-stealing operation. for arg in self.args: arg.generate_post_assignment_code(code) class DictNode(ExprNode): # Dictionary constructor. # # key_value_pairs [(ExprNode, ExprNode)] def compile_time_value(self, denv): pairs = [(key.compile_time_value(denv), value.compile_time_value(denv)) for (key, value) in self.key_value_pairs] try: return dict(pairs) except Exception, e: self.compile_time_value_error(e) def analyse_types(self, env): new_pairs = [] for key, value in self.key_value_pairs: key.analyse_types(env) value.analyse_types(env) key = key.coerce_to_pyobject(env) value = value.coerce_to_pyobject(env) new_pairs.append((key, value)) self.key_value_pairs = new_pairs self.type = py_object_type self.gil_check(env) self.is_temp = 1 gil_message = "Constructing Python dict" def allocate_temps(self, env, result = None): # Custom method used here because key-value # pairs are evaluated and used one at a time. self.allocate_temp(env, result) for key, value in self.key_value_pairs: key.allocate_temps(env) value.allocate_temps(env) key.release_temp(env) value.release_temp(env) def generate_evaluation_code(self, code): # Custom method used here because key-value # pairs are evaluated and used one at a time. result = self.result() code.putln( "%s = PyDict_New(); if (!%s) %s" % ( result, result, code.error_goto(self.pos))) for key, value in self.key_value_pairs: key.generate_evaluation_code(code) value.generate_evaluation_code(code) code.putln( "if (PyDict_SetItem(%s, %s, %s) < 0) %s" % ( result, key.py_result(), value.py_result(), code.error_goto(self.pos))) key.generate_disposal_code(code) value.generate_disposal_code(code) class ClassNode(ExprNode): # Helper class used in the implementation of Python # class definitions. Constructs a class object given # a name, tuple of bases and class dictionary. # # name ExprNode 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 string Name of defining module subexprs = ['name', 'bases', 'doc'] def analyse_types(self, env): self.name.analyse_types(env) self.name = self.name.coerce_to_pyobject(env) self.bases.analyse_types(env) if self.doc: self.doc.analyse_types(env) self.doc = self.doc.coerce_to_pyobject(env) self.module_name = env.global_scope().qualified_name self.type = py_object_type self.gil_check(env) self.is_temp = 1 # env.use_utility_code(create_class_utility_code) gil_message = "Constructing Python class" def generate_result_code(self, code): result = self.result() if self.doc: code.putln( 'if (PyDict_SetItemString(%s, "__doc__", %s) < 0) %s' % ( self.dict.py_result(), self.doc.py_result(), code.error_goto(self.pos))) code.use_utility_code(create_class_utility_code) code.putln( '%s = __Pyx_CreateClass(%s, %s, %s, "%s"); if (!%s) %s' % ( result, self.bases.py_result(), self.dict.py_result(), self.name.py_result(), self.module_name, result, code.error_goto(self.pos))) class UnboundMethodNode(ExprNode): # Helper class used in the implementation of Python # class definitions. Constructs an unbound method # object from a class and a function. # # class_cname string C var holding the class object # function ExprNode Function object subexprs = ['function'] def analyse_types(self, env): self.function.analyse_types(env) self.type = py_object_type self.gil_check(env) self.is_temp = 1 gil_message = "Constructing an unbound method" def generate_result_code(self, code): result = self.result() code.putln( "%s = PyMethod_New(%s, 0, %s); if (!%s) %s" % ( result, self.function.py_result(), self.class_cname, result, code.error_goto(self.pos))) class PyCFunctionNode(AtomicExprNode): # Helper class used in the implementation of Python # class definitions. Constructs a PyCFunction object # from a PyMethodDef struct. # # pymethdef_cname string PyMethodDef structure def analyse_types(self, env): self.type = py_object_type self.gil_check(env) self.is_temp = 1 gil_message = "Constructing Python function" def generate_result_code(self, code): result = self.result() code.putln( "%s = PyCFunction_New(&%s, 0); if (!%s) %s" % ( result, self.pymethdef_cname, result, code.error_goto(self.pos))) #------------------------------------------------------------------- # # 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'] 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 analyse_types(self, env): self.operand.analyse_types(env) if self.is_py_operation(): self.coerce_operand_to_pyobject(env) self.type = py_object_type self.gil_check(env) self.is_temp = 1 else: self.analyse_c_operation(env) def check_const(self): self.operand.check_const() def is_py_operation(self): return self.operand.type.is_pyobject 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) else: if self.is_temp: self.generate_c_operation_code(code) def generate_py_operation_code(self, code): function = self.py_operation_function() result = self.result() code.putln( "%s = %s(%s); if (!%s) %s" % ( result, function, self.operand.py_result(), result, code.error_goto(self.pos))) 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 class NotNode(ExprNode): # 'not' operator # # operand ExprNode 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) subexprs = ['operand'] def analyse_types(self, env): self.operand.analyse_types(env) self.operand = self.operand.coerce_to_boolean(env) self.type = PyrexTypes.c_int_type 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 = self.operand.type def py_operation_function(self): return "PyNumber_Positive" def calculate_result_code(self): return self.operand.result() class UnaryMinusNode(UnopNode): # unary '-' operator operator = '-' def analyse_c_operation(self, env): if self.operand.type.is_numeric: self.type = self.operand.type else: self.type_error() def py_operation_function(self): return "PyNumber_Negative" def calculate_result_code(self): return "(-%s)" % self.operand.result() class TildeNode(UnopNode): # unary '~' operator def analyse_c_operation(self, env): if self.operand.type.is_int: self.type = self.operand.type else: self.type_error() def py_operation_function(self): return "PyNumber_Invert" def calculate_result_code(self): return "(~%s)" % self.operand.result() class AmpersandNode(ExprNode): # The C address-of operator. # # operand ExprNode subexprs = ['operand'] def analyse_types(self, env): self.operand.analyse_types(env) argtype = self.operand.type if not (argtype.is_cfunction or self.operand.is_lvalue()): self.error("Taking address of non-lvalue") return if argtype.is_pyobject: self.error("Cannot take address of Python variable") return self.type = PyrexTypes.c_ptr_type(argtype) def check_const(self): 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. return unop_node_classes[operator](pos, operator = operator, operand = operand) class TypecastNode(ExprNode): # C type cast # # base_type CBaseTypeNode # declarator CDeclaratorNode # operand ExprNode subexprs = ['operand'] def analyse_types(self, env): base_type = self.base_type.analyse(env) _, self.type = self.declarator.analyse(base_type, env) if self.type.is_cfunction: error(self.pos, "Cannot cast to a function type") self.type = PyrexTypes.error_type self.operand.analyse_types(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(): error(self.pos, "Casting temporary Python object to non-Python type") #if to_py and not from_py: # self.result_ctype = py_object_type # self.is_temp = 1 def check_const(self): self.operand.check_const() def calculate_result_code(self): opnd = self.operand result_code = self.type.cast_code(opnd.result()) return result_code def result_as(self, type): #if self.type.is_pyobject and not self.is_temp: if 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 = %s;" % ( self.result(), self.operand.py_result())) code.put_incref(self.py_result()) class SizeofNode(ExprNode): # Abstract base class for sizeof(x) expression nodes. def check_const(self): pass def generate_result_code(self, code): pass class SizeofTypeNode(SizeofNode): # C sizeof function applied to a type # # base_type CBaseTypeNode # declarator CDeclaratorNode subexprs = [] def analyse_types(self, env): base_type = self.base_type.analyse(env) _, arg_type = self.declarator.analyse(base_type, env) self.arg_type = arg_type if arg_type.is_pyobject: 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) self.type = PyrexTypes.c_int_type def calculate_result_code(self): 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): self.operand.analyse_types(env) self.type = PyrexTypes.c_int_type def calculate_result_code(self): return "(sizeof(%s))" % self.operand.result() def generate_result_code(self, code): pass #------------------------------------------------------------------- # # 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.div, '//': operator.floordiv, '<<': operator.lshift, '%': operator.mod, '*': operator.mul, '|': operator.or_, '**': operator.pow, '>>': operator.rshift, '-': operator.sub, #'/': operator.truediv, '^': operator.xor, 'in': lambda x, y: x in y, 'not_in': lambda x, y: x not in y, } 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'] 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 analyse_types(self, env): self.operand1.analyse_types(env) self.operand2.analyse_types(env) if self.is_py_operation(): self.coerce_operands_to_pyobjects(env) self.type = py_object_type self.gil_check(env) self.is_temp = 1 else: self.analyse_c_operation(env) def is_py_operation(self): return (self.operand1.type.is_pyobject or self.operand2.type.is_pyobject) 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): self.operand1.check_const() 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 function == "PyNumber_Power": extra_args = ", Py_None" else: extra_args = "" result = self.result() code.putln( "%s = %s(%s, %s%s); if (!%s) %s" % ( result, function, self.operand1.py_result(), self.operand2.py_result(), extra_args, result, code.error_goto(self.pos))) else: if self.is_temp: self.generate_c_operation_code(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 NumBinopNode(BinopNode): # Binary operation taking numeric arguments. def analyse_c_operation(self, env): type1 = self.operand1.type type2 = self.operand2.type if self.operator == "**" and type1.is_int and type2.is_int: error(self.pos, "** with two C int types is ambiguous") self.type = error_type return self.type = self.compute_c_result_type(type1, type2) if not self.type: self.type_error() def compute_c_result_type(self, type1, type2): if self.c_types_okay(type1, type2): return PyrexTypes.widest_numeric_type(type1, type2) 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 calculate_result_code(self): return "(%s %s %s)" % ( self.operand1.result(), self.operator, self.operand2.result()) def py_operation_function(self): return self.py_functions[self.operator] py_functions = { "|": "PyNumber_Or", "^": "PyNumber_Xor", "&": "PyNumber_And", "<<": "PyNumber_Lshift", ">>": "PyNumber_Rshift", "+": "PyNumber_Add", "-": "PyNumber_Subtract", "*": "PyNumber_Multiply", "/": "PyNumber_Divide", "%": "PyNumber_Remainder", "**": "PyNumber_Power" } 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(self): if self.operand1.type.is_string \ and self.operand2.type.is_string: return 1 else: return NumBinopNode.is_py_operation(self) 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) 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_int_type else: return NumBinopNode.compute_c_result_type( self, type1, type2) class MulNode(NumBinopNode): # '*' operator. def is_py_operation(self): type1 = self.operand1.type type2 = self.operand2.type if (type1.is_string and type2.is_int) \ or (type2.is_string and type1.is_int): return 1 else: return NumBinopNode.is_py_operation(self) class ModNode(IntBinopNode): # '%' operator. def is_py_operation(self): return (self.operand1.type.is_string or self.operand2.type.is_string or IntBinopNode.is_py_operation(self)) class PowNode(NumBinopNode): # '**' operator. def analyse_types(self, env): env.pow_function_used = 1 NumBinopNode.analyse_types(self, env) def compute_c_result_type(self, type1, type2): if self.c_types_okay(type1, type2): return PyrexTypes.c_double_type else: return None def calculate_result_code(self): return "pow(%s, %s)" % ( self.operand1.result(), self.operand2.result()) class BoolBinopNode(ExprNode): # Short-circuiting boolean operation. # # operator string # operand1 ExprNode # operand2 ExprNode # temp_bool ExprNode used internally temp_bool = None subexprs = ['operand1', 'operand2', 'temp_bool'] 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 analyse_types(self, env): self.operand1.analyse_types(env) self.operand2.analyse_types(env) if self.operand1.type.is_pyobject or \ self.operand2.type.is_pyobject: self.operand1 = self.operand1.coerce_to_pyobject(env) self.operand2 = self.operand2.coerce_to_pyobject(env) self.temp_bool = TempNode(self.pos, PyrexTypes.c_int_type, env) self.type = py_object_type self.gil_check(env) else: self.operand1 = self.operand1.coerce_to_boolean(env) self.operand2 = self.operand2.coerce_to_boolean(env) self.type = PyrexTypes.c_int_type # For what we're about to do, it's vital that # both operands be temp nodes. self.operand1 = self.operand1.coerce_to_temp(env) #CTT self.operand2 = self.operand2.coerce_to_temp(env) self.is_temp = 1 gil_message = "Truth-testing Python object" def allocate_temps(self, env, result_code = None): # We don't need both operands at the same time, and # one of the operands will also be our result. So we # use an allocation strategy here which results in # this node and both its operands sharing the same # result variable. This allows us to avoid some # assignments and increfs/decrefs that would otherwise # be necessary. self.allocate_temp(env, result_code) self.operand1.allocate_temps(env, self.result_code) if self.temp_bool: self.temp_bool.allocate_temp(env) self.temp_bool.release_temp(env) self.operand2.allocate_temps(env, self.result_code) # We haven't called release_temp on either operand, # because although they are temp nodes, they don't own # their result variable. And because they are temp # nodes, any temps in their subnodes will have been # released before their allocate_temps returned. # Therefore, they contain no temp vars that need to # be released. def check_const(self): self.operand1.check_const() self.operand2.check_const() def calculate_result_code(self): return "(%s %s %s)" % ( self.operand1.result(), self.py_to_c_op[self.operator], self.operand2.result()) py_to_c_op = {'and': "&&", 'or': "||"} def generate_evaluation_code(self, code): self.operand1.generate_evaluation_code(code) test_result = self.generate_operand1_test(code) if self.operator == 'and': sense = "" else: sense = "!" code.putln( "if (%s%s) {" % ( sense, test_result)) self.operand1.generate_disposal_code(code) self.operand2.generate_evaluation_code(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 = self.temp_bool.result() code.putln( "%s = PyObject_IsTrue(%s); if (%s < 0) %s" % ( test_result, self.operand1.py_result(), test_result, code.error_goto(self.pos))) else: test_result = self.operand1.result() return test_result class CmpNode: # Mixin class containing code common to PrimaryCmpNodes # and CascadedCmpNodes. 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.compile_time_value(operand2, denv) return result def is_python_comparison(self): return (self.has_python_operands() or (self.cascade and self.cascade.is_python_comparison()) or self.operator in ('in', 'not_in')) def check_types(self, env, operand1, op, operand2): if not self.types_okay(operand1, op, operand2): error(self.pos, "Invalid types for '%s' (%s, %s)" % (self.operator, operand1.type, operand2.type)) def types_okay(self, operand1, op, operand2): type1 = operand1.type type2 = operand2.type if type1.is_error or type2.is_error: return 1 if type1.is_pyobject: # type2 will be, too return 1 elif type1.is_ptr or type1.is_array: return type1.is_null_ptr or type2.is_null_ptr \ or ((type2.is_ptr or type2.is_array) and type1.base_type.same_as(type2.base_type)) elif ((type1.is_numeric and type2.is_numeric or type1.is_enum and (type2.is_int or type1.same_as(type2)) or type1.is_int and type2.is_enum) and op not in ('is', 'is_not')): return 1 else: return 0 def generate_operation_code(self, code, result, operand1, op , operand2): if op == 'in' or op == 'not_in': code.putln( "%s = PySequence_Contains(%s, %s); if (%s < 0) %s" % ( result, operand2.py_result(), operand1.py_result(), result, code.error_goto(self.pos))) if op == 'not_in': code.putln( "%s = !%s;" % ( result, result)) elif (operand1.type.is_pyobject and op not in ('is', 'is_not')): code.putln( "if (PyObject_Cmp(%s, %s, &%s) < 0) %s" % ( operand1.py_result(), operand2.py_result(), result, code.error_goto(self.pos))) code.putln( "%s = %s %s 0;" % ( result, result, op)) else: type1 = operand1.type type2 = operand2.type if (type1.is_extension_type or type2.is_extension_type) \ and not operand1.ctype().same_as(operand2.ctype()): code1 = operand1.result_as(py_object_type) code2 = operand2.result_as(py_object_type) else: code1 = operand1.result() code2 = operand2.result() code.putln("%s = %s %s %s;" % ( 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. cascade = None 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.analyse_types(env) self.operand2.analyse_types(env) if self.cascade: self.cascade.analyse_types(env, self.operand2) self.is_pycmp = self.is_python_comparison() if self.is_pycmp: self.coerce_operands_to_pyobjects(env) if self.cascade: self.operand2 = self.operand2.coerce_to_simple(env) self.cascade.coerce_cascaded_operands_to_temp(env) self.check_operand_types(env) self.type = PyrexTypes.c_int_type if self.is_pycmp or self.cascade: self.is_temp = 1 def check_operand_types(self, env): self.check_types(env, self.operand1, self.operator, self.operand2) if self.cascade: self.cascade.check_operand_types(env, self.operand2) def has_python_operands(self): return (self.operand1.type.is_pyobject or self.operand2.type.is_pyobject) def coerce_operands_to_pyobjects(self, env): self.operand1 = self.operand1.coerce_to_pyobject(env) self.operand2 = self.operand2.coerce_to_pyobject(env) if self.cascade: self.cascade.coerce_operands_to_pyobjects(env) def allocate_subexpr_temps(self, env): self.operand1.allocate_temps(env) self.operand2.allocate_temps(env) if self.cascade: self.cascade.allocate_subexpr_temps(env) def release_subexpr_temps(self, env): self.operand1.release_temp(env) self.operand2.release_temp(env) if self.cascade: self.cascade.release_subexpr_temps(env) def check_const(self): self.operand1.check_const() self.operand2.check_const() if self.cascade: self.not_const() def calculate_result_code(self): return "(%s %s %s)" % ( self.operand1.result(), self.c_operator(self.operator), self.operand2.result()) def generate_evaluation_code(self, code): self.operand1.generate_evaluation_code(code) self.operand2.generate_evaluation_code(code) if self.is_temp: result = self.result() self.generate_operation_code(code, result, self.operand1, self.operator, self.operand2) if self.cascade: self.cascade.generate_evaluation_code(code, result, self.operand2) self.operand1.generate_disposal_code(code) self.operand2.generate_disposal_code(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) 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 cascade = None def analyse_types(self, env, operand1): self.operand2.analyse_types(env) if self.cascade: self.cascade.analyse_types(env, self.operand2) def check_operand_types(self, env, operand1): self.check_types(env, operand1, self.operator, self.operand2) if self.cascade: self.cascade.check_operand_types(env, self.operand2) def has_python_operands(self): return self.operand2.type.is_pyobject def coerce_operands_to_pyobjects(self, env): self.operand2 = self.operand2.coerce_to_pyobject(env) 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 allocate_subexpr_temps(self, env): self.operand2.allocate_temps(env) if self.cascade: self.cascade.allocate_subexpr_temps(env) def release_subexpr_temps(self, env): self.operand2.release_temp(env) if self.cascade: self.cascade.release_subexpr_temps(env) def generate_evaluation_code(self, code, result, operand1): code.putln("if (%s) {" % result) 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.operand2) # Cascaded cmp result is always temp self.operand2.generate_disposal_code(code) code.putln("}") binop_node_classes = { "or": BoolBinopNode, "and": BoolBinopNode, "|": IntBinopNode, "^": IntBinopNode, "&": IntBinopNode, "<<": IntBinopNode, ">>": IntBinopNode, "+": AddNode, "-": SubNode, "*": MulNode, "/": NumBinopNode, "%": ModNode, "**": PowNode } def binop_node(pos, operator, operand1, operand2): # Construct binop node of appropriate class for # given operator. return binop_node_classes[operator](pos, operator = operator, operand1 = operand1, operand2 = operand2) #------------------------------------------------------------------- # # 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'] def __init__(self, arg): self.pos = arg.pos self.arg = arg if debug_coercion: print self, "Coercing", self.arg 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 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. def __init__(self, arg, dst_type, env): # 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, "PyTypeTest on non extension type" CoercionNode.__init__(self, arg) self.type = dst_type self.result_ctype = arg.ctype() # env.use_utility_code(type_test_utility_code) self.gil_check(env) gil_message = "Python type test" def result_in_temp(self): return self.arg.result_in_temp() def is_ephemeral(self): return self.arg.is_ephemeral() def calculate_result_code(self): return self.arg.result() def generate_result_code(self, code): if self.type.typeobj_is_available(): code.use_utility_code(type_test_utility_code) code.putln( "if (!__Pyx_TypeTest(%s, %s)) %s" % ( self.arg.py_result(), self.type.typeptr_cname, 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) class CoerceToPyTypeNode(CoercionNode): # This node is used to convert a C data type # to a Python object. def __init__(self, arg, env): CoercionNode.__init__(self, arg) self.type = py_object_type self.gil_check(env) self.is_temp = 1 if not arg.type.to_py_function: error(arg.pos, "Cannot convert '%s' to Python object" % arg.type) gil_message = "Converting to Python object" def generate_result_code(self, code): function = self.arg.type.to_py_function result = self.result() code.putln('%s = %s(%s); if (!%s) %s' % ( result, function, self.arg.result(), result, code.error_goto(self.pos))) 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.from_py_function: error(arg.pos, "Cannot convert Python object to '%s'" % result_type) if self.type.is_string and self.arg.is_ephemeral(): error(arg.pos, "Obtaining char * from temporary Python value") 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) result = self.result() if self.type.is_string: err_code = "!%s" % result else: err_code = "PyErr_Occurred()" code.putln('%s = %s; if (%s) %s' % ( result, rhs, err_code, code.error_goto(self.pos))) class CoerceToBooleanNode(CoercionNode): # This node is used when a result needs to be used # in a boolean context. def __init__(self, arg, env): CoercionNode.__init__(self, arg) self.type = PyrexTypes.c_int_type if arg.type.is_pyobject: if env.nogil: self.gil_error() self.is_temp = 1 gil_message = "Truth-testing Python object" def check_const(self): if self.is_temp: self.not_const() self.arg.check_const() def calculate_result_code(self): return "(%s != 0)" % self.arg.result() def generate_result_code(self, code): if self.arg.type.is_pyobject: result = self.result() code.putln( "%s = PyObject_IsTrue(%s); if (%s < 0) %s" % ( result, self.arg.py_result(), result, code.error_goto(self.pos))) 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 self.is_temp = 1 if self.type.is_pyobject: self.gil_check(env) self.result_ctype = py_object_type gil_message = "Creating temporary Python reference" 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.type.is_pyobject: code.put_incref(self.py_result()) 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 def __init__(self, arg): CoercionNode.__init__(self, arg) self.type = arg.type self.result_ctype = arg.result_ctype def calculate_result_code(self): return self.arg.result() def generate_evaluation_code(self, code): pass def generate_result_code(self, code): pass #------------------------------------------------------------------------------------ # # Runtime support code # #------------------------------------------------------------------------------------ get_name_utility_code = [ """ static PyObject *__Pyx_GetName(PyObject *dict, char *name); /*proto*/ """,""" static PyObject *__Pyx_GetName(PyObject *dict, char *name) { PyObject *result; result = PyObject_GetAttrString(dict, name); if (!result) PyErr_SetString(PyExc_NameError, name); return result; } """] get_name_interned_utility_code = [ """ static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ """,""" static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { PyObject *result; result = PyObject_GetAttr(dict, name); if (!result) PyErr_SetObject(PyExc_NameError, name); return result; } """] #------------------------------------------------------------------------------------ import_utility_code = [ """ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/ """,""" static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) { PyObject *__import__ = 0; PyObject *empty_list = 0; PyObject *module = 0; PyObject *global_dict = 0; PyObject *empty_dict = 0; PyObject *list; __import__ = PyObject_GetAttrString(%(BUILTINS)s, "__import__"); if (!__import__) goto bad; if (from_list) list = from_list; else { empty_list = PyList_New(0); if (!empty_list) goto bad; list = empty_list; } global_dict = PyModule_GetDict(%(GLOBALS)s); if (!global_dict) goto bad; empty_dict = PyDict_New(); if (!empty_dict) goto bad; module = PyObject_CallFunction(__import__, "OOOO", name, global_dict, empty_dict, list); bad: Py_XDECREF(empty_list); Py_XDECREF(__import__); Py_XDECREF(empty_dict); return module; } """ % { "BUILTINS": Naming.builtins_cname, "GLOBALS": Naming.module_cname, }] #------------------------------------------------------------------------------------ # #get_exception_utility_code = [ #""" #static PyObject *__Pyx_GetExcValue(void); /*proto*/ #""",""" #static PyObject *__Pyx_GetExcValue(void) { # PyObject *type = 0, *value = 0, *tb = 0; # PyObject *result = 0; # PyThreadState *tstate = PyThreadState_Get(); # PyErr_Fetch(&type, &value, &tb); # PyErr_NormalizeException(&type, &value, &tb); # if (PyErr_Occurred()) # goto bad; # if (!value) { # value = Py_None; # Py_INCREF(value); # } # Py_XDECREF(tstate->exc_type); # Py_XDECREF(tstate->exc_value); # Py_XDECREF(tstate->exc_traceback); # tstate->exc_type = type; # tstate->exc_value = value; # tstate->exc_traceback = tb; # result = value; # Py_XINCREF(result); # type = 0; # value = 0; # tb = 0; #bad: # Py_XDECREF(type); # Py_XDECREF(value); # Py_XDECREF(tb); # return result; #} #"""] # #------------------------------------------------------------------------------------ unpacking_utility_code = [ """ static PyObject *__Pyx_UnpackItem(PyObject *); /*proto*/ static int __Pyx_EndUnpack(PyObject *); /*proto*/ """,""" static void __Pyx_UnpackError(void) { PyErr_SetString(PyExc_ValueError, "unpack sequence of wrong size"); } static PyObject *__Pyx_UnpackItem(PyObject *iter) { PyObject *item; if (!(item = PyIter_Next(iter))) { if (!PyErr_Occurred()) __Pyx_UnpackError(); } return item; } static int __Pyx_EndUnpack(PyObject *iter) { PyObject *item; if ((item = PyIter_Next(iter))) { Py_DECREF(item); __Pyx_UnpackError(); return -1; } else if (!PyErr_Occurred()) return 0; else return -1; } """] #------------------------------------------------------------------------------------ type_test_utility_code = [ """ static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/ """,""" static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { if (!type) { PyErr_Format(PyExc_SystemError, "Missing type object"); return 0; } if (obj == Py_None || PyObject_TypeCheck(obj, type)) return 1; PyErr_Format(PyExc_TypeError, "Cannot convert %s to %s", obj->ob_type->tp_name, type->tp_name); return 0; } """] #------------------------------------------------------------------------------------ create_class_utility_code = [ """ static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/ """,""" static PyObject *__Pyx_CreateClass( PyObject *bases, PyObject *dict, PyObject *name, char *modname) { PyObject *py_modname; PyObject *result = 0; py_modname = PyString_FromString(modname); if (!py_modname) goto bad; if (PyDict_SetItemString(dict, "__module__", py_modname) < 0) goto bad; result = PyClass_New(bases, dict, name); bad: Py_XDECREF(py_modname); return result; } """] #------------------------------------------------------------------------------------ getitem_int_utility_code = [ """ static PyObject *__Pyx_GetItemInt(PyObject *o, Py_ssize_t i); /*proto*/ """,""" static PyObject *__Pyx_GetItemInt(PyObject *o, Py_ssize_t i) { PyTypeObject *t = o->ob_type; PyObject *r; if (t->tp_as_sequence && t->tp_as_sequence->sq_item) r = PySequence_GetItem(o, i); else { PyObject *j = PyInt_FromLong(i); if (!j) return 0; r = PyObject_GetItem(o, j); Py_DECREF(j); } return r; } """] #------------------------------------------------------------------------------------ setitem_int_utility_code = [ """ static int __Pyx_SetItemInt(PyObject *o, Py_ssize_t i, PyObject *v); /*proto*/ """,""" static int __Pyx_SetItemInt(PyObject *o, Py_ssize_t i, PyObject *v) { PyTypeObject *t = o->ob_type; int r; if (t->tp_as_sequence && t->tp_as_sequence->sq_item) r = PySequence_SetItem(o, i, v); else { PyObject *j = PyInt_FromLong(i); if (!j) return -1; r = PyObject_SetItem(o, j, v); Py_DECREF(j); } return r; } """] Pyrex-0.9.8.5/Pyrex/Compiler/Lexicon.pickle0000644001243100001200000004546611011707663020560 0ustar00gregadmin00000000000000U c5454f3646e413f561018e5d29aec1aaq.(cPyrex.Plex.Lexicons Lexicon qoq}qUmachineq(cPyrex.Plex.Machines FastMachine qoq}q(Ustatesq]q (}q (UNU }q (UNU h Ubolq }q (UNU h h NUeofqNU h UactionqNUeolqNU h UnumberqKHUelseqNuhNU h h(cPyrex.Plex.Actions Ignore qoq}qU__doc__qUŒ IGNORE is a Plex action which causes its associated token to be ignored. See the docstring of Plex.Lexicon for more information. qsbhNU h hKhNuU h U"}q(UNU"}q(UNU"}q(UNh NhNh(cPyrex.Plex.Actions Call qoq}qUfunctionq(cPyrex.Compiler.Scanning Method qoq }q!(U__name__q"Ubegin_string_actionq#Unameq$h#ubsbhNhKxhNuh NhNhNhNhKIhNuh NhNhhhNhK hNuU&}q%(UNh NhNh(cPyrex.Plex.Actions Text q&oq'}q(hU¤ TEXT is a Plex action which causes the text of a token to be returned as the value of the token. See the docstring of Plex.Lexicon for more information. q)sbhNU=}q*(UNh NhNhh'hNhKhNuhK hNuU(}q+(UNh NhNh(hoq,}q-h(hoq.}q/(h"Uopen_bracket_actionq0h$h0ubsbhNhKhNuU*}q1(UNU*}q2(UNh NhNhh'hNU=h*hKMhNuh NhNhh'hNU=h*hKhNuU,h*U.}q3(UNhKhNU9}q4(UNUE}q5(UNhKyhNU9}q6(UNUJ}q7(UNh NhNh(cPyrex.Plex.Actions Return q8oq9}q:Uvalueq;UIMAGqh;UFLOATq?sbU5h6uU8h6hNU+}q@(UNhK„hNU9h6U8h6hNhNU1h6U0h6U3h6U2h6h NU4h6U7h6U6h6hNU5h6uU-h@hNU1h6U0h6U3h6U2h6h NU4h6U7h6U6h6hNU5h6uUJh7hKNhNU9h4U8h4Ueh5hNUjh7hNU1h4U0h4U3h4U2h4h NU4h4U7h4U6h4hh=U5h4uU8h4hNhNU1h4U0h4U3h4U2h4h NU4h4U7h4U6h4hh'U5h4uU0}qA(UNUE}qB(UNhKPhNU9}qC(UNUJh7hK|hNU9hCU8hChNUjh7hNU1hCU0hCU3hCU2hCh NU4hCU7hCU6hChh=U5hCuU8hChNU+}qD(UNhK{hNU9hCU8hChNhNU1hCU0hCU3hCU2hCh NU4hCU7hCU6hChNU5hCuU-hDhNU1hCU0hCU3hCU2hCh NU4hCU7hCU6hChNU5hCuUJh7hKhNU9}qE(UNUEhBUJh7hKhNU9hEU8hEhNUL}qF(UNh NhNh(h8oqG}qHh;ULONGqIsbhNhKRhNuUehBhNUjh7U.}qJ(UNUEh5UJh7hKOhNU9}qK(UNUEh5UJh7hKzhNU9hKU8hKUeh5hNUjh7hNU1hKU0hKU3hKU2hKh NU4hKU7hKU6hKhh=U5hKuU8hKUeh5hNUjh7hNU1hKU0hKU3hKU2hKh NU4hKU7hKU6hKhh=U5hKuU1hEU0hEU3hEU2hEh NU4hEU7hEU6hEh(h8oqL}qMh;UINTqNsbU5hEuU8hEhNULhFUx}qO(UNUA}qP(UNUAhPUChPUBhPUEhPUDhPUFhPUJh7hK}hNU9hPU8hPULhFUdhPUahPUchPUbhPUehPhNUfhPUjh7hNU1hPU0hPU3hPU2hPh NU4hPU7hPU6hPhhLU5hPuUChPUBhPUEhPUDhPUFhPhKShNU9hPU8hPUdhPUahPUchPUbhPUehPhNUfhPhNU1hPU0hPU3hPU2hPh NU4hPU7hPU6hPhNU5hPuUehBhNUjh7U.hJU1hEU0hEU3hEU2hEh NU4hEU7hEU6hEhhLU5hEuU2hEU4hEU6hEU8hEU:h*U<}qQ(UNU>h*h NhNU<}qR(UNh NhNhh'hNU=h*hKThNuhh'hNU=h*hKhNuU>}qS(UNU>}qT(UNh NhNhh'hNU=h*hKUhNuh NhNhh'hNU=h*hKhNuUB}qU(UNhKU0}qV(UNhKVU0hVU2hVU4hVU6hVU8hVUBhVUDhVUFhVUHhVUJhVULhVhNUPhVURhVUThVUVhVUXhVUZhVUbhVUdhVUfhVUhhVUjhVUlhVUnhVUphVUrhVUthVUvhVUxhVUzhVU1hVU3hVU5hVU7hVU9hVUuhVUAhVUChVUEhVUGhVUIhVUKhVUMhVUOhVUQhVUyhVUShVUUhVUWhVUYhVUNhVU_hVUahVUchVUehVhNUghVUihVUkhVUmhVUohVhNUqhVUshVh NUwhVh(h8oqW}qXh;UIDENTqYsbuU2hVU4hVU6hVU8hVUBhVUDhVUFhVUHhVUJhVULhVhNUPhVURhVUThVUVhVUXhVUZhVUbhVUdhVUfhVUhhVUjhVUlhVUnhVUphVUrhVUthVUvhVUxhVUzhVU1hVU3hVU5hVU7hVU9hVUuhVUAhVUChVUEhVUGhVUIhVUKhVUMhVUOhVUQhVUyhVUShVUUhVUWhVUYhVUNhVU_hVUahVUchVUehVhNUghVUihVUkhVUmhVUohVhNUqhVUshVh NUwhVhhWuUDhUUFhUUHhUUJhUULhUhKUPhUUR}qZ(UNhKU"hU0hVU2hVU4hVU6hVU8hVUBhVUDhVUFhVUHhVUJhVULhVhNUPhVURhVUThVUVhVUXhVUZhVUbhVUdhVUfhVUhhVUjhVUlhVUnhVUphVUrhVUthVUvhVUxhVUzhVU'}q[(UNh NhNU'}q\(UNh NhNU'hhNhNhKLhNuhhhNhK hNuU1hVU3hVU5hVU7hVU9hVUuhVUAhVUChVUEhVUGhVUIhVUKhVUMhVUOhVUQhVUyhVUShVUUhVUWhVUYhVUNhVU_hVUahVUchVUehVhNUghVUihVUkhVUmhVUohVhNUqhVUshVh }q](UNU"hh NhNU'h[hNhNhKWhNuUwhVhhWuUThUUVhUUXhUUZhUU\}q^(UNU }q_(UNh NhNhhhNhKXhNuh NhNhNh}q`(UNU h_h NhNhNhNhKYhNuhKhNuU^}qa(UNh NhNhh'hNU=h*hKhNuU`h*UbhUUdhUUfhUUhhUUjhUUlhUUnhUUphUUrhZUthUUvhUUxhUUzhUU|}qb(UNh NhNhh'hNU=h*hKhNuU~h*U h U!}qc(UNh NhNhNhNU=h*hKhNuU#}qd(UNU }qe(UNh NhNhNhNhKKhNuh NhNhhhNhK h}qf(UNU heh NhNhhhNhKJhhfuuU%}qg(UNh NhNhh'hNU=h*hK hNuU'h[U)}qh(UNh NhNh(hoqi}qjh(hoqk}ql(h"Uclose_bracket_actionqmh$hmubsbhNhKhNuU+}qn(UNh NhNhh'hNU=h*hKhNuU-}qo(UNh NhNhh'hNU=h*hKhNuUshUU/}qp(UNh NhNhh'hNU=h*hKhNuU1hEU3hEU5hEU7hEU9hEUuhUU;h*U=}qq(UNh NhNhh'hNU=h*hKhNuU?h*UAhUUChZUEhUUGhUUIhUUKhUUMhUUOhUUQhUUyhUUShUUUhUUWhUUYhUU[h+hNU]hhU_hUUahUUchZUehUh}qr(UNh NhNh(hoqs}qth(hoqu}qv(h"U eof_actionqwh$hwubsbhNhK!hNuUghUUihUUkhUUmhUUohUh}qx(UNU }qy(UNh NhNh(hoqz}q{h(hoq|}q}(h"Unewline_actionq~h$h~ubsbhNhKZhNuh NhNhhzh}q(UNU hyh NhNhNhNhK[hNuhK"hNuUqhUUNhUh }q€(UNU h U h U"hU&h%U(h+U*h1U,h*U.h3U0hAU2hEU4hEU6hEU8hEU:h*UhSUBhUUDhUUFhUUHhUUJhUULhUhK UPhUURhZUThUUVhUUXhUUZhUU\h^U^haU`h*UbhUUdhUUfhUUhhUUjhUUlhUUnhUUphUUrhZUthUUvhUUxhUUzhUU|hbU~h*U h U!hcU#hdU%hgU'h[U)hhU+hnU-hoUshUU/hpU1hEU3hEU5hEU7hEU9hEUuhUU;h*U=hqU?h*UAhUUChZUEhUUGhUUIhUUKhUUMhUUOhUUQhUUyhUUShUUUhUUWhUUYhUU[h+hNU]hhU_hUUahUUchZUehUhNUghUUihUUkhUUmhUUohUhhxUqhUUNhUh NUwhUhNU{h+U}hhuUwhUhNU{h+U}hhu}q(UNU }q‚(UNh NhNh(hoqƒ}q„h(hoq…}q†(h"Uunclosed_string_actionq‡h$h‡ubsbhNhK$hNuU }qˆ(UNU heU hˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆU hˆU"heU$hˆU&hˆU(hˆU*hˆU,hˆU.hˆU0hˆU2hˆU4hˆU6hˆU8hˆU:hˆUhˆU@hˆUBhˆUDhˆUFhˆUHhˆUJhˆULhˆhK#UPhˆURhˆUThˆUVhˆUXhˆUZhˆU\heU hˆU hˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆU!hˆU#hˆU%hˆU'hˆU)hˆU+hˆU-hˆU/hˆU1hˆU3hˆU5hˆU7hˆU9hˆU;hˆU=hˆU?hˆUAhˆUChˆUEhˆUGhˆUIhˆUKhˆUMhˆUOhˆUQhˆUShˆUUhˆUWhˆUYhˆU[hˆhhˆhNhNUNhˆh }q‰(UNU heU hˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆU hˆU"heU$hˆU&hˆU(hˆU*hˆU,hˆU.hˆU0hˆU2hˆU4hˆU6hˆU8hˆU:hˆUhˆU@hˆUBhˆUDhˆUFhˆUHhˆUJhˆULhˆhK\UPhˆURhˆUThˆUVhˆUXhˆUZhˆU\heU hˆU hˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆU!hˆU#hˆU%hˆU'hˆU)hˆU+hˆU-hˆU/hˆU1hˆU3hˆU5hˆU7hˆU9hˆU;hˆU=hˆU?hˆUAhˆUChˆUEhˆUGhˆUIhˆUKhˆUMhˆUOhˆUQhˆUShˆUUhˆUWhˆUYhˆU[hˆhhˆhNhNUNhˆh NhNuh(h8oqŠ}q‹h;UCHARSqŒsbuUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆU hˆU"}q(UNh NhNh(hoqŽ}qh(hoq}q‘(h"Uend_string_actionq’h$h’ubsbhNhK%hNuU$hˆU&hˆU(hˆU*hˆU,hˆU.hˆU0hˆU2hˆU4hˆU6hˆU8hˆU:hˆUhˆU@hˆUBhˆUDhˆUFhˆUHhˆUJhˆULhˆhKUPhˆURhˆUThˆUVhˆUXhˆUZhˆU\}q“(UNU }q”(UNh NhNh(h8oq•}q–h;UESCAPEq—sbhNhK]hNuU h”Uh”Uh”Uh”Uh”Uh”Uh”Uh”Uh”Uh”U h”U"h”U$h”U&h”U(h”U*h”U,h”U.h”U0}q˜(UNUAh”UCh”UBh”UEh”UDh”UFh”hK^hNU9h”U8h”Udh”Uah”Uch”Ubh”Ueh”hNUfh”hNU1}q™(UNhK~hNhNhNU1h”U0h”U3h”U2h”h NU4h”U7h”U6h”hh•U5h”uU0h™U3h™U2h™h NU4h™U7h™U6h™hh•U5h™uU2h˜U4h˜U6h˜U8}qš(UNUAh”UCh”UBh”UEh”UDh”UFh”hK_hNU9h”U8h”Udh”Uah”Uch”Ubh”Ueh”hNUfh”hNU1h”U0h”U3h”U2h”h NU4h”U7h”U6h”hh•U5h”uU:h”Uh”U@h”UBhšUDhšUFhšUHh”UJh”ULh”hK'UPh”URh”UTh”UVh”UXh”UZh”U\h”U^h”U`h”UbhšUdhšUfhšU h”U h”Uh”Uh”Uh”Uh”Uh”Uh”Uh”Uh”Uh”U!h”U#h”U%h”U'h”U)h”U+h”U-h”U/h”U1h˜U3h˜U5h˜U7h˜U9hšU;h”U=h”U?h”UAhšUChšUEhšUGh”UIh”UKh”UMh”UOh”UQh”USh”UUh”UWh”UYh”U[h”hh”U]h”U_h”UahšUchšUehšhNh}q›(UNU h”h NhNhNhNhK`hNuUNh”h NhNuU hˆU hˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆU!hˆU#hˆU%hˆU'}qœ(UNU heU hˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆU hˆU"heU$hˆU&hˆU(hˆU*hˆU,hˆU.hˆU0hˆU2hˆU4hˆU6hˆU8hˆU:hˆUhˆU@hˆUBhˆUDhˆUFhˆUHhˆUJhˆULhˆhK&UPhˆURhˆUThˆUVhˆUXhˆUZhˆU\heU hˆU hˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆU!hˆU#hˆU%hˆU'hˆU)hˆU+hˆU-hˆU/hˆU1hˆU3hˆU5hˆU7hˆU9hˆU;hˆU=hˆU?hˆUAhˆUChˆUEhˆUGhˆUIhˆUKhˆUMhˆUOhˆUQhˆUShˆUUhˆUWhˆUYhˆU[hˆhhˆhNhNUNhˆh h‰hhŠuU)hˆU+hˆU-hˆU/hˆU1hˆU3hˆU5hˆU7hˆU9hˆU;hˆU=hˆU?hˆUAhˆUChˆUEhˆUGhˆUIhˆUKhˆUMhˆUOhˆUQhˆUShˆUUhˆUWhˆUYhˆU[hˆhhˆh}q(UNh NhNh(h8oqž}qŸh;UEOFq sbhNhK)hNuh}q¡(UNU h‚h NhNhNhNhK*hNuUNhˆh }q¢(UNU h‚U hˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆU hˆU"hU$hˆU&hˆU(hˆU*hˆU,hˆU.hˆU0hˆU2hˆU4hˆU6hˆU8hˆU:hˆUhˆU@hˆUBhˆUDhˆUFhˆUHhˆUJhˆULhˆhK(UPhˆURhˆUThˆUVhˆUXhˆUZhˆU\h“U hˆU hˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆUhˆU!hˆU#hˆU%hˆU'hœU)hˆU+hˆU-hˆU/hˆU1hˆU3hˆU5hˆU7hˆU9hˆU;hˆU=hˆU?hˆUAhˆUChˆUEhˆUGhˆUIhˆUKhˆUMhˆUOhˆUQhˆUShˆUUhˆUWhˆUYhˆU[hˆhhˆhNhh¡UNhˆh NhNuhNu}q£(UNU }q¤(UNU h¤U h¤hK+hNU h¤U#}q¥(UNU heh }q¦(UNh NhNhNh}q§(UNU }q¨(UNh NhNhhhNhKehNuh NhNhhh}q©(UNU h¨h NhNhNhNhKfhNuhK/hNuhKchNuhNhNhh§hK,h}qª(UNU heh h¦hNhNhh§hKbhhªuuhNhh§h }q«(UNU#h¥h NhNhNhh§hKahNuhNuU h¤hKhNU h¤U#h¥h}q¬(UNh NhNh(hoq­}q®h(hoq¯}q°(h"hwh$hwubsbhNhK.hNuhh§h }q±(UNU }q²(UNU h²U h¤hKdhNU h²U#h¥hNhh§h h«h(hoq³}q´h(hoqµ}q¶(h"Uindentation_actionq·h$h·ubsbuU h¤hK-hNU h²U#h¥hNhh§h Nhh³uhNu}q¸(UNU }q¹(UNh NhNh(hoqº}q»h(hoq¼}q½(h"h‡h$h‡ubsbhNhK1hNuU }q¾(UNU heU h¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾U h¾U"heU$h¾U&h¾U(h¾U*h¾U,h¾U.h¾U0h¾U2h¾U4h¾U6h¾U8h¾U:h¾Uh¾U@h¾UBh¾UDh¾UFh¾UHh¾UJh¾ULh¾hK0UPh¾URh¾UTh¾UVh¾UXh¾UZh¾U\heU h¾U h¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾U!h¾U#h¾U%h¾U'heU)h¾U+h¾U-h¾U/h¾U1h¾U3h¾U5h¾U7h¾U9h¾U;h¾U=h¾U?h¾UAh¾UCh¾UEh¾UGh¾UIh¾UKh¾UMh¾UOh¾UQh¾USh¾UUh¾UWh¾UYh¾U[h¾hh¾hNhNUNh¾h }q¿(UNU heU h¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾U h¾U"heU$h¾U&h¾U(h¾U*h¾U,h¾U.h¾U0h¾U2h¾U4h¾U6h¾U8h¾U:h¾Uh¾U@h¾UBh¾UDh¾UFh¾UHh¾UJh¾ULh¾hKgUPh¾URh¾UTh¾UVh¾UXh¾UZh¾U\heU h¾U h¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾U!h¾U#h¾U%h¾U'heU)h¾U+h¾U-h¾U/h¾U1h¾U3h¾U5h¾U7h¾U9h¾U;h¾U=h¾U?h¾UAh¾UCh¾UEh¾UGh¾UIh¾UKh¾UMh¾UOh¾UQh¾USh¾UUh¾UWh¾UYh¾U[h¾hh¾hNhNUNh¾h NhNuh(h8oqÀ}qÁh;hŒsbuUh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾U h¾U"}qÂ(UNh NhNh(h8oqÃ}qÄh;hŒsbhNhK2hNuU$h¾U&h¾U(h¾U*h¾U,h¾U.h¾U0h¾U2h¾U4h¾U6h¾U8h¾U:h¾Uh¾U@h¾UBh¾UDh¾UFh¾UHh¾UJh¾ULh¾hKUPh¾URh¾UTh¾UVh¾UXh¾UZh¾U\}qÅ(UNU }qÆ(UNh NhNh(h8oqÇ}qÈh;h—sbhNhKhhNuU hÆUhÆUhÆUhÆUhÆUhÆUhÆUhÆUhÆUhÆU hÆU"hÆU$hÆU&hÆU(hÆU*hÆU,hÆU.hÆU0}qÉ(UNUAhÆUChÆUBhÆUEhÆUDhÆUFhÆhKihNU9hÆU8hÆUdhÆUahÆUchÆUbhÆUehÆhNUfhÆhNU1}qÊ(UNhKhNhNhNU1hÆU0hÆU3hÆU2hÆh NU4hÆU7hÆU6hÆhhÇU5hÆuU0hÊU3hÊU2hÊh NU4hÊU7hÊU6hÊhhÇU5hÊuU2hÉU4hÉU6hÉU8}qË(UNUAhÆUChÆUBhÆUEhÆUDhÆUFhÆhKjhNU9hÆU8hÆUdhÆUahÆUchÆUbhÆUehÆhNUfhÆhNU1hÆU0hÆU3hÆU2hÆh NU4hÆU7hÆU6hÆhhÇU5hÆuU:hÆUhÆU@hÆUBhËUDhËUFhËUHhÆUJhÆULhÆhK4UPhÆURhÆUThÆUVhÆUXhÆUZhÆU\hÆU^hÆU`hÆUbhËUdhËUfhËU hÆU hÆUhÆUhÆUhÆUhÆUhÆUhÆUhÆUhÆUhÆU!hÆU#hÆU%hÆU'hÆU)hÆU+hÆU-hÆU/hÆU1hÉU3hÉU5hÉU7hÉU9hËU;hÆU=hÆU?hÆUAhËUChËUEhËUGhÆUIhÆUKhÆUMhÆUOhÆUQhÆUShÆUUhÆUWhÆUYhÆU[hÆhhÆU]hÆU_hÆUahËUchËUehËhNh}qÌ(UNU hÆh NhNhNhNhKkhNuUNhÆh NhNuU h¾U h¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾U!h¾U#h¾U%h¾U'}qÍ(UNh NhNh(hoqÎ}qÏh(hoqÐ}qÑ(h"h’h$h’ubsbhNhK3hNuU)h¾U+h¾U-h¾U/h¾U1h¾U3h¾U5h¾U7h¾U9h¾U;h¾U=h¾U?h¾UAh¾UCh¾UEh¾UGh¾UIh¾UKh¾UMh¾UOh¾UQh¾USh¾UUh¾UWh¾UYh¾U[h¾hh¾h}qÒ(UNh NhNh(h8oqÓ}qÔh;h sbhNhK6hNuh}qÕ(UNU h¹h NhNhNhNhK7hNuUNh¾h }qÖ(UNU h¹U h¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾U h¾U"hÂU$h¾U&h¾U(h¾U*h¾U,h¾U.h¾U0h¾U2h¾U4h¾U6h¾U8h¾U:h¾Uh¾U@h¾UBh¾UDh¾UFh¾UHh¾UJh¾ULh¾hK5UPh¾URh¾UTh¾UVh¾UXh¾UZh¾U\hÅU h¾U h¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾Uh¾U!h¾U#h¾U%h¾U'hÍU)h¾U+h¾U-h¾U/h¾U1h¾U3h¾U5h¾U7h¾U9h¾U;h¾U=h¾U?h¾UAh¾UCh¾UEh¾UGh¾UIh¾UKh¾UMh¾UOh¾UQh¾USh¾UUh¾UWh¾UYh¾U[h¾hh¾hNhhÕUNh¾h NhNuhNu}q×(UNU }qØ(UNh NhNh(h8oqÙ}qÚh;UNEWLINEqÛsbhNhK9hNuU }qÜ(UNU heU hÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜU hÜU"heU$hÜU&hÜU(hÜU*hÜU,hÜU.hÜU0hÜU2hÜU4hÜU6hÜU8hÜU:hÜUhÜU@hÜUBhÜUDhÜUFhÜUHhÜUJhÜULhÜhK8UPhÜURhÜUThÜUVhÜUXhÜUZhÜU\heU hÜU hÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜU!hÜU#hÜU%hÜU'heU)hÜU+hÜU-hÜU/hÜU1hÜU3hÜU5hÜU7hÜU9hÜU;hÜU=hÜU?hÜUAhÜUChÜUEhÜUGhÜUIhÜUKhÜUMhÜUOhÜUQhÜUShÜUUhÜUWhÜUYhÜU[hÜhhÜhNhNUNhÜh }qÝ(UNU heU hÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜU hÜU"heU$hÜU&hÜU(hÜU*hÜU,hÜU.hÜU0hÜU2hÜU4hÜU6hÜU8hÜU:hÜUhÜU@hÜUBhÜUDhÜUFhÜUHhÜUJhÜULhÜhKlUPhÜURhÜUThÜUVhÜUXhÜUZhÜU\heU hÜU hÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜU!hÜU#hÜU%hÜU'heU)hÜU+hÜU-hÜU/hÜU1hÜU3hÜU5hÜU7hÜU9hÜU;hÜU=hÜU?hÜUAhÜUChÜUEhÜUGhÜUIhÜUKhÜUMhÜUOhÜUQhÜUShÜUUhÜUWhÜUYhÜU[hÜhhÜhNhNUNhÜh NhNuh(h8oqÞ}qßh;hŒsbuUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜU hÜU"}qà(UNU"}qá(UNU"}qâ(UNh NhNh(hoqã}qäh(hoqå}qæ(h"h’h$h’ubsbhNhK€hNuh NhNhNhNhKmhNuh NhNh(h8oqç}qèh;hŒsbhNhK:hNuU$hÜU&hÜU(hÜU*hÜU,hÜU.hÜU0hÜU2hÜU4hÜU6hÜU8hÜU:hÜUhÜU@hÜUBhÜUDhÜUFhÜUHhÜUJhÜULhÜhKUPhÜURhÜUThÜUVhÜUXhÜUZhÜU\}qé(UNU }qê(UNh NhNh(h8oqë}qìh;h—sbhNhKnhNuU hêUhêUhêUhêUhêUhêUhêUhêUhêUhêU hêU"hêU$hêU&hêU(hêU*hêU,hêU.hêU0}qí(UNUAhêUChêUBhêUEhêUDhêUFhêhKohNU9hêU8hêUdhêUahêUchêUbhêUehêhNUfhêhNU1}qî(UNhKhNhNhNU1hêU0hêU3hêU2hêh NU4hêU7hêU6hêhhëU5hêuU0hîU3hîU2hîh NU4hîU7hîU6hîhhëU5hîuU2híU4híU6híU8}qï(UNUAhêUChêUBhêUEhêUDhêUFhêhKphNU9hêU8hêUdhêUahêUchêUbhêUehêhNUfhêhNU1hêU0hêU3hêU2hêh NU4hêU7hêU6hêhhëU5hêuU:hêUhêU@hêUBhïUDhïUFhïUHhêUJhêULhêhKhNuh}qõ(UNU hØh NhNhNhNhK?hNuUNhÜh }qö(UNU hØU hÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜU hÜU"hàU$hÜU&hÜU(hÜU*hÜU,hÜU.hÜU0hÜU2hÜU4hÜU6hÜU8hÜU:hÜUhÜU@hÜUBhÜUDhÜUFhÜUHhÜUJhÜULhÜhK=UPhÜURhÜUThÜUVhÜUXhÜUZhÜU\héU hÜU hÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜUhÜU!hÜU#hÜU%hÜU'hñU)hÜU+hÜU-hÜU/hÜU1hÜU3hÜU5hÜU7hÜU9hÜU;hÜU=hÜU?hÜUAhÜUChÜUEhÜUGhÜUIhÜUKhÜUMhÜUOhÜUQhÜUShÜUUhÜUWhÜUYhÜU[hÜhhÜhNhhõUNhÜh NhNuhNu}q÷(UNU }qø(UNh NhNh(h8oqù}qúh;hÛsbhNhKAhNuU }qû(UNU heU hûUhûUhûUhûUhûUhûUhûUhûUhûUhûU hûU"heU$hûU&hûU(hûU*hûU,hûU.hûU0hûU2hûU4hûU6hûU8hûU:hûUhûU@hûUBhûUDhûUFhûUHhûUJhûULhûhK@UPhûURhûUThûUVhûUXhûUZhûU\heU hûU hûUhûUhûUhûUhûUhûUhûUhûUhûUhûU!hûU#hûU%hûU'heU)hûU+hûU-hûU/hûU1hûU3hûU5hûU7hûU9hûU;hûU=hûU?hûUAhûUChûUEhûUGhûUIhûUKhûUMhûUOhûUQhûUShûUUhûUWhûUYhûU[hûhhûhNhNUNhûh }qü(UNU heU hûUhûUhûUhûUhûUhûUhûUhûUhûUhûU hûU"heU$hûU&hûU(hûU*hûU,hûU.hûU0hûU2hûU4hûU6hûU8hûU:hûUhûU@hûUBhûUDhûUFhûUHhûUJhûULhûhKrUPhûURhûUThûUVhûUXhûUZhûU\heU hûU hûUhûUhûUhûUhûUhûUhûUhûUhûUhûU!hûU#hûU%hûU'heU)hûU+hûU-hûU/hûU1hûU3hûU5hûU7hûU9hûU;hûU=hûU?hûUAhûUChûUEhûUGhûUIhûUKhûUMhûUOhûUQhûUShûUUhûUWhûUYhûU[hûhhûhNhNUNhûh NhNuh(h8oqý}qþh;hŒsbuUhûUhûUhûUhûUhûUhûUhûUhûUhûU hûU"}qÿ(UNh NhNh(h8or}rh;hŒsbhNhKBhNuU$hûU&hûU(hûU*hûU,hûU.hûU0hûU2hûU4hûU6hûU8hûU:hûUhûU@hûUBhûUDhûUFhûUHhûUJhûULhûhKUPhûURhûUThûUVhûUXhûUZhûU\}r(UNU }r(UNh NhNh(h8or}rh;h—sbhNhKthNuU jUjUjUjUjUjUjUjUjUjU jU"jU$jU&jU(jU*jU,jU.jU0}r(UNUAjUCjUBjUEjUDjUFjhKuhNU9jU8jUdjUajUcjUbjUejhNUfjhNU1}r(UNhKƒhNhNhNU1jU0jU3jU2jh NU4jU7jU6jhjU5juU0jU3jU2jh NU4jU7jU6jhjU5juU2jU4jU6jU8}r(UNUAjUCjUBjUEjUDjUFjhKvhNU9jU8jUdjUajUcjUbjUejhNUfjhNU1jU0jU3jU2jh NU4jU7jU6jhjU5juU:jUjU@jUBjUDjUFjUHjUJjULjhKDUPjURjUTjUVjUXjUZjU\jU^jU`jUbjUdjUfjU jU jUjUjUjUjUjUjUjUjUjU!jU#jU%jU'jU)jU+jU-jU/jU1jU3jU5jU7jU9jU;jU=jU?jUAjUCjUEjUGjUIjUKjUMjUOjUQjUSjUUjUWjUYjU[jhjU]jU_jUajUcjUejhNh}r (UNU jh NhNhNhNhKwhNuUNjh NhNuU hûU hûUhûUhûUhûUhûUhûUhûUhûUhûUhûU!hûU#hûU%hûU'}r (UNh NhNU'}r (UNh NhNU'}r (UNh NhNh(hor }rh(hor}r(h"h’h$h’ubsbhNhK‚hNuhNhNhKshNuhjhNhKChNuU)hûU+hûU-hûU/hûU1hûU3hûU5hûU7hûU9hûU;hûU=hûU?hûUAhûUChûUEhûUGhûUIhûUKhûUMhûUOhûUQhûUShûUUhûUWhûUYhûU[hûhhûh}r(UNh NhNh(h8or}rh;h sbhNhKFhNuh}r(UNU høh NhNhNhNhKGhNuUNhûh }r(UNU høU hûUhûUhûUhûUhûUhûUhûUhûUhûUhûU hûU"hÿU$hûU&hûU(hûU*hûU,hûU.hûU0hûU2hûU4hûU6hûU8hûU:hûUhûU@hûUBhûUDhûUFhûUHhûUJhûULhûhKEUPhûURhûUThûUVhûUXhûUZhûU\jU hûU hûUhûUhûUhûUhûUhûUhûUhûUhûUhûU!hûU#hûU%hûU'j U)hûU+hûU-hûU/hûU1hûU3hûU5hûU7hûU9hûU;hûU=hûU?hûUAhûUChûUEhûUGhûUIhûUKhûUMhûUOhûUQhûUShûUUhûUWhûUYhûU[hûhhûhNhjUNhûh NhNuhNuh hchhdhgh%h[h+hhh1hnh*hoh3hphAhEhQhqhShUhZh^hahbh€hrhxhˆh‚hhœh“h¢hh¡h¤h¥h±h¬h§h¾h¹hÂhÍhÅhÖhÒhÕhÜhØhàhñhéhöhòhõhûhøhÿj jjjjh hhfheh\h2h4hJhBh7hFhOhRhThVh]h_h`hyhh‰h”h˜hšh›h«hªh¦h²h¨h©h¿hÆhÉhËhÌhÝháhêhíhïhðhüj jjjj hh5hKhDhChPh™hÊhâhîj jh@h6eU next_numberrK†Uinitial_statesr}r(Uh U DQ_STRINGrhUINDENTrh£U SQ_STRINGrh¸U TDQ_STRINGrh×U TSQ_STRINGrh÷uubsb.Pyrex-0.9.8.5/Pyrex/Compiler/Lexicon.py0000644001243100001200000001052511011562155017720 0ustar00gregadmin00000000000000# # Pyrex Scanner - Lexical Definitions # # Changing anything in this file will cause Lexicon.pickle # to be rebuilt next time pyrexc is run. # string_prefixes = "cCrR" def make_lexicon(): from Pyrex.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") 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("0x") + Rep1(hexdigit)) longconst = intconst + Str("L") fltconst = (decimal_fract + Opt(exponent)) | (decimal + exponent) imagconst = (intconst | fltconst) + Any("jJ") # sq_string = ( # Str("'") + # Rep(AnyBut("\\\n'") | (Str("\\") + AnyChar)) + # Str("'") # ) # # dq_string = ( # Str('"') + # Rep(AnyBut('\\\n"') | (Str("\\") + AnyChar)) + # Str('"') # ) # # non_sq = AnyBut("'") | (Str('\\') + AnyChar) # tsq_string = ( # Str("'''") # + Rep(non_sq | (Str("'") + non_sq) | (Str("''") + non_sq)) # + Str("'''") # ) # # non_dq = AnyBut('"') | (Str('\\') + AnyChar) # tdq_string = ( # Str('"""') # + Rep(non_dq | (Str('"') + non_dq) | (Str('""') + non_dq)) # + Str('"""') # ) # # stringlit = Opt(Any(string_prefixes)) + (sq_string | dq_string | tsq_string| tdq_string) beginstring = Opt(Any(string_prefixes)) + (Str("'") | Str('"') | Str("'''") | Str('"""')) two_oct = octdigit + octdigit three_oct = octdigit + octdigit + octdigit two_hex = hexdigit + hexdigit escapeseq = Str("\\") + (two_oct | three_oct | two_hex | AnyChar) bra = Any("([{") ket = Any(")]}") punct = Any(":,;+-*/|&<>=.%`~^?") diphthong = Str("==", "<>", "!=", "<=", ">=", "<<", ">>", "**", "+=", "-=", "*=", "/=", "%=", "**=", "<<=", ">>=", "&=", "^=", "|=") spaces = Rep1(Any(" \t\f")) comment = Str("#") + Rep(AnyBut("\n")) escaped_newline = Str("\\\n") lineterm = Eol + Opt(Str("\n")) return Lexicon([ (name, 'IDENT'), (intconst, 'INT'), (longconst, 'LONG'), (fltconst, 'FLOAT'), (imagconst, 'IMAG'), (punct | diphthong, TEXT), (bra, Method('open_bracket_action')), (ket, Method('close_bracket_action')), (lineterm, Method('newline_action')), #(stringlit, 'STRING'), (beginstring, Method('begin_string_action')), (comment, IGNORE), (spaces, IGNORE), (escaped_newline, IGNORE), State('INDENT', [ (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 ) Pyrex-0.9.8.5/Pyrex/Compiler/Main.py0000644001243100001200000005220311055155263017210 0ustar00gregadmin00000000000000# # Pyrex Top Level # import os, re, sys if sys.version_info[:2] < (2, 3): print >>sys.stderr, "Sorry, Pyrex requires Python 2.3 or later" sys.exit(1) import os from time import time import Builtin import Code import Errors import Parsing import Version from Errors import PyrexError, CompileError, error from Scanning import PyrexScanner from Symtab import BuiltinScope, DefinitionScope, ImplementationScope from Pyrex.Utils import set, replace_suffix, modification_time, \ file_newer_than, castrate_file verbose = 0 debug_timestamps = 0 module_name_pattern = re.compile( r"[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$") class Context: # This class encapsulates the context needed for compiling # one or more Pyrex implementation files along with their # associated and imported declaration files. It holds # the root of the module import namespace and the list # of directories to search for include files. # # modules {string : DefinitionScope} # include_directories [string] def __init__(self, include_directories): self.modules = {"__builtin__" : Builtin.builtin_scope} self.include_directories = include_directories def find_module(self, module_name, relative_to = None, pos = None, need_pxd = 1): # 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 =", module_name, \ "relative_to =", relative_to, "pos =", pos, "need_pxd =", need_pxd scope = None pxd_pathname = None 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: error(pos, "Cannot find .pxd file for module '%s'" % module_name) if pxd_pathname: try: if debug_find_module: print "Context.find_module: Parsing", pxd_pathname pxd_tree = self.parse(pxd_pathname, scope, pxd = 1) pxd_tree.analyse_declarations(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. return self.search_package_directories(qualified_name, ".pxd", pos) 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_package_directories(qualified_name, ".pyx", pos) def search_package_directories(self, qualified_name, suffix, pos): dotted_filename = qualified_name + suffix if pos: here = os.path.dirname(pos[0]) path = os.path.join(here, dotted_filename) if os.path.exists(path): return path dirs = self.include_directories if pos: here = self.find_root_package_dir(pos[0]) dirs = [here] + dirs names = qualified_name.split(".") package_names = names[:-1] module_name = names[-1] filename = module_name + suffix for root in dirs: path = os.path.join(root, dotted_filename) if os.path.exists(path): return path dir = self.descend_to_package_dir(root, package_names) if dir: path = os.path.join(dir, filename) if os.path.exists(path): return path path = os.path.join(dir, module_name, "__init__" + suffix) if os.path.exists(path): return path def find_root_package_dir(self, file_path): # Given the full pathname of a source file, find the directory # containing the top-level package that it ultimately belongs to. dir = os.path.dirname(file_path) while 1: if not self.is_package_dir(dir): return dir parent = os.path.dirname(dir) if parent == dir: return dir dir = parent def descend_to_package_dir(self, root_dir, package_names): # Starting from the given root directory, look for a nested # succession of package directories. Returns the full pathname # of the innermost one, or None. dir = root_dir for name in package_names: dir = os.path.join(dir, name) for filename in ("__init__.py", "__init__.pyx"): path = os.path.join(dir, filename) if os.path.exists(path): return dir def is_package_dir(self, dir_path): # Return true if the given directory is a package directory. for filename in ("__init__.py", "__init__.pyx"): path = os.path.join(dir_path, filename) if os.path.exists(path): return 1 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) if not path: error(pos, "'%s' not found" % filename) return path def search_include_directories(self, filename, pos): # 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. dirs = self.include_directories if pos: here_dir = os.path.dirname(pos[0]) dirs = [here_dir] + dirs for dir in dirs: path = os.path.join(dir, filename) if os.path.exists(path): return path return None 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 = DefinitionScope(name, parent_module = None, context = self) self.modules[name] = scope return scope def parse(self, source_filename, scope, pxd): # Parse the given source file and return a parse tree. f = open(source_filename, "rU") s = PyrexScanner(f, source_filename, scope = scope, context = self) try: tree = Parsing.p_module(s, pxd) finally: f.close() if Errors.num_errors > 0: raise CompileError return tree def extract_module_name(self, path): # 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 "." not in module_name: if module_name == "__init__": dir, module_name = os.path.split(dir) names = [module_name] while self.is_package_dir(dir): parent, package_name = os.path.split(dir) if parent == dir: break names.insert(0, package_name) dir = parent module_name = ".".join(names) if not module_name_pattern.match(module_name): raise CompileError((path, 0, 0), "'%s' is not a valid module name" % module_name) return module_name def dep_file_out_of_date(self, source_path): dep_path = replace_suffix(source_path, ".dep") if not os.path.exists(dep_path): return 1 dep_time = modification_time(dep_path) return file_newer_than(source_path, dep_time) def c_file_out_of_date(self, source_path): if debug_timestamps: print "Checking whether", source_path, "is out of date" c_path = replace_suffix(source_path, ".c") if not os.path.exists(c_path): if debug_timestamps: print "...yes, c file doesn't exist" return 1 c_time = modification_time(c_path) if file_newer_than(source_path, c_time): if debug_timestamps: print "...yes, newer than c file" return 1 pos = [source_path] module_name = self.extract_module_name(source_path) pxd_path = self.find_pxd_file(module_name, pos) if pxd_path and file_newer_than(pxd_path, c_time): if debug_timestamps: print "...yes, pxd file newer than c file" return 1 dep_path = replace_suffix(source_path, ".dep") if not os.path.exists(dep_path): if debug_timestamps: print "...yes, dep file does not exist" 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 file_newer_than(dep_path, c_time): if debug_timestamps: print "...yes,", dep_path, "newer than c file" return 1 if debug_timestamps: print "...no" def find_cimported_module_names(self, source_path): for kind, name in self.read_dependency_file(source_path): if kind == "cimport": yield name def read_dependency_file(self, source_path): dep_path = replace_suffix(source_path, ".dep") if os.path.exists(dep_path): f = open(dep_path, "rU") for line in f.readlines(): chunks = line.strip().split(" ", 1) if len(chunks) == 2: yield chunks f.close() def compile(self, source, options = None): # Compile a Pyrex implementation file in this context # and return a CompilationResult. if not options: options = default_options result = CompilationResult() cwd = os.getcwd() source = os.path.join(cwd, source) if options.use_listing_file: result.listing_file = replace_suffix(source, ".lis") Errors.open_listing_file(result.listing_file, echo_to_stderr = options.errors_to_stderr) else: Errors.open_listing_file(None) if options.output_file: result.c_file = os.path.join(cwd, options.output_file) else: if options.cplus: c_suffix = ".cpp" else: c_suffix = ".c" result.c_file = replace_suffix(source, c_suffix) module_name = self.extract_module_name(source) initial_pos = (source, 1, 0) def_scope = self.find_module(module_name, pos = initial_pos, need_pxd = 0) imp_scope = ImplementationScope(def_scope) errors_occurred = False try: tree = self.parse(source, imp_scope, pxd = 0) tree.process_implementation(imp_scope, options, result) except CompileError: errors_occurred = True Errors.close_listing_file() result.num_errors = Errors.num_errors if result.num_errors > 0: errors_occurred = True if errors_occurred and result.c_file: try: st = os.stat(source) castrate_file(result.c_file, st) except EnvironmentError: pass result.c_file = None if result.c_file and not options.c_only and c_compile: result.object_file = c_compile(result.c_file, verbose_flag = options.show_version, cplus = options.cplus) if not options.obj_only and c_link: result.extension_file = c_link(result.object_file, extra_objects = options.objects, verbose_flag = options.show_version, cplus = options.cplus) return result #------------------------------------------------------------------------ # # Main Python entry points # #------------------------------------------------------------------------ class CompilationOptions: """ Options to the Pyrex compiler: show_version boolean Display version number use_listing_file boolean Generate a .lis file errors_to_stderr boolean Echo errors to stderr when using .lis include_path [string] Directories to search for include files output_file string Name of generated .c file generate_pxi boolean Generate .pxi file for public declarations recursive boolean Recursively find and compile dependencies timestamps boolean Only compile changed source files. If None, defaults to true when recursive is true. verbose boolean Always print source names being compiled quiet boolean Don't print source names in recursive mode Following options are experimental and only used on MacOSX: c_only boolean Stop after generating C file (default) obj_only boolean Stop after compiling to .o file objects [string] Extra .o files to link with cplus boolean Compile as c++ code """ def __init__(self, defaults = None, c_compile = 0, c_link = 0, **kw): self.include_path = [] self.objects = [] if defaults: if isinstance(defaults, CompilationOptions): defaults = defaults.__dict__ else: defaults = default_options self.__dict__.update(defaults) self.__dict__.update(kw) if c_compile: self.c_only = 0 if c_link: self.obj_only = 0 class CompilationResult: """ Results from the Pyrex compiler: c_file string or None The generated C source file h_file string or None The generated C header file i_file string or None The generated .pxi file api_file string or None The generated C API .h file listing_file string or None File of error messages object_file string or None Result of compiling the C file extension_file string or None Result of linking the object file num_errors integer Number of compilation errors """ def __init__(self): self.c_file = None self.h_file = None self.i_file = None self.api_file = None self.listing_file = None self.object_file = None self.extension_file = None class CompilationResultSet(dict): """ Results from compiling multiple Pyrex source files. A mapping from source file paths to CompilationResult instances. Also has the following attributes: num_errors integer Total number of compilation errors """ num_errors = 0 def add(self, source, result): self[source] = result self.num_errors += result.num_errors def compile_single(source, options): """ compile_single(source, options) Compile the given Pyrex implementation file and return a CompilationResult. Always compiles a single file; does not perform timestamp checking or recursion. """ context = Context(options.include_path) return context.compile(source, options) def compile_multiple(sources, options): """ compile_multiple(sources, options) Compiles the given sequence of Pyrex implementation files and returns a CompilationResultSet. Performs timestamp checking and/or recursion if these are specified in the options. """ sources = [os.path.abspath(source) for source in sources] processed = set() results = CompilationResultSet() context = Context(options.include_path) recursive = options.recursive timestamps = options.timestamps if timestamps is None: timestamps = recursive verbose = options.verbose or ((recursive or timestamps) and not options.quiet) for source in sources: if source not in processed: if not timestamps or context.c_file_out_of_date(source): if verbose: print >>sys.stderr, "Compiling", source result = context.compile(source, options) results.add(source, result) processed.add(source) if recursive: for module_name in context.find_cimported_module_names(source): path = context.find_pyx_file(module_name, [source]) if path: sources.append(path) else: print >>sys.stderr, \ "Cannot find .pyx file for cimported module '%s'" % module_name return results def compile(source, options = None, c_compile = 0, c_link = 0, **kwds): """ compile(source [, options], [,