DEB pyrex: Added to repository.

Signed-off-by: Slávek Banko <slavek.banko@axis.cz>
pull/3/head
Slávek Banko 3 years ago
parent bad411472a
commit 0f27805eed
Signed by: SlavekB
GPG Key ID: 608F5293A04BE668

@ -0,0 +1,8 @@
588a14055d1691eb3d0a14d69be108c6110fcee7 0.9.8
66ff407aae9ec4fba986bfdbc6686f1eb7016dce 0.9.8.2
37554acbb702072bdefef51980be33c551e38895 0.9.8.3
ac76d2c45aa1f7055b6101064eac30cfb648a350 0.9.8.4
ac4da2723c96ef0ffc792d9a763638a62e103426 0.9.8.5
f89737e75fc5ef7c007abb97dd0f2694c7ae071b 0.9.8.6
67efcff42bd53148cfdbb0767c64e1c7a852f82f 0.9.9
f11df44eb1bfa2f7ed609c7affc89461e8aa91f5 0.9.9

File diff suppressed because it is too large Load Diff

@ -0,0 +1,24 @@
Release 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
* make push

@ -0,0 +1,15 @@
all:
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

@ -0,0 +1,21 @@
PYHOME = $(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

@ -0,0 +1,14 @@
from 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}
)

@ -0,0 +1,10 @@
all:
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

@ -0,0 +1,19 @@
PYHOME = $(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.*

@ -0,0 +1 @@
This 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.

@ -0,0 +1,11 @@
from 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}
)

@ -0,0 +1,13 @@
#
# 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, <void*>f)
cdef void callback(char *name, void *f):
(<object>f)(name)

@ -0,0 +1,21 @@
/*
* 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;
}
}

@ -0,0 +1 @@
typedef void (*cheesefunc)(char *name, void *user_data); void find_cheeses(cheesefunc user_func, void *user_data);

@ -0,0 +1,7 @@
import cheese
def report_cheese(name):
print "Found cheese:", name
cheese.find(report_cheese)

@ -0,0 +1,35 @@
# 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

@ -0,0 +1 @@
# 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

@ -0,0 +1,30 @@
PYVERSION = 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

@ -0,0 +1 @@
This 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 <Duncan.Booth@SuttonCourtenay.org.uk>.

@ -0,0 +1,5 @@
cdef public void spam():
praise()
def praise():
print "Spam, glorious spam!"

@ -0,0 +1,9 @@
#include "Python.h"
#include "embedded.h"
int main(int argc, char *argv) {
Py_Initialize();
initembedded();
spam();
Py_Finalize();
}

@ -0,0 +1,39 @@
#
# 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 = <float *>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

@ -0,0 +1,18 @@
def primes(int kmax):
cdef int n, k, i
cdef int p[1000]
result = []
if kmax > 1000:
kmax = 1000
k = 0
n = 2
while k < kmax:
i = 0
while i < k and n % p[i] <> 0:
i = i + 1
if i == k:
p[k] = n
k = k + 1
result.append(n)
n = n + 1
return result

@ -0,0 +1,13 @@
def 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

@ -0,0 +1,5 @@
import 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)

@ -0,0 +1,7 @@
import sys
from primes import primes
if len(sys.argv) >= 2:
n = int(sys.argv[1])
else:
n = 1000
print primes(n)

@ -0,0 +1,8 @@
from spam import Spam
s = Spam()
print "Created:", s
s.set_amount(42)
print "Amount =", s.get_amount()
s.describe()
s = None

@ -0,0 +1,22 @@
#
# Example of an extension type.
#
cdef class Spam:
cdef int amount
def __cinit__(self):
self.amount = 0
def __dealloc__(self):
print self.amount, "tons of spam is history."
def get_amount(self):
return self.amount
def set_amount(self, new_amount):
self.amount = new_amount
def describe(self):
print self.amount, "tons of spam!"

@ -0,0 +1,149 @@
<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.51 (Macintosh; I; PPC) [Netscape]">
<title>About Pyrex</title></head>
<body>
<center>
<h1>
<hr width="100%">Pyrex</h1></center>
<center><i><font size="+1">A language for writing Python extension modules</font></i>
<hr width="100%"></center>
<h2>
What is Pyrex all about?</h2>
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.
<p>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?
</p><p>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.
</p><p>Various tools have been developed to ease some of the burdens of producing
extension code, of which perhaps <a href="http://www.swig.org">SWIG</a>
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.
</p><p>What's more, SWIG gives you no help at all if you want to create a new
built-in Python <i>type. </i>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.
</p><p>Another notable attempt at making it easier to extend Python is <a href="http://pyinline.sourceforge.net/">PyInline</a>
, 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,&nbsp; it doesn't address the creation
of new Python types.
</p><p>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
<i>anything</i> about the Python/C API. That's right -- <i>nothing at all</i>!
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
<i>built-in</i> Python types just as easily as you can define new classes
in Python.
</p><p>Sound too good to be true? Read on and find out how it's done.
</p><h2>
The Basics of Pyrex</h2>
The fundamental nature of Pyrex can be summed up as follows: <b>Pyrex is
Python with C data types</b>.
<p><i>Pyrex is Python:</i> 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).
</p><p><i>...with C data types.</i> 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.
</p><p>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.
</p><blockquote><b><tt><font size="+1">primes.pyx</font></tt></b></blockquote>
<blockquote>
<pre>&nbsp;1&nbsp; def primes(int kmax):<br>&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cdef int n, k, i<br>&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cdef int p[1000]<br>&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = []<br>&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if kmax &gt; 1000:<br>&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kmax = 1000<br>&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; k = 0<br>&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = 2<br>&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while k &lt; kmax:<br>10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = 0<br>11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while i &lt; k and n % p[i] &lt;&gt; 0:<br>12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = i + 1<br>13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if i == k:<br>14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p[k] = n<br>15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; k = k + 1<br>16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result.append(n)<br>17&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = n + 1<br>18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result</pre>
</blockquote>
You'll see that it starts out just like a normal Python function definition,
except that the parameter <b>kmax</b> is declared to be of type <b>int</b>
. This means that the object passed will be converted to a C integer (or
a TypeError will be raised if it can't be).
<p>Lines 2 and 3 use the <b>cdef</b> 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 <b>result</b> hasn't been given a type, it is assumed to hold
a Python object.
</p><p>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.
</p><p>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 <b>n</b> is automatically converted
to a Python object before being passed to the <b>append</b> method. Finally,
at line 18, a normal Python <b>return</b> statement returns the result
list.
</p><p>Compiling primes.pyx with the Pyrex compiler produces an extension module
which we can try out in the interactive interpreter as follows:
</p><blockquote>
<pre>&gt;&gt;&gt; import primes<br>&gt;&gt;&gt; primes.primes(10)<br>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]<br>&gt;&gt;&gt;</pre>
</blockquote>
See, it works! And if you're curious about how much work Pyrex has saved
you, take a look at the <a href="primes.c">C code generated for this module</a>
.
<h2>
Language Details</h2>
For more about the Pyrex language, see the <a href="LanguageOverview.html">Language
Overview</a> .
<h2>
Future Plans</h2>
Pyrex is not finished. Substantial tasks remaining include:
<ul>
<li>
Support for certain Python language features which are planned but not
yet implemented. See the <a href="Manual/Limitations.html">Limitations</a>
section of the <a href="LanguageOverview.html">Language Overview</a> for a current
list.</li>
</ul>
<ul>
<li>
C++ support. This could be a very big can of worms - careful thought required
before going there.</li>
</ul>
<ul>
<li>
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.</li>
</ul>
</body></html>

@ -0,0 +1,75 @@
<!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.51 (Macintosh; I; PPC) [Netscape]"><title>FAQ.html</title></head>
<body>
<center> <h1> <hr width="100%">Pyrex FAQ
<hr width="100%"></h1>
</center>
<h2> Contents</h2>
<ul>
<li> <b><a href="#CallCAPI">How do I call Python/C API routines?</a></b></li>
<li> <b><a href="#NullBytes">How do I convert a C string containing null
bytes to a Python string?</a></b></li>
<li> <b><a href="#NumericAccess">How do I access the data inside a Numeric
array object?</a></b></li>
<li><b><a href="#Rhubarb">Pyrex says my extension type object has no attribute
'rhubarb', but I know it does. What gives?</a></b></li><li><a style="font-weight: bold;" href="#Quack">Python says my extension type has no method called 'quack', but I know it does. What gives?</a><br>
</li>
</ul>
<hr width="100%"> <h2> <a name="CallCAPI"></a>How do I call Python/C API routines?</h2>
Declare them as C functions inside a <tt>cdef extern from</tt> block.
Use the type name <tt>object</tt> for any parameters and return types which
are Python object references. Don't use the word <tt>const</tt> anywhere.
Here is an example which defines and uses the <tt>PyString_FromStringAndSize</tt> routine:
<blockquote><tt>cdef extern from "Python.h":</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; object PyString_FromStringAndSize(char *, int)</tt> <p><tt>cdef char buf[42]</tt> <br>
<tt>my_string = PyString_FromStringAndSize(buf, 42)</tt></p>
</blockquote>
<h2> <a name="NullBytes"></a>How do I convert a C string containing null
bytes to a Python string?</h2>
Put in a declaration for the <tt>PyString_FromStringAndSize</tt> API routine
and use that<tt>.</tt> See <a href="#CallCAPI">How do I call Python/C API
routines?</a> <h2> <a name="NumericAccess"></a>How do I access the data inside a Numeric
array object?</h2>
Use a <tt>cdef extern from</tt> 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:
<blockquote><tt>cdef extern from "Numeric/arrayobject.h":</tt> <p><tt>&nbsp;&nbsp;&nbsp; struct PyArray_Descr:</tt> <br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int type_num, elsize</tt> <br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char type</tt> </p>
<p><tt>&nbsp;&nbsp;&nbsp; ctypedef class Numeric.ArrayType [object PyArrayObject]</tt><tt>:</tt> <br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cdef char *data</tt> <br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cdef int nd</tt> <br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cdef int *dimensions,
*strides</tt> <br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cdef object base</tt>
<br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cdef PyArray_Descr *descr</tt> <br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cdef int flags<br>
</tt></p>
</blockquote>
<p>For more information about external extension types, see the <a href="extension_types.html#ExternalExtTypes">"External Extension Types"</a>
section of the <a href="extension_types.html">"Extension Types"</a> documentation
page.<br>
<tt> </tt> </p>
<h2><a name="Rhubarb"></a>Pyrex says my extension type object has no attribute
'rhubarb', but I know it does. What gives?</h2>
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,<br>
<blockquote><tt>cdef class Vegetables:</tt><br>
<tt>&nbsp; &nbsp; cdef int rhubarb</tt><br>
<br>
<tt>...</tt><br>
<tt>cdef Vegetables veg</tt><br>
<tt>veg.rhubarb = 42</tt><br>
</blockquote>
Also see the <a href="Manual/extension_types.html#ExtTypeAttrs">"Attributes"</a>
section of the <a href="Manual/extension_types.html">"Extension
Types"</a> documentation page.<br>
<h2><a name="Quack"></a>Python says my extension type has no method called 'quack', but I know it does. What gives?</h2>
You may have declared the method using <span style="font-family: monospace;">cdef</span> instead of <span style="font-family: monospace;">def</span>. Only functions and methods declared with <span style="font-family: monospace;">def</span> are callable from Python code.<br><br>
---
</body></html>

@ -0,0 +1,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Pyrex Language Overview</title></head>
<body>
<h1>
<hr width="100%">Overview of the Pyrex Language&nbsp;
<hr width="100%"></h1>
This is a combined tutorial and reference manual that describes the extensions to the Python language
made by Pyrex.<h2> Contents</h2>
<ul><li><a href="Manual/source_files.html">Source Files and Compilation</a> <span style="color: rgb(0, 153, 0);">(Section added in 0.9.5)</span><br>
</li><li><a href="Manual/basics.html">Language Basics</a></li><li> <a href="Manual/external.html">Interfacing with External C Code</a></li><li> <a href="Manual/extension_types.html">Extension Types</a></li><li><a href="Manual/special_methods.html">Special Methods of Extension Types</a></li><li> <a href="Manual/sharing.html">Sharing Declarations Between Pyrex Modules</a></li><li><a href="Manual/using_with_c++.html">Using Pyrex with C++</a></li><li> <a href="Manual/Limitations.html">Limitations</a></li></ul>---</body></html>

@ -0,0 +1,53 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Limitations</title></head>
<body><h1><hr width="100%">
<a name="Limitations"></a>Limitations <hr width="100%"></h1><h2> <a name="Unsupported"></a>Unsupported
Python features</h2>
Pyrex is not quite a full superset of Python. The following
restrictions apply: <blockquote> <li> Function
definitions (whether using <b>def</b> or <b>cdef</b>)
cannot be nested within other function definitions.<br> </li>
&nbsp; <li> Class definitions can only appear at the top
level of a module, not inside a function.<br> </li>
&nbsp; <li> The<tt> import *</tt> form of import
is not allowed anywhere (other forms of the import statement are fine,
though).<br> </li> &nbsp; <li> Generators
cannot be defined in Pyrex.<br> <br> </li> <li>
The <tt>globals()</tt> and <tt>locals()</tt>
functions cannot be used.</li> </blockquote> The above
restrictions will most likely remain, since removing them would be
difficult and they're not really needed for Pyrex's intended
applications. <p>There are also some temporary limitations,
which may eventually be lifted, including: </p> <blockquote>
<li> Class and function definitions cannot be placed inside
control structures.<br> </li> &nbsp; <li> List comprehensions are not yet
supported.<br> </li> &nbsp; <li> There is no
support for Unicode.<br> </li> &nbsp; <li>
Special methods of extension types cannot have functioning
docstrings.<br> <br> </li> <li> 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.</li></blockquote><hr style="width: 100%; height: 2px;"><h2><a name="SemanticDifferences"></a>Semantic
differences between Python and Pyrex</h2> <h3> Behaviour
of class scopes</h3> 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 method<sup><font size="-2"><a href="#Footnote1">1</a></font></sup>.
A consequence of this is that the
usual idiom for using the classmethod and staticmethod functions, e.g. <blockquote>
<pre>class Spam:</pre> <pre>&nbsp; def method(cls):<br>&nbsp;&nbsp;&nbsp; ...</pre><pre>&nbsp; method = classmethod(method)</pre>
</blockquote>
will not work in Pyrex. This can be worked around by defining the
function <i>outside</i> the class, and then assigning the
result of classmethod or staticmethod inside the class, i.e. <blockquote>
<pre>def Spam_method(cls):<br>&nbsp; ...</pre> <pre>class Spam:</pre><pre>&nbsp; method = classmethod(Spam_method)</pre>
</blockquote> <hr width="100%"><span style="font-weight: bold;">Footnotes</span><br><hr style="width: 100%; height: 2px;"><a name="Footnote1"></a>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.<br><br>--- </body></html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,294 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Interfacing with External C Code</title></head>
<body><h1><hr style="width: 100%; height: 2px;"><a name="InterfacingWithExternal"></a>Interfacing with
External C Code <hr width="100%"></h1><ul><li>
<a href="#ExternDecls">External declarations</a></li><ul><li>
<a href="#ReferencingHeaders">Referencing C header files</a></li><li>
<a href="#StructDeclStyles">Styles of struct/union/enum
declaration</a></li><li> <a href="#AccessingAPI">Accessing
Python/C API routines</a></li><li><a href="#SpecialTypes">Special Types</a><span style="color: rgb(255, 0, 0);"> <span style="color: rgb(255, 102, 0);">(New in 0.9.6)</span></span></li><li><a href="#CallingConventions">Windows Calling Conventions</a><span style="color: rgb(255, 0, 0);"> <span style="color: rgb(255, 102, 0);">(New in 0.9.6)</span></span></li><li>
<a href="#CNameSpecs">Resolving naming conflicts - C name
specifications</a></li></ul><li><a href="#Using_Pyrex_Declarations_from_C">Using Pyrex
declarations from C</a></li><ul><li> <a href="#PublicDecls">Public declarations</a></li></ul><ul><li><a href="#C_API_Declarations">C API declarations</a><span style="color: rgb(255, 0, 0);"> <span style="color: rgb(255, 102, 0);">(New in 0.9.6)</span></span></li><li><a href="#Multiple_public_and_api_declarations">Multiple public and API declarations</a><span style="color: rgb(255, 0, 0);"> (New in 0.9.6.3)</span></li><li><a href="#Acquiring_and_Releasing_the_GIL">Acquiring and Releasing the GIL</a><span style="color: rgb(255, 0, 0);"> <span style="color: rgb(255, 102, 0);">(New in 0.9.6)</span></span></li></ul></ul>
One of the main uses of Pyrex is wrapping existing libraries of C code.
This is achieved by using <a href="#ExternDecls">external
declarations</a> to declare the C functions and variables from
the library that you want to use. <p>You can also use <a href="#PublicDecls">public declarations</a> 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.</p><hr style="width: 100%; height: 2px;"> <h2> <a name="ExternDecls"></a>External
declarations</h2> By default, C functions and variables declared
at the module level are local to the module (i.e. they have the C <b>static</b>
storage class). They can also be declared <b>extern</b> to
specify that they are defined elsewhere, for example: <blockquote>
<pre>cdef extern int spam_counter</pre> <pre>cdef extern void order_spam(int tons)</pre></blockquote>
<h3>
<a name="ReferencingHeaders"></a>Referencing C
header files</h3> 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. <p>To achieve this, you can tell Pyrex
that the declarations are to be found in a C header file, like this: </p>
<blockquote> <pre>cdef extern from "spam.h":</pre> <pre>&nbsp;&nbsp;&nbsp; int spam_counter</pre><pre>&nbsp;&nbsp;&nbsp; void order_spam(int tons)</pre>
</blockquote> The <b>cdef extern from</b> clause
does three things: <ol><li> It directs Pyrex to place a <b>#include</b>
statement for the named header file in the generated C code.<br> </li>
&nbsp; <li> It prevents Pyrex from generating any C code for
the declarations found in the associated block.<br> </li>
&nbsp; <li> It treats all declarations within the block as
though they
started with <b>cdef extern</b>.</li></ol>
It's important to understand that Pyrex does <i>not</i>
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: <ol><li> Don't use <b>const</b>.
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.<sup><a href="#Footnote1"> 1</a></sup><br> </li>
&nbsp; <li> Leave out any platform-specific extensions to C
declarations such as <b>__declspec()</b>.<br> </li>
&nbsp; <li> 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.<br> <br>
In some cases, you might not need <i>any</i> of the
struct's members, in
which case you can just put <tt>pass</tt> in the body of
the struct declaration,
e.g.<br> <br> <tt>&nbsp; &nbsp; cdef extern
from "foo.h":<br> &nbsp; &nbsp; &nbsp; &nbsp;
struct spam:<br> &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; pass</tt><br> <br>
Note that you can only do this inside a <b>cdef extern from</b>
block; struct
declarations anywhere else must be non-empty.<br> <br> </li><li>
If the header file uses typedef names such as <b>size_t </b>to
refer to platform-dependent flavours of numeric types, you will need a
corresponding <b>ctypedef</b> statement, but you don't
need to match the type exactly, just use something of the right general
kind (int, float, etc). For example,</li><ol><pre>ctypedef int size_t</pre></ol>
will work okay whatever the actual size of a size_t is (provided the
header file defines it correctly). <br> &nbsp; <li>
If the header file uses macros to define constants, translate them into
a dummy <b>enum</b> declaration.<br> </li>
&nbsp; <li> 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.</li></ol> A few more tricks and tips: <ul><li>
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 <tt><font size="+1">pass</font></tt> in the extern-from
block:</li></ul> <ul><ul><tt>cdef extern
from "spam.h":</tt><br><tt>&nbsp;&nbsp;&nbsp;
pass</tt></ul></ul> <ul><li> 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 <tt>*</tt> in place of the
header file name:</li></ul> <blockquote> <blockquote><tt>cdef
extern from *:</tt> <br> <tt>&nbsp;&nbsp;&nbsp;
...</tt></blockquote> </blockquote> <h3> <a name="StructDeclStyles"></a>Styles of struct, union
and enum declaration</h3> 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. <p>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 <b>ctypedef</b>, as illustrated
below. </p> <p>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 <b>cdef
exern from </b>block. Struct declarations are used as an
example; the same applies equally to union and enum declarations. </p>
<p>Note that in all the cases below, you refer to the type in
Pyrex code simply
as <tt><font size="+1">Foo</font></tt>,
not <tt><font size="+1">struct Foo</font></tt>.
</p><table cellpadding="5"> <tbody>
<tr bgcolor="#8cbc1c" valign="top"> <td bgcolor="#8cbc1c">&nbsp;</td> <td bgcolor="#ff9933" nowrap="nowrap"><b>C code</b></td>
<td bgcolor="#66cccc" valign="top"><b>Possibilities
for corresponding Pyrex code</b></td> <td bgcolor="#99cc33" valign="top"><b>Comments</b></td>
</tr> <tr bgcolor="#8cbc1c" valign="top"> <td>1</td>
<td bgcolor="#ff9900"><tt>struct Foo {</tt> <br>
<tt>&nbsp; ...</tt> <br> <tt>};</tt></td>
<td bgcolor="#66cccc"><tt>cdef struct Foo:</tt>
<br> <tt>&nbsp; ...</tt></td> <td>Pyrex
will refer to the type as <tt>struct Foo </tt>in the
generated C code<tt>.</tt></td> </tr> <tr bgcolor="#8cbc1c" valign="top"> <td valign="top">2</td>
<td bgcolor="#ff9900" nowrap="nowrap"><tt>typedef
struct {</tt> <br> <tt>&nbsp; ...</tt> <br>
<tt>} Foo;</tt></td> <td bgcolor="#66cccc" valign="top"><tt>ctypedef struct Foo:</tt> <br>
<tt>&nbsp; ...</tt></td> <td valign="top">Pyrex
will refer to the type simply as <tt>Foo</tt>
in the generated C code.</td> </tr> <tr bgcolor="#8cbc1c" valign="top"> <td rowspan="2">3</td>
<td rowspan="2" bgcolor="#ff9900" nowrap="nowrap"><tt>typedef
struct
foo {</tt> <br> <tt>&nbsp; ...</tt> <br>
<tt>} Foo;</tt></td> <td bgcolor="#66cccc" nowrap="nowrap" valign="top"><tt>cdef struct
foo:</tt> <br> <tt>&nbsp; ...</tt> <br>
<tt>ctypedef foo Foo #optional</tt></td> <td rowspan="2" valign="top">If the C header uses both a
tag and a typedef with <i>different</i> 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).</td> </tr> <tr> <td bgcolor="#66cccc"><tt>ctypedef struct Foo:</tt> <br>
<tt>&nbsp; ...</tt></td> </tr> <tr bgcolor="#8cbc1c" valign="top"> <td>4</td>
<td bgcolor="#ff9900" nowrap="nowrap"><tt>typedef
struct Foo {</tt> <br> <tt>&nbsp; ...</tt>
<br> <tt>} Foo;</tt></td> <td bgcolor="#66cccc" valign="top"><tt>cdef struct
Foo:</tt> <br> <tt>&nbsp; ...</tt></td>
<td>If the header uses the <i>same</i> name for the
tag and the typedef, you won't be able to include a <b>ctypedef</b>
for it -- but then, it's not
necessary.</td> </tr> </tbody> </table> <h3>
<a name="AccessingAPI"></a>Accessing
Python/C API routines</h3> One particular use of the <b>cdef
extern from</b> statement is for gaining access to routines in
the Python/C API. For example, <blockquote> <pre>cdef extern from "Python.h":</pre>
<pre>&nbsp;&nbsp;&nbsp; object PyString_FromStringAndSize(char *s, Py_ssize_t len)</pre></blockquote>
will allow you to create Python strings containing
null bytes. <h3> <a name="SpecialTypes"></a>Special
Types</h3><p>Pyrex predefines the name <span style="font-family: monospace;">Py_ssize_t</span>
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.</p><h3><a name="CallingConventions"></a>Windows Calling
Conventions</h3><p>The <span style="font-family: monospace;">__stdcall</span>, <span style="font-family: monospace;">__fastcall</span> and <span style="font-family: monospace;">__cdecl</span> calling
convention specifiers can be used in Pyrex, with the same syntax as
used by C compilers on Windows, for example,</p><pre style="margin-left: 40px;">cdef extern int __stdcall FrobnicateWindow(long handle)<br><br>cdef void (__stdcall *callback)(void *)<br></pre>If
__stdcall is used, the function is only considered compatible with
other __stdcall functions of the same signature.<br><br> <hr width="100%"> <h2> <a name="CNameSpecs"></a>Resolving
naming conflicts - C name specifications</h2> 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. <p>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 <a href="sharing.html">sharing
declarations between Pyrex modules</a>. </p> <p>The
other way is to use a <b>c name specification</b> to give
different Pyrex and C names to the C function. Suppose, for example,
that you want to wrap an external function called <tt>eject_tomato</tt>.
If you declare it as </p> <blockquote> <pre>cdef extern void c_eject_tomato "eject_tomato" (float speed)</pre>
</blockquote> then its name inside the Pyrex module will be <tt>c_eject_tomato</tt>,
whereas its name in C will be <tt>eject_tomato</tt>. You
can then wrap it with <blockquote> <pre>def eject_tomato(speed):<br>&nbsp; c_eject_tomato(speed)</pre>
</blockquote> so that users of your module can refer to it as <tt>eject_tomato</tt>.
<p>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 <tt>print</tt>, you can rename it
to something else in your Pyrex module. </p> <p>As well
as functions, C names can be specified for variables, structs, unions,
enums, struct and union members, and enum values. For example, </p>
<blockquote> <pre>cdef extern int one "ein", two "zwei"<br>cdef extern float three "drei"<br><br>cdef struct spam "SPAM":<br>&nbsp; int i "eye"</pre><tt>cdef
enum surprise "inquisition":</tt> <br> <tt>&nbsp;
first "alpha"</tt> <br> <tt>&nbsp; second
"beta" = 3</tt></blockquote> <hr width="100%">
<h2><a name="Using_Pyrex_Declarations_from_C"></a>Using
Pyrex Declarations from C</h2>Pyrex
provides two methods for making C declarations from a Pyrex module
available for use by external C code &#8211; public declarations and C API
declarations.<br><br><div style="margin-left: 40px;"><span style="font-weight: bold;">NOTE:</span> You do <span style="font-style: italic;">not</span> need to use
either of these to make declarations from one Pyrex module available to
another Pyrex module &#8211; you should use the <span style="font-weight: bold;">cimport</span> statement
for that. <a href="sharing.html">Sharing Declarations
Between Pyrex Modules</a>.</div><h3><a name="PublicDecls"></a>Public Declarations</h3>
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 <b><tt>public</tt></b> keyword: <blockquote><tt>cdef
public struct Bunny: # public type declaration<br>&nbsp;
&nbsp; int vorpalness<br><br>cdef public int spam #
public variable declaration</tt> <p><tt>cdef public
void grail(Bunny *): # public function declaration</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; ...</tt></p> </blockquote>
If there are any <tt>public</tt> declarations in a Pyrex
module, a header file called <b><span style="font-style: italic;">modulename</span>.h</b>
file is generated containing equivalent C declarations for inclusion in
other C code.<br><br>Any
C code wanting to make use of these declarations will need to be
linked, either statically or dynamically, with the extension module.<br><br>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 <span style="font-weight: bold;">foo.spam</span> would have
a header file called <span style="font-weight: bold;">foo.spam.h</span>.
<h3><a name="C_API_Declarations"></a>C API
Declarations</h3><p>The other way of making declarations available to C code is to declare them with the <span style="font-family: monospace; font-weight: bold;">api</span>
keyword. You can use this keyword with C functions and extension types. A header file called "<span style="font-weight: bold;"><span style="font-style: italic;">modulename</span>_api.h</span>"
is produced containing declarations of the functions and extension types, and a function
called <span style="font-weight: bold;">import_<span style="font-style: italic;">modulename</span>()</span>.</p><p>C
code wanting to use these functions or extension types needs to include the header and call
the import_<span style="font-style: italic;">modulename</span>()
function. The other functions can then be called and the extension types used as usual.</p><p>Any
<span style="font-family: monospace;">public</span>
C type or extension type declarations in the Pyrex module are also made available when you
include <span style="font-style: italic;">modulename</span>_api.h.</p><table style="text-align: left; width: 100%;" border="0" cellpadding="5" cellspacing="2"><tbody><tr><td style="background-color: rgb(102, 204, 204);"><pre>delorean.pyx</pre></td><td style="background-color: rgb(255, 153, 0);"><pre>marty.c</pre></td></tr><tr><td style="vertical-align: top; background-color: rgb(102, 204, 204);"><pre>cdef public struct Vehicle:<br> int speed<br> float power<br><br>cdef api void activate(Vehicle *v):<br> if v.speed &gt;= 88 \<br> and v.power &gt;= 1.21:<br> print "Time travel achieved"</pre></td><td style="background-color: rgb(255, 153, 0);"><pre>#include "delorean_api.h"<br><br>Vehicle car;<br><br>int main(int argc, char *argv[]) {<br> import_delorean();<br> car.speed = atoi(argv[1]);<br> car.power = atof(argv[2]);&nbsp;<br> activate(&amp;car);<br>}</pre></td></tr></tbody></table><br>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 <span style="font-family: monospace;">public</span>,
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.<br><br>Using the <span style="font-family: monospace;">api</span> 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.<br><br>You can use both <span style="font-family: monospace;">public</span> and <span style="font-family: monospace;">api</span> on the same
function to make it available by both methods, e.g.<br><pre style="margin-left: 40px;">cdef public api void belt_and_braces():<br> ...<br></pre>However,
note that you should include <span style="font-weight: bold;">either</span>
<span style="font-style: italic;">modulename</span>.h
<span style="font-weight: bold;">or</span> <span style="font-style: italic;">modulename</span>_api.h in
a given C file, <span style="font-style: italic;">not</span>
both, otherwise you may get conflicting dual definitions.<br><br>If
the Pyrex module resides within a package, then:<br><ul><li>The
name of the header file contains of the full dotted name of the module.</li><li>The
name of the importing function contains the full name with dots
replaced by double underscores.</li></ul>E.g. a module
called <span style="font-weight: bold;">foo.spam</span>
would have an API header file called <span style="font-weight: bold;">foo.spam_api.h</span> and
an importing function called <span style="font-weight: bold;">import_foo__spam()</span>.<br><h3><a name="Multiple_public_and_api_declarations"></a>Multiple public and api declarations</h3>You can declare a whole group of items as <span style="font-style: italic;">public</span> and/or <span style="font-style: italic;">api</span> all at once by enclosing them in a cdef block, for example,<br><pre style="margin-left: 40px;">cdef public api:<br> void order_spam(int tons)<br> char *get_lunch(float tomato_size)<br></pre>This can be a useful thing to do in a <span style="font-family: monospace;">.pxd</span> file (see <a href="sharing.html">Sharing Declarations
Between Pyrex Modules</a>) to make the module's public interface available by all three methods.<br><br><hr style="width: 100%; height: 2px;"><h2><a name="Acquiring_and_Releasing_the_GIL"></a>Acquiring and Releasing the GIL</h2>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.<br><h3>Releasing the GIL</h3>You can release the GIL around a section of code using the<span style="font-family: monospace; font-weight: bold;"> with nogil </span>statement:<br><pre style="margin-left: 40px;">with nogil:<br> &lt;code to be executed with the GIL released&gt;<br></pre>Code in the body of the statement <span style="font-style: italic;">must not manipulate Python objects</span>,
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<span style="font-weight: bold;"></span>.<br><br>Any external C functions called inside the block must be declared as <span style="font-family: monospace;">nogil</span> (<a href="#nogil">see below</a>).<br><br><span style="font-weight: bold;">Note</span>:
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.<br><br>However, in the absence of such locking, it is not safe to do <span style="font-style: italic;">anything</span> with Python objects with the GIL released -- not even look at them.<br><h3>Acquiring the GIL</h3>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<span style="font-family: monospace; font-weight: bold;"> with gil </span>in the function header:<br><pre style="margin-left: 40px;">cdef void my_callback(void *data) with gil:<br> ...<br></pre><h3><a name="nogil"></a>Declaring a function as callable without the GIL</h3>You can specify <span style="font-family: monospace; font-weight: bold;">nogil</span> in a C function header or function type to declare that it is safe to call without the GIL.<br><br><div style="margin-left: 40px;"><span style="font-family: monospace;">cdef extern int swizzle_the_knob() nogil</span><br></div><br>A block of external functions can be declared <span style="font-family: monospace;">nogil</span> at once.<br><br><div style="margin-left: 40px;"><span style="font-family: monospace;">cdef extern from "somewhere.h" nogil:</span><br style="font-family: monospace;"><div style="margin-left: 40px;"><span style="font-family: monospace;">...</span><br></div></div><br>Note that declaring a function <span style="font-family: monospace;">nogil</span> does <span style="font-style: italic;">not</span>
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.<br><br>You can also declare a function implemented in Pyrex as <span style="font-family: monospace;">nogil</span>.<br><pre style="margin-left: 40px;">cdef void my_gil_free_func(int spam) nogil:<br> ...</pre>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<span style="font-family: monospace;"> with nogil </span>block.<br><br>Declaring a function<span style="font-family: monospace;"> with gil </span>also implicitly makes its signature<span style="font-family: monospace;"> nogil</span>.<br><br>
<hr style="width: 100%; height: 2px;"><span style="font-weight: bold;">Footnotes</span>
<hr width="100%"><a name="Footnote1"></a>1.
A problem with const
could arise if you have something like <blockquote> <pre>cdef extern from "grail.h":<br>&nbsp; char *nun</pre>
</blockquote> where grail.h actually contains <blockquote>
<pre>extern const char *nun;</pre> </blockquote> and
you do <blockquote> <pre>cdef void languissement(char *s):<br>&nbsp; #something that doesn't change s</pre>
<pre>...</pre> <pre>languissement(nun)</pre> </blockquote>which
will cause the C compiler to complain. You can work around it by
casting away the constness: <blockquote> <pre>languissement(&lt;char *&gt;nun)&nbsp; <br></pre>
</blockquote>---</body></html>

@ -0,0 +1,342 @@
<!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.61 (Macintosh; I; PPC) [Netscape]">
<title>Sharing Declarations Between Pyrex Modules</title></head>
<body>
<h1>
<hr width="100%">Sharing Declarations Between Pyrex Modules
<hr width="100%"></h1>
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.
<h2><a class="mozTocH2" name="mozTocId699652"></a> Contents</h2><ul id="mozToc"><!--mozToc h2 1 h3 2--><li><a href="#mozTocId989010"> Definition and Implementation files</a><ul><li><a href="#mozTocId411233"> What a Definition File contains</a></li><li><a href="#mozTocId20347"> What an Implementation File contains</a></li></ul></li><li><a href="#mozTocId950993"> The <span style="font-family: monospace;">cimport</span> statement</a><ul><li><a href="#mozTocId559554"> Search paths for definition files</a></li><li><a href="#mozTocId478514"> Using <span style="font-family: monospace;">cimport</span> to resolve naming
conflicts</a></li></ul></li><li><a href="#mozTocId937218">Sharing C Functions</a></li><li><a href="#mozTocId825278">Sharing Extension Types</a></li><li><a href="#mozTocId144977">Circular cimports</a></li></ul>
<h2><a class="mozTocH2" name="mozTocId989010"></a> <a name="DefAndImpFiles"></a>Definition and Implementation files</h2>
A Pyrex module can be split into two parts: a <i>definition file</i> with
a <tt>.pxd</tt> suffix, containing C declarations that are to be available
to other Pyrex modules, and an <i>implementation file</i> with a <tt>.pyx</tt>
suffix, containing everything else. When a module wants to use something
declared in another module's definition file, it imports it using the <a href="#CImportStatement"><b>cimport</b> statement</a>.
<h3><a class="mozTocH3" name="mozTocId411233"></a> <a name="WhatDefFileContains"></a>What a Definition File contains</h3>
A definition file can contain:
<ul>
<li> Any kind of C type declaration.</li>
<li> <b>extern</b> C function or variable declarations.</li><li>Declarations of C functions defined in the module.</li>
<li> The definition part of an extension type (<a href="#SharingExtensionTypes">see below</a>).</li>
</ul>
It cannot contain any non-extern C variable declarations.
<p>It cannot contain the implementations of any C or Python functions, or
any Python class definitions, or any executable statements. </p>
<blockquote>NOTE: You don't need to (and shouldn't) declare anything in a
declaration file <b>public</b> 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.</blockquote>
<h3><a class="mozTocH3" name="mozTocId20347"></a> <a name="WhatImpFileContains"></a>What an Implementation File contains</h3>
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).
<h2><a class="mozTocH2" name="mozTocId950993"></a> <a name="CImportStatement"></a>The <tt>cimport</tt> statement</h2>
The <b>cimport</b> 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:
<blockquote><tt>cimport </tt><i>module</i><tt> [, </tt><i>module</i><tt>...]</tt></blockquote>
<blockquote><tt>from </tt><i>module</i><tt> cimport </tt><i>name</i><tt>
[as </tt><i>name</i><tt>] [, </tt><i>name</i><tt> [as </tt><i>name</i><tt>]
...]</tt></blockquote>
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. <br>
&nbsp;
<table cellpadding="5" cols="2" width="100%">
<tbody>
<tr>
<td bgcolor="#ffcc00" width="40%"><b><tt>dishes.pxd</tt></b></td>
<td bgcolor="#5dbaca"><b><tt>restaurant.pyx</tt></b></td>
</tr>
<tr align="left" valign="top">
<td bgcolor="#ffcc18" width="40%"><tt>cdef enum otherstuff:</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; sausage, eggs, lettuce</tt>
<p><tt>cdef struct spamdish:</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; int oz_of_spam</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; otherstuff filler</tt></p>
</td>
<td bgcolor="#5dbaca"><tt>cimport dishes</tt> <br>
<tt>from dishes cimport spamdish</tt>
<p><tt>cdef void prepare(spamdish *d):</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; d.oz_of_spam = 42</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; d.filler = dishes.sausage</tt> </p>
<p><tt>def serve():</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; cdef spamdish d</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; prepare(&amp;d)</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; print "%d oz spam, filler no. %d" % \</tt>
<br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (d.oz_of_spam,
d.filler)</tt></p>
</td>
</tr>
</tbody>
</table>
<p>It is important to understand that the <b>cimport</b> statement can <i>only</i>
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 <b>import</b> statement for it as well. </p>
<p>The exception is that when you use <b>cimport</b> 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 <b>cimport</b> to import extension
types is covered in more detail <a href="#SharingExtensionTypes">below</a>.
</p>
<h3><a class="mozTocH3" name="mozTocId559554"></a> <a name="SearchPaths"></a>Search paths for definition files</h3>
When you <b>cimport</b> a module called <tt>modulename</tt>, the Pyrex
compiler searches for a file called <tt>modulename.pxd</tt> along the search
path for include files, as specified by <b>-I</b> command line options.
<p>Also, whenever you compile a file <tt>modulename.pyx</tt>, the corresponding
definition file <tt>modulename.pxd</tt> is first searched for along the
same path, and if found, it is processed before processing the <tt>.pyx</tt>
file. </p>
<h3><a class="mozTocH3" name="mozTocId478514"></a> <a name="ResolvingNamingConflicts"></a>Using cimport to resolve naming
conflicts</h3>
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:
<br>
&nbsp;
<table cellpadding="5" cols="2" width="100%">
<tbody>
<tr>
<td bgcolor="#ffcc00" width="50%"><b><tt>c_lunch.pxd</tt></b></td>
<td bgcolor="#5dbaca"><b><tt>lunch.pyx</tt></b></td>
</tr>
<tr align="left" valign="top">
<td bgcolor="#ffcc18" width="50%"><tt>cdef extern from "lunch.h":</tt>
<br>
<tt>&nbsp;&nbsp;&nbsp; void eject_tomato(float)</tt></td>
<td bgcolor="#5dbaca"><tt>cimport c_lunch</tt>
<p><tt>def eject_tomato(float speed):</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; c_lunch.eject_tomato(speed)</tt></p>
</td>
</tr>
</tbody>
</table>
<p>You don't need any <tt>c_lunch.pyx</tt> file, because the only things
defined in <tt>c_lunch.pxd</tt> are extern C entities. There won't be any
actual <tt>c_lunch</tt> module at run time, but that doesn't matter; the <tt>c_lunch.pxd</tt> file has done its job of providing an additional namespace at compile time.</p><h2><a class="mozTocH2" name="mozTocId937218"></a><a name="Sharing_C_Functions"></a>Sharing C Functions</h2><p>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,</p><table style="text-align: left; width: 100%;" border="0" cellpadding="5" cellspacing="2"><tbody><tr><td style="font-weight: bold; background-color: rgb(255, 204, 0);"><pre>volume.pxd</pre></td><td style="font-weight: bold; background-color: rgb(93, 186, 202);"><pre>spammery.pyx</pre></td></tr><tr><td style="vertical-align: top; background-color: rgb(255, 204, 0);"><pre>cdef float cube(float)</pre></td><td style="background-color: rgb(93, 186, 202);" colspan="1" rowspan="3"><pre>from volume cimport cube<br><br>def menu(description, size):<br>&nbsp; &nbsp; print description, ":", cube(size), \<br> "cubic metres of spam"<br><br>menu("Entree", 1)<br>menu("Main course", 3)<br>menu("Dessert", 2)</pre></td></tr><tr style="font-weight: bold;"><td style="vertical-align: top; background-color: rgb(153, 204, 51); height: 1px;"><pre>volume.pyx</pre></td></tr><tr><td style="vertical-align: top; background-color: rgb(153, 204, 51);"><pre>cdef float cube(float x):<br>&nbsp; &nbsp; return x * x * x</pre></td></tr></tbody></table><br><h2><a class="mozTocH2" name="mozTocId825278"></a><a name="Sharing_Extension_Types"></a>Sharing Extension Types</h2>
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.
<br>
<br>
The definition part of the extension type can only declare C attributes
and C methods, not Python methods, and it must declare <i>all</i> of that
type's C attributes and C methods.<br>
<br>
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.
<p>Here is an example of a module which defines and exports an extension
type, and another module which uses it. <br>
&nbsp;
<table cellpadding="5" cols="2" width="100%">
<tbody>
<tr>
<td bgcolor="#ffcc18" width="30%"><b><tt>Shrubbing.pxd</tt></b></td>
<td bgcolor="#5dbaca" width="50%"><b><tt>Shrubbing.pyx</tt></b></td>
</tr>
<tr align="left" valign="top">
<td bgcolor="#ffcc18" width="30%"><tt>cdef class Shrubbery:</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; cdef int width</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; cdef int length</tt></td>
<td bgcolor="#5dbaca" width="50%"><tt>cdef class Shrubbery:</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; def __cinit__(self, int w, int l):</tt> <br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.width = w</tt>
<br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.length = l</tt>
<p><tt>def standard_shrubbery():</tt> <br>
<tt>&nbsp;&nbsp;&nbsp; return Shrubbery(3, 7)</tt></p>
</td>
</tr>
<tr>
<td colspan="2" bgcolor="#8cbc1c" width="30%"><b><tt>Landscaping.pyx</tt></b></td>
</tr>
<tr>
<td colspan="2" bgcolor="#99cc00" width="30%"><tt>cimport Shrubbing</tt>
<br>
<tt>import Shrubbing</tt>
<p><tt>cdef Shrubbing.Shrubbery sh</tt> <br>
<tt>sh = Shrubbing.standard_shrubbery()</tt> <br>
<tt>print "Shrubbery size is %d x %d" % (sh.width, sh.length)</tt>
<br>
&nbsp;</p>
</td>
</tr>
</tbody>
</table>
</p>
<p>Some things to note about this example: </p>
<ul>
<li> There is a <tt>cdef</tt> <tt>class</tt> <tt>Shrubbery</tt> declaration in both Shrubbing.pxd
and Shrubbing.pyx. When the Shrubbing module is compiled, these two declarations
are combined into one.</li>
&nbsp; <li> In Landscaping.pyx, the <tt>cimport</tt> <tt>Shrubbing</tt> declaration
allows us to refer to the Shrubbery type as <tt>Shrubbing.Shrubbery</tt>.
But it doesn't bind the name <tt>Shrubbing</tt> in Landscaping's module namespace
at run time, so to access <tt>Shrubbing.standard_shrubbery</tt> we also
need to <tt>import</tt> <tt>Shrubbing</tt>.</li>
</ul>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.<h2><a class="mozTocH2" name="mozTocId144977"></a><a name="CircularCImports"></a>Circular cimports</h2>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 <span style="font-style: italic;">before</span> the first <span style="font-family: monospace;">cimport</span> statement.<br><br>For example:<br><br><table style="text-align: left; margin-left: 40px;" border="1" cellpadding="5" cellspacing="2"><tbody><tr><td style="vertical-align: top; white-space: nowrap; text-align: left; background-color: rgb(255, 204, 24); font-family: monospace;">foo.pxd</td><td style="vertical-align: top; white-space: nowrap; text-align: left; background-color: rgb(255, 204, 24); font-family: monospace;">blarg.pxd</td></tr><tr><td style="vertical-align: top; white-space: nowrap; text-align: left; font-family: monospace; background-color: rgb(255, 204, 24);">cdef struct Spam<br><br>from blarg cimport Eggs<br><br>cdef struct Spam:<br>&nbsp;&nbsp;&nbsp;&nbsp;Eggs *eggs</td><td style="vertical-align: top; white-space: nowrap; text-align: left; background-color: rgb(255, 204, 24); font-family: monospace;">cdef struct Eggs<br><br>from foo cimport Spam<br><br>cdef struct Eggs:<br>&nbsp;&nbsp;&nbsp;&nbsp;Spam *spam</td></tr></tbody></table><br>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 <span style="font-family: monospace;">cimport</span> statements ensures that all type names are known to the Pyrex compiler sufficiently far in advance.<br><br>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. <hr width="100%">Back to the <a href="overview.html">Language Overview</a>
<br>
<br>
</body></html>

@ -0,0 +1,78 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Source Files and Compilation</title></head>
<body>
<h1>
<hr style="width: 100%; height: 2px;">
Source
Files and Compilation
<hr style="width: 100%; height: 2px;">
</h1><ul id="mozToc"><!--mozToc h2 1 h3 2--><li><a href="#mozTocId581403">File Names and Extensions</a></li><li><a href="#mozTocId146379">Modules in Packages</a></li><li><a href="#mozTocId431365">Building an Extension</a><ul><li><a href="#mozTocId233830">Command Line</a></li><li><a href="#mozTocId49372">Calling the Pyrex compiler from Python</a></li><li><a href="#mozTocId11953">Using the distutils extension</a></li></ul></li><li><a href="#mozTocId559484">Distributing Pyrex modules</a></li></ul><h2><a class="mozTocH2" name="mozTocId581403"></a>File Names and Extensions</h2>Pyrex
source file names consist of the name of the module followed by a <span style="font-family: monospace;">.pyx</span> extension,
for example a module called <span style="font-family: monospace;">primes</span>
would have a source file named <span style="font-family: monospace;">primes.pyx</span>.<br><h2><a class="mozTocH2" name="mozTocId146379"></a>Modules in Packages</h2>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.<br><br>There are currently two ways to give it this information:<br><ol><li>Name the source file with the full dotted name of the module. For
example, a module called <span style="font-family: monospace;">primes</span> to be installed in a package called <span style="font-family: monospace;">numbers</span> would
have a source file called <span style="font-family: monospace;">numbers.primes.pyx</span>.<br><br></li><li>Place the source file in a <span style="font-style: italic;">package directory</span>. To Pyrex, a package directory is one that contains a file called either <span style="font-family: monospace;">__init__.py</span> or <span style="font-family: monospace;">__init__.pyx</span>. For example, a package called <span style="font-family: monospace;">numbers</span> containing a module called <span style="font-family: monospace;">primes</span> would have the source files laid out like this:</li></ol><div style="margin-left: 80px;"><span style="font-family: monospace;">numbers</span><br style="font-family: monospace;"><div style="margin-left: 40px;"><span style="font-family: monospace;">__init__.py</span><br style="font-family: monospace;"><span style="font-family: monospace;">primes.pyx</span><br></div></div><br>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.<br>
<h2><a class="mozTocH2" name="mozTocId431365"></a>Building an Extension</h2>There are two steps involved in creating an extension module from Pyres sources:<br><ol><li>Use the Pyrex compiler to translate the .pyx file into a .c file.</li><li>Compile the .c file with a C compiler and link it with whatever libraries it needs, to produce an extension module.</li></ol>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.<br>
<br><div style="margin-left: 40px;"><span style="font-family: monospace;">pyrexc -r primes.pyx</span><br>
</div><br>
This will compile <span style="font-family: monospace;">primes.pyx</span>
and any other source files that it depends on, if any of them have
changed since the last compilation, and produce a file called <span style="font-family: monospace;">primes.c</span>,
which then needs to be compiled with the C compiler using whatever
options are appropriate on your platform for generating an extension
module.<br><br>You
can perform the C compilation using distutils and a <span style="font-family: monospace;">setup.py</span> file, or with a conventional
Makefile. There's a Makefile in the Demos directory (called <span style="font-family: monospace;">Makefile.nodistutils</span>)
that shows how to do this for Linux.<br><br>Another approach is to put code at the beginning of your <span style="font-family: monospace;">setup.py</span> file to import the Pyrex compiler and call it from Python. You can then follow this with a normal call to <span style="font-family: monospace;">setup()</span> to compile the resulting .c files.<br>
<br>You can also perform both steps at once in a <span style="font-family: monospace;">setup.py</span> file using the distutils
extension provided with Pyrex. See the <span style="font-family: monospace;">Setup.py</span>
file in the <span style="font-family: monospace;">Demos</span>
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.<br><h3><a class="mozTocH3" name="mozTocId233830"></a>Command Line</h3>You can run the Pyrex compiler from the command line using either the <span style="font-family: monospace;">pyrexc</span> shell command or the Python version of it, <span style="font-family: monospace;">pyrexc.py</span>.<br><br>The following command line options exist:<br><br><table style="text-align: left; margin-left: 40px;" border="1" cellpadding="2" cellspacing="2"><tbody><tr><td style="font-weight: bold;" align="left" nowrap="nowrap" valign="top">Short</td><td style="font-weight: bold;" align="left" nowrap="nowrap" valign="top">Long</td><td style="font-weight: bold;" align="left" nowrap="nowrap" valign="top">Description</td></tr><tr><td align="left" nowrap="nowrap" valign="top">-v</td><td align="left" nowrap="nowrap" valign="top">--version</td><td align="left" nowrap="nowrap" valign="top">Display the version number of the Pyrex compiler</td></tr><tr><td align="left" nowrap="nowrap" valign="top">-l</td><td align="left" nowrap="nowrap" valign="top">--create-listing</td><td align="left" nowrap="nowrap" valign="top">Produces a .lis file for each compiled .pyx file containing error messages</td></tr><tr><td align="left" nowrap="nowrap" valign="top">-I</td><td align="left" nowrap="nowrap" valign="top">--include-dir</td><td style="vertical-align: top; text-align: left; width: 200px;">Specifies
a directory to be searched for included files and top-level package
directories. Multiple -I options may be given, each specifying one
directory.</td></tr><tr><td align="left" nowrap="nowrap" valign="top">-o</td><td align="left" nowrap="nowrap" valign="top">--output-file</td><td style="vertical-align: top; text-align: left; width: 200px;">Specifies name of generated C file. Only meaningful when a single .pyx file is being compiled.</td></tr><tr><td align="left" nowrap="nowrap" valign="top">-r</td><td align="left" nowrap="nowrap" valign="top">--recursive</td><td style="vertical-align: top; text-align: left; width: 200px;">Compile the given .pyx files, plus those of any modules it depends on directly or indirectly via <a href="sharing.html#CImportStatement">cimport</a> statements. The include path specified by -I options is used to find the .pyx files of dependent modules.</td></tr><tr><td align="left" nowrap="nowrap" valign="top">-t</td><td align="left" nowrap="nowrap" valign="top">--timestamps</td><td style="vertical-align: top; text-align: left; width: 200px;">Use
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.</td></tr><tr><td align="left" nowrap="nowrap" valign="top">-f</td><td align="left" nowrap="nowrap" valign="top">--force</td><td style="vertical-align: top; text-align: left; width: 200px;">Compile all .pyx files regardless of modification times. This is the default when -r is not given.</td></tr><tr><td align="left" nowrap="nowrap" valign="top">-q</td><td align="left" nowrap="nowrap" valign="top">--quiet</td><td style="vertical-align: top; text-align: left; width: 200px;">When -r is given, don't display the names of source files being compiled.</td></tr></tbody></table><br><h3><a class="mozTocH3" name="mozTocId49372"></a>Calling the Pyrex compiler from Python</h3>The module <span style="font-family: monospace;">Pyrex.Compiler.Main</span> exports the following classes and functions to facilitate invoking the compiler from another Python program.<br><br><span style="font-family: monospace;">compile(</span><span style="font-style: italic;">source</span> [, <span style="font-style: italic;">options</span>] [, <span style="font-style: italic;">&nbsp;option</span>&nbsp; =&nbsp;<span style="font-style: italic;">value</span> ]...<span style="font-family: monospace;">)</span><br><br><div style="margin-left: 40px;">Compiles one or more Pyrex source files, which should be <span style="font-family: monospace;">.pyx</span> files. The <span style="font-style: italic;">source</span> argument may be either a single filename or a list of filenames.<br><br>Depending on the <span style="font-family: monospace;">recursive</span>&nbsp;option,
it may compile just the specified source files, or the specified source
files plus those of other modules that they depend on via <span style="font-style: italic;">cimport</span> statements. The options may be given either as keyword arguments or a <span style="font-family: monospace;">CompilationOptions</span> instance. If both are used, keyword arguments take precedence.<br><br>The return value depends on whether a list of sources was specifed and whether the <span style="font-family: monospace;">recursive</span> option is in effect. If a single source file is specified and the <span style="font-family: monospace;">recursive</span> option is false, the return value is a <span style="font-family: monospace;">CompilationResult</span> instance. Otherwise, the return value is a&nbsp;<span style="font-family: monospace;">CompilationResultSet</span><span style="font-family: monospace;"></span> containing a <span style="font-family: monospace;">CompilationResult</span>
for each of the modules which were actually compiled (which may or may
not include ones corresponding to the specified source files).<br><br>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&nbsp;is parsed only once instead of being
parsed each time it is cimported.<br></div><br><span style="font-family: monospace;">compile_single(</span><span style="font-style: italic;">source_path</span> [, <span style="font-style: italic;">options</span>] [, <span style="font-style: italic;">&nbsp;option</span>&nbsp; =&nbsp;<span style="font-style: italic;">value</span> ]...<span style="font-family: monospace;">)</span><br><br><div style="margin-left: 40px;">Compiles just a single .pyx source file, specified as a string, with no dependency or timestamp checking (the <span style="font-family: monospace;">recursive</span> and <span style="font-family: monospace;">timestamps</span> options are ignored). Always returns a <span style="font-family: monospace;">CompilationResult</span>.</div><span style="font-family: monospace;"><br></span><span style="font-family: monospace;">compile_multiple(</span><span style="font-style: italic;">source_list</span> [, <span style="font-style: italic;">options</span>] [, <span style="font-style: italic;">&nbsp;option</span>&nbsp; =&nbsp;<span style="font-style: italic;">value</span> ]...<span style="font-family: monospace;">)</span><br><br><div style="margin-left: 40px;">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 <span style="font-family: monospace;">CompilationResultSet</span>.</div><span style="font-family: monospace;"><br>class CompilationOptions</span><br><br><div style="margin-left: 40px;">A collection of options to be passed to the <span style="font-family: monospace;">compile()</span> function. The following options may be specified as keyword arguments to either the <span style="font-family: monospace;">CompilationOptions</span> constructor or the <span style="font-family: monospace;">compile()</span> function.<br></div><div style="margin-left: 80px;"><dl><dt style="font-family: monospace;">show_version</dt><dd>Display the version number of the Pyrex compiler.<br></dd><dt style="font-family: monospace;">use_listing_file</dt><dd>Produce a .lis file for each .pyx file containing compilation errors.<br></dd><dt style="font-family: monospace;">include_path</dt><dd>A list of directories to search for included files and top-level package directories.<br></dd><dt style="font-family: monospace;">output_file</dt><dd>Use the given name for the generated .c file (only in non-recursive mode).<br></dd><dt style="font-family: monospace;">recursive</dt><dd>Compile the .pyx files of any cimported modules in addition to the one specified.<br></dd><dt style="font-family: monospace;">timestamps</dt><dd>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.<br></dd><dt style="font-family: monospace;">quiet</dt><dd>Don't display names of sources being compiled in recursive mode.</dd></dl></div><span style="font-family: monospace;">class CompilationResult</span><br><br><div style="margin-left: 40px;">An object providing information about the result of compiling a .pyx file. It has the following attributes:<br></div><div style="margin-left: 80px;"><dl><dt style="font-family: monospace;">c_file</dt><dd>Pathname of the generated C source file.<br></dd><dt style="font-family: monospace;">h_file</dt><dd>Pathname of the generated C header file, if any.<br></dd><dt style="font-family: monospace;">api_file</dt><dd>Pathname of the generated C API header file, if any.<br></dd><dt style="font-family: monospace;">listing_file</dt><dd>Pathname of the generated error message file, if any.<br></dd><dt style="font-family: monospace;">num_errors</dt><dd>Number of compilation errors.</dd></dl></div><span style="font-family: monospace;">class CompilationResultSet</span><div style="margin-left: 40px;"></div><div style="margin-left: 40px;">This is a mapping object whose keys are the pathnames of .pyx files and whose values are the corresponding <span style="font-family: monospace;">CompilationResult</span> instances. It also has the following additional attributes:<br><dl style="margin-left: 40px;"><dt style="font-family: monospace;">num_errors</dt><dd>Total number of compilation errors.</dd></dl></div><h3><a class="mozTocH3" name="mozTocId11953"></a>Using the distutils extension</h3>The
distutils extension provided with Pyrex allows you to pass .pyx files
directly to the Extension constructor in your setup file.<br><br>To use it, you need to put the following at the top of your setup.py file:<br><br><div style="margin-left: 40px; font-family: monospace;">from Pyrex.Distutils.extension import Extension<br>from Pyrex.Distutils import build_ext<br></div><br>and you need to specify the Pyrex version of the build_ext command class in your setup() call:<br><br><div style="margin-left: 40px; font-family: monospace;">setup(<br>&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp; cmdclass = {'build_ext': build_ext}<br>)<br></div><br>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.<br><h2><a class="mozTocH2" name="mozTocId559484"></a>Distributing Pyrex modules</h2>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.<br><br>It is also recommended that Pyrex compilation <span style="font-style: italic;">not</span>
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.<br><br>---<br></body></html>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -0,0 +1,43 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>0.9.9 Release Notes</title></head><body><h1>Release Notes for Pyrex 0.9.9</h1><h2>C++ Features</h2>Some features for interfacing with C++ code have been introduced in this release. Structs declared with '<span style="font-family: monospace;">cdef+ struct</span>' may have constructors and member functions, there is a '<span style="font-family: monospace;">new</span>' operator for instantiating them, and they may be deallocated using the '<span style="font-family: monospace;">del</span>' operator. Details may be found in the <a href="LanguageOverview.html">Language Overview</a> under <a href="Manual/using_with_c++.html">Using Pyrex with C++</a>.<br><h2>Changes to Exception Semantics</h2>The
behaviour surrounding exceptions caught using a try-except statement
were previously an inconsistent mixture of Pyrex and Python semantics.
Attempts to make the behaviour match Python more closely were requiring
the generation of increasingly convoluted and inefficient code, so I
decided to backtrack and return to something simpler.<br><br>Pyrex no
longer places caught exceptions into the thread state. This ensures
that exceptions and tracebacks do not leak out of the except clause
that caught them, unless you do something to explicitly preserve them.<br><br>It also means that you <span style="font-style: italic;">cannot</span> retrieve an caught exception in Pyrex using <span style="font-family: monospace;">sys.exc_info()</span>. If you want to capture the exception, you need to bind it to a name in the <span style="font-family: monospace;">except</span> clause.<br><br>To capture the traceback, the syntax of the <span style="font-family: monospace;">except</span> clause has been extended to allow a third argument. For example,<br><pre style="margin-left: 40px;">try:<br> start_vehicle()<br>except HovercraftError, err, tb:<br> print "Can't start:", err<br> traceback.print_tb(tb)<br></pre>As previously, a <span style="font-family: monospace;">raise</span> statement with no arguments must be lexically enclosed in the <span style="font-family: monospace;">except</span>
clause which caught the exception that you are trying to re-raise. In
order to re-raise it from somewhere else, you will need to explicity
communicate the exception and traceback to that place and use an
ordinary <span style="font-family: monospace;">raise</span> statement.<br><h2>Planned Change to None-checking</h2>Currently,
an argument to a Python function that is declared as an extension type
will, by default, be allowed to receive the value None; to prevent
this, you must qualify the argument declaration with '<span style="font-family: monospace;">not None</span>'.<br><br>This
arrangement has proved to be error-prone, because it requires the
programmer to be aware of the 'not None' feature and to remember to use
it everywhere necessary. Failure to do so results in a Pyrex module
that is prone to being crashed hard if it is passed a None value that
it is not expecting.<br><br>To improve this situation, I am planning to make '<span style="font-family: monospace;">not None</span>' the default in a future release of Pyrex. In order to allow None as a legal argument value, it will be necessary to use an '<span style="font-family: monospace;">or None</span>' qualifier.<br><br>In release 0.9.9, the '<span style="font-family: monospace;">or None</span>'
qualifier may be used, but it is optional. In preparation for the
change of default, the Pyrex compiler will issue a warning (once per
run) if it encounters an extension type argument that is not qualified
with either 'or None' or 'not None'. For example, if <span style="font-family: monospace;">Spam</span> and <span style="font-family: monospace;">Eggs</span> are extension types and you have a function declared as<br><pre style="margin-left: 40px;">def frobulate(Spam s, Eggs e not None):<br> ...<br></pre>then in order to eliminate the warning, you will need to change it to<br><pre style="margin-left: 40px;">def frobulate(Spam s or None, Eggs e not None):<br> ...</pre>In a later release, when 'not None' has become the default, it will be possible to drop the 'not None' qualifiers.<br><h2>Non-GC Extension Types</h2>It
is now possible to define and extension type with Python attributes
that does not participate in cyclic garbage collection, using a new <span style="font-family: monospace;">nogc</span> option, for example:<br><pre style="margin-left: 40px;">cdef class Spam [nogc]:<br> """This class doesn't participate in GC even though<br> it has a Python attribute."""<br> object sausages</pre><h2>Other New Features</h2>Some other minor feature additions and modifications have been made.<br><ul><li><span style="font-family: monospace;">size_t </span>is now a built-in type and is the type returned by the <span style="font-family: monospace;">sizeof</span> operator. Also, the sizes of <span style="font-family: monospace;">size_t</span> and <span style="font-family: monospace;">Py_ssize_t</span> are now assumed to be somewhere between <span style="font-family: monospace;">long</span> and <span style="font-family: monospace;">long long</span>.<br><br></li><li>Operations
between two int types of the same rank now return an
unsigned result if either of the operands is unsigned; if the ranks
differ, the result has the same type as the wider-ranked operand. I
think this is the best
approximation of the ANSI C rules that is possible without knowing the
exact sizes of the types.<br><br><span style="font-family: monospace;"></span></li><li><span style="font-family: monospace;">PyString_InternFromString</span> is now exposed under the name <span style="font-family: monospace; font-weight: bold;">cintern</span><span style="font-weight: bold;"> </span>rather than <span style="font-family: monospace;">intern</span>, because it is not a complete replacement for the Python <span style="font-family: monospace;">intern</span> function (it can't handle strings containing null bytes).<br></li><li>The
size check that was previously generated when importing an extension
type has been disabled for the time being until I can think of
something better. It was generating too many false positives, for
example from different versions of numpy.<br><br></li><li>The <span style="font-family: monospace;">__fastcall</span> calling convention option is now supported. Also, Pyrex no longer assumes that <span style="font-family: monospace;">__cdecl</span>
is the default calling convention. To be considered compatible, two
function types must either be declared with the same calling
convention, or both must leave it unspecified.<br><br></li><li>As I have been threatening for some time, using <span style="font-family: monospace;">__new__</span>
as the name of the initialisation method of an extension type has
become an error rather than just a warning. In some future release, <span style="font-family: monospace;">__new__</span> will re-emerge with more Python-like semantics.</li></ul><br></body></html>

@ -0,0 +1,70 @@
<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.51 (Macintosh; I; PPC) [Netscape]">
<title>Pyrex - Front Page</title></head>
<body>
&nbsp;
<table style="width: 100%;" cellpadding="10" cellspacing="0">
<tbody><tr>
<td bgcolor="#ff9218" valign="top"><font face="Arial,Helvetica"><font size="+4">Pyrex</font></font></td>
<td style="width: 200px; vertical-align: top; text-align: right; background-color: rgb(93, 186, 202);"><font face="Arial,Helvetica"><font size="+1">A
smooth blend of the finest Python&nbsp;</font></font>
<br><font face="Arial,Helvetica"><font size="+1">with the unsurpassed power&nbsp;</font></font>
<font face="Arial,Helvetica"><font size="+1">of raw C.</font></font></td>
</tr>
</tbody></table>
<blockquote><font size="+1">Welcome to Pyrex, a language for writing Python
extension modules. Pyrex makes creating an extension module&nbsp;almost as
easy as creating a Python module.</font></blockquote>
<h1>
<font face="Arial,Helvetica"><font size="+2">Documentation</font></font></h1>
<blockquote>
<h2>
<font face="Arial,Helvetica"><font size="+1"><a href="About.html">About Pyrex</a></font></font></h2>
<blockquote><font size="+1">Read this to find out what Pyrex is all about
and what it can do for you.</font></blockquote>
<h2>
<font face="Arial,Helvetica"><font size="+1"><a href="LanguageOverview.html">Language
Overview</a></font></font></h2>
<blockquote><font size="+1">A comined tutorial and reference manual describing of all the features of the Pyrex
language.</font></blockquote>
<h2>
<font face="Arial,Helvetica"><font size="+1"><a href="FAQ.html">FAQ</a></font></font></h2>
<blockquote><font size="+1">Want to know how to do something in Pyrex? Check
here first<font face="Arial,Helvetica">.</font></font></blockquote>
</blockquote>
<h1>
<font face="Arial,Helvetica"><font size="+2">Other Resources</font></font></h1>
<blockquote>
<h2>
<font face="Arial,Helvetica"><font size="+1"><a href="http://www.cosc.canterbury.ac.nz/%7Egreg/python/Pyrex/mpj17-pyrex-guide/">Michael's
Quick Guide to Pyrex</a></font></font></h2>
<blockquote><font size="+1">This tutorial-style presentation will take you
through the steps of creating some Pyrex modules to wrap existing C libraries.
Contributed by <a href="mailto:mpj17@cosc.canterbury.ac.nz">Michael JasonSmith</a>.</font></blockquote>
<h2>
<font face="Arial,Helvetica"><font size="+1"><a href="mailto:greg.ewing@canterbury.ac.nz">Mail
to the Author</a></font></font></h2>
<blockquote><font size="+1">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:<font face="Arial,Helvetica"> </font><tt><a href="mailto:greg.ewing@canterbury.ac.nz">greg.ewing@canterbury.ac.nz</a></tt></font></blockquote>
</blockquote>
</body></html>

@ -0,0 +1 @@
#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 */

@ -0,0 +1,33 @@
Pyrex - 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 module search path.
For example, create a pyrex.pth file in your
Python installation's Lib/site-packages
directory and insert a line containing the
fully qualified path to the directory containing
this file.
On unix, also put the bin directory on your PATH.
On Win32 copy the pyrexc.py file to your Python
installation's Scripts directory, which should
already be on the PATH.
See README.txt for pointers to other documentation.

@ -0,0 +1,173 @@
Apache License Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the
copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other
entities that control, are controlled by, or are under common control
with that entity. For the purposes of this definition, "control" means
(i) the power, direct or indirect, to cause the direction or
management of such entity, whether by contract or otherwise, or (ii)
ownership of fifty percent (50%) or more of the outstanding shares, or
(iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but not
limited to compiled object code, generated documentation, and
conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object
form, made available under the License, as indicated by a copyright
notice that is included in or attached to the work (an example is
provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the
purposes of this License, Derivative Works shall not include works
that remain separable from, or merely link (or bind by name) to the
interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the
original version of the Work and any modifications or additions to
that Work or Derivative Works thereof, that is intentionally submitted
to Licensor for inclusion in the Work by the copyright owner or by an
individual or Legal Entity authorized to submit on behalf of the
copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent to
the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control
systems, and issue tracking systems that are managed by, or on behalf
of, the Licensor for the purpose of discussing and improving the Work,
but excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of, publicly
display, publicly perform, sublicense, and distribute the Work and
such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except
as stated in this section) patent license to make, have made, use,
offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such
Contributor that are necessarily infringed by their Contribution(s)
alone or by combination of their Contribution(s) with the Work to
which such Contribution(s) was submitted. If You institute patent
litigation against any entity (including a cross-claim or counterclaim
in a lawsuit) alleging that the Work or a Contribution incorporated
within the Work constitutes direct or contributory patent
infringement, then any patent licenses granted to You under this
License for that Work shall terminate as of the date such litigation
is filed.
4. Redistribution. You may reproduce and distribute copies of the Work
or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You meet
the following conditions:
1. You must give any other recipients of the Work or Derivative Works
a copy of this License; and
2. You must cause any modified files to carry prominent notices
stating that You changed the files; and
3. You must retain, in the Source form of any Derivative Works that
You distribute, all copyright, patent, trademark, and attribution
notices from the Source form of the Work, excluding those notices that
do not pertain to any part of the Derivative Works; and
4. If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained within
such NOTICE file, excluding those notices that do not pertain to any
part of the Derivative Works, in at least one of the following places:
within a NOTICE text file distributed as part of the Derivative Works;
within the Source form or documentation, if provided along with the
Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The
contents of the NOTICE file are for informational purposes only and do
not modify the License. You may add Your own attribution notices
within Derivative Works that You distribute, alongside or as an
addendum to the NOTICE text from the Work, provided that such
additional attribution notices cannot be construed as modifying the
License.
You may add Your own copyright statement to Your modifications and may
provide additional or different license terms and conditions for use,
reproduction, or distribution of Your modifications, or for any such
Derivative Works as a whole, provided Your use, reproduction, and
distribution of the Work otherwise complies with the conditions stated
in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work by
You to the Licensor shall be under the terms and conditions of this
License, without any additional terms or conditions. Notwithstanding
the above, nothing herein shall supersede or modify the terms of any
separate license agreement you may have executed with Licensor
regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed
to in writing, Licensor provides the Work (and each Contributor
provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied, including, without
limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely
responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your
exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise, unless
required by applicable law (such as deliberate and grossly negligent
acts) or agreed to in writing, shall any Contributor be liable to You
for damages, including any direct, indirect, special, incidental, or
consequential damages of any character arising as a result of this
License or out of the use or inability to use the Work (including but
not limited to damages for loss of goodwill, work stoppage, computer
failure or malfunction, or any and all other commercial damages or
losses), even if such Contributor has been advised of the possibility
of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer, and
charge a fee for, acceptance of support, warranty, indemnity, or other
liability obligations and/or rights consistent with this License.
However, in accepting such obligations, You may act only on Your own
behalf and on Your sole responsibility, not on behalf of any other
Contributor, and only if You agree to indemnify, defend, and hold each
Contributor harmless for any liability incurred by, or claims asserted
against, such Contributor by reason of your accepting any such
warranty or additional liability.
END OF TERMS AND CONDITIONS

@ -0,0 +1,7 @@
include 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/*

@ -0,0 +1,15 @@
VERSION = 0.9.9
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

@ -0,0 +1,829 @@
#
# 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 "<CVoidType>"
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 "<CNumericType %s%s>" % (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 "<error>"
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)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,276 @@
#
# Pyrex - Builtin Definitions
#
from Symtab import BuiltinScope
from TypeSlots import Signature
from PyrexTypes import py_type_type, c_size_t_type, c_py_ssize_t_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", "l", "PyObject_Hash"),
#('hex', "", "", ""),
#('id', "", "", ""),
#('input', "", "", ""),
('cintern', "s", "O", "PyString_InternFromString"), # different name because doesn't handle null bytes
('isinstance', "OO", "i", "PyObject_IsInstance"),
('issubclass', "OO", "i", "PyObject_IsSubclass"),
('iter', "O", "O", "PyObject_GetIter"),
('iter2', "OO", "O", "PyCallIter_New"),
('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"),
("iappend", "OO", "i", "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_c_type_table = [
("size_t", c_size_t_type),
("Py_ssize_t", c_py_ssize_t_type),
]
builtin_type_table = [
# name, objstruct, typeobj, methods, members, flags
# 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, [], ['is_sequence']),
# 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
]
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_c_type(name, type):
builtin_scope.declare_builtin_c_type(name, type)
def declare_builtin_type(name, objstruct, typeobj, methods, members = [],
flags = []):
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)
for flag in flags:
setattr(type, flag, 1)
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_c_type_table:
declare_builtin_c_type(*desc)
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()

@ -0,0 +1,94 @@
#
# Pyrex - Command Line Parsing
#
import sys
from Filenames import pyx_suffixes
from Pyrex.Utils import has_suffix
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 <directory> Search for include files in named directory
-o, --output-file <filename> 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 has_suffix(arg, pyx_suffixes):
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

@ -0,0 +1,546 @@
##########################################################################
#
# 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; goto %s;}" % (
self.error_setup(pos),
lbl)
def error_setup(self, pos):
return "%s = %s[%s]; %s = %s" % (
Naming.filename_cname,
Naming.filetable_cname,
self.lookup_filename(pos[0]),
Naming.lineno_cname,
pos[1])
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

@ -0,0 +1,4 @@
debug_disposal_code = 0
debug_temp_alloc = 0
debug_coercion = 0

@ -0,0 +1,77 @@
#
# Pyrex - Errors
#
import sys
from Pyrex.Utils import open_new_file
warnings_issued = {}
class PyrexError(EnvironmentError):
pass
class CompileError(PyrexError):
def __init__(self, position = None, message = ""):
self.position = position
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 one_time_warning(position, key, message):
if key not in warnings_issued:
warnings_issued[key] = 1
warning(position, message)
def error(position, message):
global num_errors
num_errors = num_errors + 1
return report(position, message)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,9 @@
#
# Pyrex - Filename suffixes
#
cplus_suffix = ".cpp"
pxd_suffixes = (".pxd",)
pyx_suffixes = (".pyx", ".pyx+")
package_init_files = ("__init__.py", "__init__.pyx", "__init__.pyx+")
pyx_to_c_suffix = {".pyx": ".c", ".pyx+": cplus_suffix}

@ -0,0 +1,145 @@
#
# 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
)

@ -0,0 +1,564 @@
#
# 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, map_suffix
from Filenames import cplus_suffix, pxd_suffixes, pyx_suffixes, \
package_init_files, pyx_to_c_suffix
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_suffixes, 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_suffixes, pos)
def search_package_directories(self, qualified_name, suffixes, pos):
dotted_filenames = [qualified_name + suffix for suffix in suffixes]
if pos:
here = os.path.dirname(pos[0])
for dotted_filename in dotted_filenames:
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]
filenames = [module_name + suffix for suffix in suffixes]
for root in dirs:
for dotted_filename in dotted_filenames:
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:
for filename in filenames:
path = os.path.join(dir, filename)
if os.path.exists(path):
return path
for init_filename in package_init_files:
path = os.path.join(dir, module_name, init_filename)
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)
if self.is_package_dir(dir):
return dir
def is_package_dir(self, dir_path):
# Return true if the given directory is a package directory.
for filename in package_init_files:
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 = map_suffix(source_path, pyx_to_c_suffix, ".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:
result.c_file = replace_suffix(source, cplus_suffix)
else:
result.c_file = map_suffix(source, pyx_to_c_suffix, ".c")
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], [, <option> = <value>]...)
Compile one or more Pyrex implementation files, with optional timestamp
checking and recursing on dependecies. The source argument may be a string
or a sequence of strings. If it is a string and no recursion or timestamp
checking is requested, a CompilationResult is returned, otherwise a
CompilationResultSet is returned.
"""
options = CompilationOptions(defaults = options, c_compile = c_compile,
c_link = c_link, **kwds)
if isinstance(source, basestring) and not options.timestamps \
and not options.recursive:
return compile_single(source, options)
else:
return compile_multiple(source, options)
#------------------------------------------------------------------------
#
# Main command-line entry point
#
#------------------------------------------------------------------------
def main(command_line = 0):
args = sys.argv[1:]
any_failures = 0
if command_line:
from CmdLine import parse_command_line
options, sources = parse_command_line(args)
else:
options = CompilationOptions(default_options)
sources = args
if options.show_version:
print >>sys.stderr, "Pyrex version %s" % Version.version
try:
result = compile(sources, options)
if result.num_errors > 0:
any_failures = 1
except EnvironmentError, e:
print >>sys.stderr, e
any_failures = 1
if any_failures:
sys.exit(1)
#------------------------------------------------------------------------
#
# Set the default options depending on the platform
#
#------------------------------------------------------------------------
default_options = dict(
show_version = 0,
use_listing_file = 0,
errors_to_stderr = 1,
c_only = 1,
obj_only = 1,
cplus = 0,
output_file = None,
generate_pxi = 0,
recursive = 0,
timestamps = None,
verbose = 0,
quiet = 0)
if sys.platform == "mac":
from Pyrex.Mac.MacSystem import c_compile, c_link, CCompilerError
default_options['use_listing_file'] = 1
elif sys.platform == "darwin":
from Pyrex.Mac.DarwinSystem import c_compile, c_link, CCompilerError
else:
c_compile = None
c_link = None

File diff suppressed because it is too large Load Diff

@ -0,0 +1,69 @@
#
# Pyrex - C naming conventions
#
#
# Prefixes for generating C names.
# Collected here to facilitate ensuring uniqueness.
#
pyrex_prefix = "__pyx_"
arg_prefix = pyrex_prefix + "arg_"
funcdoc_prefix = pyrex_prefix + "doc_"
enum_prefix = pyrex_prefix + "e_"
func_prefix = pyrex_prefix + "f_"
gstab_prefix = pyrex_prefix + "getsets_"
prop_get_prefix = pyrex_prefix + "getprop_"
const_prefix = pyrex_prefix + "k"
label_prefix = pyrex_prefix + "L"
pymethdef_prefix = pyrex_prefix + "mdef_"
methtab_prefix = pyrex_prefix + "methods_"
memtab_prefix = pyrex_prefix + "members_"
interned_prefix = pyrex_prefix + "n_"
objstruct_prefix = pyrex_prefix + "obj_"
typeptr_prefix = pyrex_prefix + "ptype_"
prop_set_prefix = pyrex_prefix + "setprop_"
type_prefix = pyrex_prefix + "t_"
typeobj_prefix = pyrex_prefix + "type_"
var_prefix = pyrex_prefix + "v_"
vtable_prefix = pyrex_prefix + "vtable_"
vtabptr_prefix = pyrex_prefix + "vtabptr_"
vtabstruct_prefix = pyrex_prefix + "vtabstruct_"
args_cname = pyrex_prefix + "args"
kwdlist_cname = pyrex_prefix + "argnames"
obj_base_cname = pyrex_prefix + "base"
builtins_cname = pyrex_prefix + "b"
moddict_cname = pyrex_prefix + "d"
default_prefix = pyrex_prefix + "d"
dummy_cname = pyrex_prefix + "dummy"
filename_cname = pyrex_prefix + "filename"
filetable_cname = pyrex_prefix + "f"
filenames_cname = pyrex_prefix + "filenames"
fileinit_cname = pyrex_prefix + "init_filenames"
intern_tab_cname = pyrex_prefix + "intern_tab"
kwds_cname = pyrex_prefix + "kwds"
lineno_cname = pyrex_prefix + "lineno"
module_cname = pyrex_prefix + "m"
moddoc_cname = pyrex_prefix + "mdoc"
methtable_cname = pyrex_prefix + "methods"
retval_cname = pyrex_prefix + "r"
reqd_kwds_cname = pyrex_prefix + "reqd_kwds"
self_cname = pyrex_prefix + "self"
stringtab_cname = pyrex_prefix + "string_tab"
vtabslot_cname = pyrex_prefix + "vtab"
extern_c_macro = pyrex_prefix.upper() + "EXTERN_C"
exc_type_name = pyrex_prefix + "exc_type"
exc_value_name = pyrex_prefix + "exc_value"
exc_tb_name = pyrex_prefix + "exc_tb"
exc_lineno_name = pyrex_prefix + "exc_lineno"
exc_vars = (exc_type_name, exc_value_name, exc_tb_name)
api_name = pyrex_prefix + "capi__"
h_guard_prefix = "__PYX_HAVE__"
api_guard_prefix = "__PYX_HAVE_API__"
api_func_guard = "__PYX_HAVE_API_FUNC_"

File diff suppressed because it is too large Load Diff

@ -0,0 +1,5 @@
#
# Pyrex - Compilation-wide options
#
intern_names = 1 # Intern global variable and attribute names

File diff suppressed because it is too large Load Diff

@ -0,0 +1,974 @@
#
# Pyrex - Types
#
import string
import Naming
class BaseType:
#
# Base class for all Pyrex types including pseudo-types.
def cast_code(self, expr_code):
return "((%s)%s)" % (self.declaration_code(""), expr_code)
def base_declaration_code(self, base_code, entity_code):
if entity_code:
return "%s %s" % (base_code, entity_code)
else:
return base_code
class PyrexType(BaseType):
#
# Base class for all non-pseudo 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_typedef boolean Is a typedef type
# is_string boolean Is a C char * type
# is_returncode boolean Is used only to signal exceptions
# is_sequence boolean Is a sequence type
# is_builtin boolean Is a built-in Python type
# 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_typedef = 0
is_string = 0
is_returncode = 0
is_sequence = 0
is_builtin = 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
class TypeWrapper(BaseType):
# Base class for pseudo-types that delegate most
# attribute lookups to another type.
#
# delegate_type PyrexType
def __init__(self, base_type):
self.delegate_type = base_type
def __getattr__(self, name):
return getattr(self.delegate_type, name)
def define(self, base_type):
self.delegate_type = base_type
def resolve(self):
return self.delegate_type.resolve()
class CTypedefType(TypeWrapper):
#
# Pseudo-type defined with a ctypedef statement in a
# 'cdef extern from' block. Delegates most attribute
# lookups to the base type. ANYTHING NOT DEFINED
# HERE IS DELEGATED!
#
# qualified_name string
# typedef_cname string
# typedef_base_type PyrexType
is_typedef = 1
def __init__(self, cname, base_type):
TypeWrapper.__init__(self, base_type)
self.typedef_cname = cname
self.typedef_base_type = base_type
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
name = self.declaration_name(for_display, pyrex)
return self.base_declaration_code(name, entity_code)
def declaration_name(self, for_display = 0, pyrex = 0):
if pyrex or for_display:
return self.qualified_name
else:
return self.typedef_cname
def as_argument_type(self):
return self
def __repr__(self):
return "<CTypedefType %s>" % self.typedef_cname
def __str__(self):
return self.declaration_name(for_display = 1)
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 or for_display:
return self.base_declaration_code("object", 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
if base_type and base_type.is_sequence:
self.is_sequence = 1
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 or for_display:
return self.base_declaration_code(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 is_defined(self):
scope = self.scope
return scope and (scope.defined or scope.implemented)
def __str__(self):
return self.name
def __repr__(self):
return "<PyExtensionType %s%s>" % (self.scope.class_name,
("", " typedef")[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 CVoidType(CType):
is_void = 1
def __repr__(self):
return "<CVoidType>"
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
base = public_decl("void", dll_linkage)
return self.base_declaration_code(base, entity_code)
def is_complete(self):
return 0
class CNumericType(CType):
#
# Base class for all C numeric types.
#
# rank integer Relative size
# signed integer 0 = unsigned, 1 = unspecified, 2 = explicitly signed
# name string or None to construct from sign and rank
#
is_numeric = 1
default_value = "0"
parsetuple_formats = ( # rank -> format
"BHIk?K???", # unsigned
"bhil?Lfd?", # assumed signed
"bhil?Lfd?", # explicitly signed
)
sign_words = ("unsigned ", "", "signed ")
def __init__(self, rank, signed, name, pymemberdef_typecode = None):
self.rank = rank
self.signed = signed
self.name = name
ptf = self.parsetuple_formats[signed][rank]
if ptf == '?':
ptf = None
self.parsetuple_format = ptf
self.pymemberdef_typecode = pymemberdef_typecode
def sign_and_name(self):
return self.name
def __repr__(self):
return "<CNumericType %s>" % self.sign_and_name()
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
base = public_decl(self.sign_and_name(), dll_linkage)
return self.base_declaration_code(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, name, pymemberdef_typecode = None, is_returncode = 0):
CNumericType.__init__(self, rank, signed, name, 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 CAnonEnumType(CIntType):
is_enum = 1
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 CPySSizeTType(CIntType):
to_py_function = "PyInt_FromSsize_t"
from_py_function = "PyInt_AsSsize_t"
class CFloatType(CNumericType):
is_float = 1
to_py_function = "PyFloat_FromDouble"
from_py_function = "PyFloat_AsDouble"
def __init__(self, rank, name, pymemberdef_typecode = None):
CNumericType.__init__(self, rank, 1, name, 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 = ""
if entity_code.startswith("*"):
entity_code = "(%s)" % entity_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
if other_type.is_null_ptr:
return 1
if self.base_type.is_cfunction:
if other_type.is_ptr:
other_type = other_type.base_type.resolve()
if other_type.is_cfunction:
return self.base_type.pointer_assignable_from_resolved_type(other_type)
else:
return 0
if other_type.is_array or other_type.is_ptr:
return self.base_type.is_void or self.base_type.same_as(other_type.base_type)
return 0
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
# calling_convention string Function calling convention
# nogil boolean Can be called without gil
# with_gil boolean Acquire gil around function body
is_cfunction = 1
is_overloaded = 0
def __init__(self, return_type, args, has_varargs = 0,
exception_value = None, exception_check = 0, calling_convention = "",
nogil = 0, with_gil = 0):
self.return_type = return_type
self.args = args
self.has_varargs = has_varargs
self.exception_value = exception_value
self.exception_check = exception_check
self.calling_convention = calling_convention
self.nogil = nogil
self.with_gil = with_gil
def __repr__(self):
arg_reprs = map(repr, self.args)
if self.has_varargs:
arg_reprs.append("...")
return "<CFuncType %s %s[%s]>" % (
repr(self.return_type),
self.calling_convention_prefix(),
string.join(arg_reprs, ","))
def callable_with(self, actual_arg_types):
formal_arg_types = self.args
nf = len(formal_arg_types)
na = len(actual_arg_types)
if not (nf == na or self.has_varargs and nf >= na):
return False
for formal_type, actual_type in zip(formal_arg_types, actual_arg_types):
if not formal_type.assignable_from(actual_type):
return False
return True
def calling_convention_prefix(self):
cc = self.calling_convention
if cc:
return cc + " "
else:
return ""
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 = 0):
#print "CFuncType.same_c_signature_as_resolved_type:", \
# self, other_type, "as_cmethod =", 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
if not self.same_calling_convention_as(other_type):
return 0
return 1
def same_calling_convention_as(self, other):
return self.calling_convention == other.calling_convention
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) \
and self.nogil == other_type.nogil
def pointer_assignable_from_resolved_type(self, other_type):
return self.same_c_signature_as_resolved_type(other_type) \
and self.same_exception_signature_as_resolved_type(other_type) \
and not (self.nogil and not other_type.nogil)
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"
trailer = ""
if (pyrex or for_display) and not self.return_type.is_pyobject:
if self.exception_value and self.exception_check:
trailer = " except? %s" % self.exception_value
elif self.exception_value:
trailer = " except %s" % self.exception_value
elif self.exception_check:
trailer = " except *"
if self.nogil:
trailer += " nogil"
cc = self.calling_convention_prefix()
if (not entity_code and cc) or entity_code.startswith("*"):
entity_code = "(%s%s)" % (cc, entity_code)
cc = ""
return self.return_type.declaration_code(
"%s%s(%s)%s" % (cc, entity_code, arg_decl_code, trailer),
for_display, dll_linkage, pyrex)
def function_header_code(self, func_name, arg_code):
return "%s%s(%s)" % (self.calling_convention_prefix(),
func_name, arg_code)
def signature_string(self):
s = self.declaration_code("")
return s
class COverloadedFuncType(CType):
# return_type CType
# signatures [CFuncType]
is_cfunction = 1
is_overloaded = 1
def __init__(self, return_type, signatures):
self.return_type = return_type
self.signatures = signatures
def __str__(self):
return "COverloadedFuncType(%s, [%s])" % (self.return_type,
", ".join(map(str, self.signatures)))
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
# cplus_constructor_type COverloadedFuncType
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.typedef_flag = typedef_flag
self.set_scope(scope)
def __repr__(self):
return "<CStructOrUnionType %s %s%s>" % (self.name, self.cname,
("", " typedef")[self.typedef_flag])
def set_scope(self, scope):
self.scope = scope
if scope and scope.is_cplus:
self.cplus_constructor_type = COverloadedFuncType(self,
scope.cplus_constructors)
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex:
return self.base_declaration_code(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 self.base_declaration_code(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 = -1 # Ranks below any integer type
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 __str__(self):
return self.name
def __repr__(self):
return "<CEnumType %s %s%s>" % (self.name, self.cname,
("", " typedef")[self.typedef_flag])
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex:
return self.base_declaration_code(self.cname, entity_code)
else:
if self.typedef_flag:
base = self.cname
else:
base = "enum %s" % self.cname
return self.base_declaration_code(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"
parsetuple_format = "E"
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
return "<error>"
def same_as_resolved_type(self, other_type):
return 1
py_object_type = PyObjectType()
py_type_type = TypeWrapper(None) # Bootstrapping placeholder, filled later
c_void_type = CVoidType()
c_void_ptr_type = CPtrType(c_void_type)
c_void_ptr_ptr_type = CPtrType(c_void_ptr_type)
c_uchar_type = CIntType(0, 0, "unsigned char", "T_UBYTE")
c_ushort_type = CIntType(1, 0, "unsigned short", "T_USHORT")
c_uint_type = CUIntType(2, 0, "unsigned int", "T_UINT")
c_ulong_type = CULongType(3, 0, "unsigned long", "T_ULONG")
c_size_t_type = CPySSizeTType(4, 0, "size_t")
c_ulonglong_type = CULongLongType(5, 0, "unsigned PY_LONG_LONG", "T_ULONGLONG")
c_char_type = CIntType(0, 1, "char", "T_CHAR")
c_short_type = CIntType(1, 1, "short", "T_SHORT")
c_int_type = CIntType(2, 1, "int", "T_INT")
c_long_type = CIntType(3, 1, "long", "T_LONG")
c_longlong_type = CLongLongType(5, 1, "PY_LONG_LONG", "T_LONGLONG")
c_schar_type = CIntType(0, 2, "signed char", "T_CHAR")
c_sshort_type = CIntType(1, 2, "signed short", "T_SHORT")
c_sint_type = CIntType(2, 2, "signed int", "T_INT")
c_slong_type = CIntType(3, 2, "signed long", "T_LONG")
c_py_ssize_t_type = CPySSizeTType(4, 2, "Py_ssize_t")
c_slonglong_type = CLongLongType(5, 2, "signed PY_LONG_LONG", "T_LONGLONG")
c_float_type = CFloatType(6, "float", "T_FLOAT")
c_double_type = CFloatType(7, "double", "T_DOUBLE")
c_longdouble_type = CFloatType(8, "long double")
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, "int", "T_INT", is_returncode = 1)
c_anon_enum_type = CAnonEnumType(-1, 1, "<enum>")
error_type = ErrorType()
# Signedness values
UNSIGNED = 0
NOSIGN = 1
SIGNED = 2
# Longness values
SHORT = -1
NOLEN = 0
LONG = 1
LONGLONG = 2
modifiers_and_name_to_type = {
#(signedness, longness, name)
(UNSIGNED, NOLEN, "char"): c_uchar_type,
(UNSIGNED, SHORT, "int"): c_ushort_type,
(UNSIGNED, NOLEN, "int"): c_uint_type,
(UNSIGNED, LONG, "int"): c_ulong_type,
(UNSIGNED, LONGLONG, "int"): c_ulonglong_type,
(NOSIGN, NOLEN, "void"): c_void_type,
(NOSIGN, NOLEN, "char"): c_char_type,
(NOSIGN, SHORT, "int"): c_short_type,
(NOSIGN, NOLEN, "int"): c_int_type,
#(NOSIGN, NOLEN, "size_t"): c_size_t_type,
#(NOSIGN, NOLEN, "Py_ssize_t"): c_py_ssize_t_type,
(NOSIGN, LONG, "int"): c_long_type,
(NOSIGN, LONGLONG, "int"): c_longlong_type,
(NOSIGN, NOLEN, "float"): c_float_type,
(NOSIGN, NOLEN, "double"): c_double_type,
(NOSIGN, LONG, "double"): c_longdouble_type,
(NOSIGN, NOLEN, "object"): py_object_type,
(SIGNED, NOLEN, "char"): c_schar_type,
(SIGNED, SHORT, "int"): c_sshort_type,
(SIGNED, NOLEN, "int"): c_sint_type,
(SIGNED, LONG, "int"): c_slong_type,
(SIGNED, LONGLONG, "int"): c_slonglong_type,
}
def widest_numeric_type(type1, type2):
# Given two numeric types, return the narrowest type
# encompassing both of them.
if type1.is_enum and type2.is_enum:
widest_type = c_int_type
elif type1.rank < type2.rank:
widest_type = type2
elif type1.rank > type2.rank:
widest_type = type1
elif type1.signed < type2.signed:
widest_type = type1
else:
widest_type = type2
return widest_type
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 \
same_type(to_type, from_type) or \
(not to_type.is_pyobject and assignable_from(to_type, from_type)):
return expr_code
else:
return to_type.cast_code(expr_code)

@ -0,0 +1,390 @@
#
# Pyrex Scanner
#
#import pickle
import cPickle as pickle
import os
import platform
import stat
import sys
from time import time
from Pyrex import Plex
from Pyrex.Plex import Scanner
from Pyrex.Plex.Errors import UnrecognizedInput
from Errors import CompileError, error
from Lexicon import string_prefixes, make_lexicon
plex_version = getattr(Plex, '_version', None)
#print "Plex version:", plex_version ###
debug_scanner = 0
trace_scanner = 0
scanner_debug_flags = 0
scanner_dump_file = None
binary_lexicon_pickle = 1
notify_lexicon_unpickling = 0
notify_lexicon_pickling = 1
lexicon = None
#-----------------------------------------------------------------
def hash_source_file(path):
# Try to calculate a hash code for the given source file.
# Returns an empty string if the file cannot be accessed.
#print "Hashing", path ###
try:
from hashlib import md5
except ImportError:
from md5 import new as md5
try:
try:
f = open(path, "rU")
text = f.read()
except IOError, e:
print "Unable to hash scanner source file (%s)" % e
return ""
finally:
f.close()
# Normalise spaces/tabs. We don't know what sort of
# space-tab substitution the file may have been
# through, so we replace all spans of spaces and
# tabs by a single space.
import re
text = re.sub("[ \t]+", " ", text)
hash = md5(text).hexdigest()
return hash
def open_pickled_lexicon(expected_hash):
# Try to open pickled lexicon file and verify that
# it matches the source file. Returns the opened
# file if successful, otherwise None. ???
f = None
result = None
if os.path.exists(lexicon_pickle):
try:
f = open(lexicon_pickle, "rb")
actual_hash = pickle.load(f)
if actual_hash == expected_hash:
result = f
f = None
else:
print "Lexicon hash mismatch:" ###
print " expected", expected_hash ###
print " got ", actual_hash ###
except IOError, e:
print "Warning: Unable to read pickled lexicon", lexicon_pickle
print e
if f:
f.close()
return result
def try_to_unpickle_lexicon():
global lexicon, lexicon_pickle, lexicon_hash
dir = os.path.dirname(__file__)
source_file = os.path.join(dir, "Lexicon.py")
lexicon_hash = hash_source_file(source_file)
lexicon_pickle = os.path.join(dir, "Lexicon.pickle")
f = open_pickled_lexicon(expected_hash = lexicon_hash)
if f:
if notify_lexicon_unpickling:
t0 = time()
print "Unpickling lexicon..."
lexicon = pickle.load(f)
f.close()
if notify_lexicon_unpickling:
t1 = time()
print "Done (%.2f seconds)" % (t1 - t0)
def create_new_lexicon():
global lexicon
t0 = time()
print "Creating lexicon..."
lexicon = make_lexicon()
t1 = time()
print "Done (%.2f seconds)" % (t1 - t0)
def pickle_lexicon():
f = None
try:
f = open(lexicon_pickle, "wb")
except IOError:
print "Warning: Unable to save pickled lexicon in", lexicon_pickle
if f:
if notify_lexicon_pickling:
t0 = time()
print "Pickling lexicon..."
pickle.dump(lexicon_hash, f, binary_lexicon_pickle)
pickle.dump(lexicon, f, binary_lexicon_pickle)
f.close()
if notify_lexicon_pickling:
t1 = time()
print "Done (%.2f seconds)" % (t1 - t0)
def get_lexicon():
global lexicon
if not lexicon and plex_version is None:
try_to_unpickle_lexicon()
if not lexicon:
create_new_lexicon()
if plex_version is None:
pickle_lexicon()
return lexicon
#------------------------------------------------------------------
reserved_words = [
"global", "include", "ctypedef", "cdef", "def", "class",
"print", "del", "pass", "break", "continue", "return",
"raise", "import", "exec", "try", "except", "finally",
"while", "if", "elif", "else", "for", "in", "assert",
"and", "or", "not", "is", "in", "lambda", "from",
"NULL", "cimport", "with", "DEF", "IF", "ELIF", "ELSE"
]
class Method:
def __init__(self, name):
self.name = name
self.__name__ = name # for Plex tracing
def __call__(self, stream, text):
return getattr(stream, self.name)(text)
#------------------------------------------------------------------
def build_resword_dict():
d = {}
for word in reserved_words:
d[word] = 1
return d
#------------------------------------------------------------------
class CompileTimeScope(object):
def __init__(self, outer = None):
self.entries = {}
self.outer = outer
def declare(self, name, value):
self.entries[name] = value
def lookup_here(self, name):
return self.entries[name]
def lookup(self, name):
try:
return self.lookup_here(name)
except KeyError:
outer = self.outer
if outer:
return outer.lookup(name)
else:
raise
def initial_compile_time_env():
benv = CompileTimeScope()
names = ('UNAME_SYSNAME', 'UNAME_NODENAME', 'UNAME_RELEASE',
'UNAME_VERSION', 'UNAME_MACHINE')
for name, value in zip(names, platform.uname()):
benv.declare(name, value)
import __builtin__
names = ('False', 'True',
'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')
for name in names:
benv.declare(name, getattr(__builtin__, name))
denv = CompileTimeScope(benv)
return denv
#------------------------------------------------------------------
class PyrexScanner(Scanner):
# context Context Compilation context
# type_names set Identifiers to be treated as type names
# included_files [string] Files included with 'include' statement
# compile_time_env dict Environment for conditional compilation
# compile_time_eval boolean In a true conditional compilation context
# compile_time_expr boolean In a compile-time expression context
resword_dict = build_resword_dict()
def __init__(self, file, filename, parent_scanner = None,
scope = None, context = None):
Scanner.__init__(self, get_lexicon(), file, filename)
if parent_scanner:
self.context = parent_scanner.context
self.type_names = parent_scanner.type_names
self.included_files = parent_scanner.included_files
self.compile_time_env = parent_scanner.compile_time_env
self.compile_time_eval = parent_scanner.compile_time_eval
self.compile_time_expr = parent_scanner.compile_time_expr
else:
self.context = context
self.type_names = scope.type_names
self.included_files = scope.pyrex_include_files
self.compile_time_env = initial_compile_time_env()
self.compile_time_eval = 1
self.compile_time_expr = 0
self.trace = trace_scanner
self.indentation_stack = [0]
self.indentation_char = None
self.bracket_nesting_level = 0
self.begin('INDENT')
self.sy = ''
self.next()
def current_level(self):
return self.indentation_stack[-1]
def open_bracket_action(self, text):
self.bracket_nesting_level = self.bracket_nesting_level + 1
return text
def close_bracket_action(self, text):
self.bracket_nesting_level = self.bracket_nesting_level - 1
return text
def newline_action(self, text):
if self.bracket_nesting_level == 0:
self.begin('INDENT')
self.produce('NEWLINE', '')
string_states = {
"'": 'SQ_STRING',
'"': 'DQ_STRING',
"'''": 'TSQ_STRING',
'"""': 'TDQ_STRING'
}
def begin_string_action(self, text):
if text[:1] in string_prefixes:
text = text[1:]
self.begin(self.string_states[text])
self.produce('BEGIN_STRING')
def end_string_action(self, text):
self.begin('')
self.produce('END_STRING')
def unclosed_string_action(self, text):
self.end_string_action(text)
self.error("Unclosed string literal")
def indentation_action(self, text):
self.begin('')
# Indentation within brackets should be ignored.
#if self.bracket_nesting_level > 0:
# return
# Check that tabs and spaces are being used consistently.
if text:
c = text[0]
#print "Scanner.indentation_action: indent with", repr(c) ###
if self.indentation_char is None:
self.indentation_char = c
#print "Scanner.indentation_action: setting indent_char to", repr(c)
else:
if self.indentation_char <> c:
self.error("Mixed use of tabs and spaces")
if text.replace(c, "") <> "":
self.error("Mixed use of tabs and spaces")
# Figure out how many indents/dedents to do
current_level = self.current_level()
new_level = len(text)
#print "Changing indent level from", current_level, "to", new_level ###
if new_level == current_level:
return
elif new_level > current_level:
#print "...pushing level", new_level ###
self.indentation_stack.append(new_level)
self.produce('INDENT', '')
else:
while new_level < self.current_level():
#print "...popping level", self.indentation_stack[-1] ###
self.indentation_stack.pop()
self.produce('DEDENT', '')
#print "...current level now", self.current_level() ###
if new_level <> self.current_level():
self.error("Inconsistent indentation")
def eof_action(self, text):
while len(self.indentation_stack) > 1:
self.produce('DEDENT', '')
self.indentation_stack.pop()
self.produce('EOF', '')
def next(self):
try:
sy, systring = self.read()
except UnrecognizedInput:
self.error("Unrecognized character")
if sy == 'IDENT' and systring in self.resword_dict:
sy = systring
self.sy = sy
self.systring = systring
if debug_scanner:
_, line, col = self.position()
if not self.systring or self.sy == self.systring:
t = self.sy
else:
t = "%s %s" % (self.sy, self.systring)
print "--- %3d %2d %s" % (line, col, t)
def put_back(self, sy, systring):
self.unread(self.sy, self.systring)
self.sy = sy
self.systring = systring
def unread(self, token, value):
# This method should be added to Plex
self.queue.insert(0, (token, value))
def add_type_name(self, name):
self.type_names[name] = 1
def looking_at_type_name(self):
return self.sy == 'IDENT' and self.systring in self.type_names
def error(self, message, pos = None):
if pos is None:
pos = self.position()
if self.sy == 'INDENT':
error(pos, "Possible inconsistent indentation")
raise error(pos, message)
def expect(self, what, message = None):
if self.sy == what:
self.next()
else:
self.expected(what, message)
def expect_keyword(self, what, message = None):
if self.sy == 'IDENT' and self.systring == what:
self.next()
else:
self.expected(what, message)
def expected(self, what, message):
if message:
self.error(message)
else:
self.error("Expected '%s'" % what)
def expect_indent(self):
self.expect('INDENT',
"Expected an increase in indentation level")
def expect_dedent(self):
self.expect('DEDENT',
"Expected a decrease in indentation level")
def expect_newline(self, message = "Expected a newline"):
# Expect either a newline or end of file
if self.sy <> 'EOF':
self.expect('NEWLINE', message)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,629 @@
#
# Pyrex - Tables describing slots in the type object
# and associated know-how.
#
import Naming
import PyrexTypes
class Signature:
# Method slot signature descriptor.
#
# has_dummy_arg boolean
# has_generic_args boolean
# fixed_arg_format string
# ret_format string
# error_value string
#
# The formats are strings made up of the following
# characters:
#
# 'O' Python object
# 'T' Python object of the type of 'self'
# 't' Python type object
# 'v' void
# 'p' void *
# 'P' void **
# 'i' int
# 'I' int *
# 'l' long
# 'Z' Py_ssize_t
# 's' char *
# 'S' char **
# 'r' int used only to signal exception
# '-' dummy 'self' argument (not used)
# '*' rest of args passed as generic Python
# arg tuple and kw dict (must be last
# char in format string)
format_map = {
'O': PyrexTypes.py_object_type,
't': PyrexTypes.py_type_type,
'v': PyrexTypes.c_void_type,
'p': PyrexTypes.c_void_ptr_type,
'P': PyrexTypes.c_void_ptr_ptr_type,
'b': PyrexTypes.c_int_type, # boolean - no error value
'i': PyrexTypes.c_int_type,
'I': PyrexTypes.c_int_ptr_type,
'l': PyrexTypes.c_long_type,
'Z': PyrexTypes.c_py_ssize_t_type,
's': PyrexTypes.c_char_ptr_type,
'S': PyrexTypes.c_char_ptr_ptr_type,
'r': PyrexTypes.c_returncode_type,
# 'T', '-' and '*' are handled otherwise
# and are not looked up in here
}
error_value_map = {
'O': "0",
't': "0",
'i': "-1",
'l': "-1",
'r': "-1",
'Z': "-1",
}
def __init__(self, arg_format, ret_format):
self.has_dummy_arg = 0
self.has_generic_args = 0
if arg_format[:1] == '-':
self.has_dummy_arg = 1
arg_format = arg_format[1:]
if arg_format[-1:] == '*':
self.has_generic_args = 1
arg_format = arg_format[:-1]
self.fixed_arg_format = arg_format
self.ret_format = ret_format
self.error_value = self.error_value_map.get(ret_format, None)
def num_fixed_args(self):
return len(self.fixed_arg_format)
def is_self_arg(self, i):
return self.fixed_arg_format[i] == 'T'
def fixed_arg_type(self, i):
return self.format_map[self.fixed_arg_format[i]]
def return_type(self):
return self.format_map[self.ret_format]
def exception_value(self):
return self.error_value_map.get(self.ret_format)
def function_type(self, self_type = None):
# Construct a C function type descriptor for this signature
args = []
#for i in xrange(self.num_fixed_args()):
# arg_type = self.fixed_arg_type(i)
for c in self.fixed_arg_format:
if c == "T":
assert self_type is not None
arg_type = self_type
else:
arg_type = self.format_map[c]
args.append(PyrexTypes.CFuncTypeArg("", arg_type, None))
ret_type = self.return_type()
exc_value = self.exception_value()
return PyrexTypes.CFuncType(ret_type, args, exception_value = exc_value)
class SlotDescriptor:
# Abstract base class for type slot descriptors.
#
# slot_name string Member name of the slot in the type object
# is_initialised_dynamically Is initialised by code in the module init function
# flag Py_TPFLAGS_XXX value indicating presence of slot
def __init__(self, slot_name, dynamic = 0, flag = None):
self.slot_name = slot_name
self.is_initialised_dynamically = dynamic
self.flag = flag
def generate(self, scope, code):
if self.is_initialised_dynamically:
value = 0
else:
value = self.slot_code(scope)
flag = self.flag
if flag:
code.putln("#if Py_TPFLAGS_DEFAULT & %s" % flag)
code.putln("%s, /*%s*/" % (value, self.slot_name))
if flag:
code.putln("#endif")
# Some C implementations have trouble statically
# initialising a global with a pointer to an extern
# function, so we initialise some of the type slots
# in the module init function instead.
def generate_dynamic_init_code(self, scope, code):
if self.is_initialised_dynamically:
value = self.slot_code(scope)
if value <> "0":
code.putln("%s.%s = %s;" % (
scope.parent_type.typeobj_cname,
self.slot_name,
value
)
)
class FixedSlot(SlotDescriptor):
# Descriptor for a type slot with a fixed value.
#
# value string
def __init__(self, slot_name, value):
SlotDescriptor.__init__(self, slot_name)
self.value = value
def slot_code(self, scope):
return self.value
class EmptySlot(FixedSlot):
# Descriptor for a type slot whose value is always 0.
def __init__(self, slot_name):
FixedSlot.__init__(self, slot_name, "0")
class GCDependentSlot(SlotDescriptor):
# Descriptor for a slot whose value depends on whether
# the type participates in GC.
def __init__(self, slot_name, no_gc_value, gc_value, dynamic = 0):
SlotDescriptor.__init__(self, slot_name, dynamic)
self.no_gc_value = no_gc_value
self.gc_value = gc_value
def slot_code(self, scope):
if scope.has_pyobject_attrs:
return self.gc_value
else:
return self.no_gc_value
class MethodSlot(SlotDescriptor):
# Type slot descriptor for a user-definable method.
#
# signature Signature
# method_name string The __xxx__ name of the method
# default string or None Default value of the slot
def __init__(self, signature, slot_name, method_name, default = None, flag = None):
SlotDescriptor.__init__(self, slot_name, flag = flag)
self.signature = signature
self.slot_name = slot_name
self.method_name = method_name
self.default = default
method_name_to_slot[method_name] = self
def slot_code(self, scope):
entry = scope.lookup_here(self.method_name)
if entry:
return entry.func_cname
else:
return "0"
class InternalMethodSlot(SlotDescriptor):
# Type slot descriptor for a method which is always
# synthesized by Pyrex.
#
# slot_name string Member name of the slot in the type object
def __init__(self, slot_name):
SlotDescriptor.__init__(self, slot_name)
def slot_code(self, scope):
return scope.mangle_internal(self.slot_name)
class PyAttrDependentSlot(InternalMethodSlot):
# Type slot for a method that is synthesized only
# when the extension type has Python-valued attributes.
def slot_code(self, scope):
if scope.pyattr_entries:
return InternalMethodSlot.slot_code(self, scope)
else:
return "0"
class SyntheticSlot(InternalMethodSlot):
# Type slot descriptor for a synthesized method which
# dispatches to one or more user-defined methods depending
# on its arguments. If none of the relevant methods are
# defined, the method will not be synthesized and an
# alternative default value will be placed in the type
# slot.
def __init__(self, slot_name, user_methods, default_value):
InternalMethodSlot.__init__(self, slot_name)
self.user_methods = user_methods
self.default_value = default_value
def slot_code(self, scope):
if scope.defines_any(self.user_methods):
return InternalMethodSlot.slot_code(self, scope)
else:
return self.default_value
class TypeFlagsSlot(SlotDescriptor):
# Descriptor for the type flags slot.
def slot_code(self, scope):
value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE"
if scope.pyattr_entries and not scope.no_gc:
value += "|Py_TPFLAGS_HAVE_GC"
return value
class DocStringSlot(SlotDescriptor):
# Descriptor for the docstring slot.
def slot_code(self, scope):
if scope.doc is not None:
return '"%s"' % scope.doc
else:
return "0"
class SuiteSlot(SlotDescriptor):
# Descriptor for a substructure of the type object.
#
# sub_slots [SlotDescriptor]
def __init__(self, sub_slots, slot_type, slot_name):
SlotDescriptor.__init__(self, slot_name)
self.sub_slots = sub_slots
self.slot_type = slot_type
substructures.append(self)
def substructure_cname(self, scope):
return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name)
def slot_code(self, scope):
return "&%s" % self.substructure_cname(scope)
def generate_substructure(self, scope, code):
code.putln("")
code.putln(
"static %s %s = {" % (
self.slot_type,
self.substructure_cname(scope)))
for slot in self.sub_slots:
slot.generate(scope, code)
code.putln("};")
substructures = [] # List of all SuiteSlot instances
class MethodTableSlot(SlotDescriptor):
# Slot descriptor for the method table.
def slot_code(self, scope):
return scope.method_table_cname
class MemberTableSlot(SlotDescriptor):
# Slot descriptor for the table of Python-accessible attributes.
def slot_code(self, scope):
if scope.public_attr_entries:
return scope.member_table_cname
else:
return "0"
class GetSetSlot(SlotDescriptor):
# Slot descriptor for the table of attribute get & set methods.
def slot_code(self, scope):
if scope.property_entries:
return scope.getset_table_cname
else:
return "0"
class BaseClassSlot(SlotDescriptor):
# Slot descriptor for the base class slot.
def __init__(self, name):
SlotDescriptor.__init__(self, name, dynamic = 1)
def generate_dynamic_init_code(self, scope, code):
base_type = scope.parent_type.base_type
if base_type:
code.putln("%s.%s = %s;" % (
scope.parent_type.typeobj_cname,
self.slot_name,
base_type.typeptr_cname))
# The following dictionary maps __xxx__ method names to slot descriptors.
method_name_to_slot = {}
## The following slots are (or could be) initialised with an
## extern function pointer.
#
#slots_initialised_from_extern = (
# "tp_free",
#)
#------------------------------------------------------------------------------------------
#
# Utility functions for accessing slot table data structures
#
#------------------------------------------------------------------------------------------
def get_special_method_signature(name):
# Given a method name, if it is a special method,
# return its signature, else return None.
slot = method_name_to_slot.get(name)
if slot:
return slot.signature
else:
return None
def get_property_accessor_signature(name):
# Return signature of accessor for an extension type
# property, else None.
return property_accessor_signatures.get(name)
#------------------------------------------------------------------------------------------
#
# Signatures for generic Python functions and methods.
#
#------------------------------------------------------------------------------------------
pyfunction_signature = Signature("-*", "O")
pymethod_signature = Signature("T*", "O")
#------------------------------------------------------------------------------------------
#
# Signatures for the various kinds of function that
# can appear in the type object and its substructures.
#
#------------------------------------------------------------------------------------------
unaryfunc = Signature("T", "O") # typedef PyObject * (*unaryfunc)(PyObject *);
binaryfunc = Signature("OO", "O") # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
ibinaryfunc = Signature("TO", "O") # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
ternaryfunc = Signature("OOO", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
iternaryfunc = Signature("TOO", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
callfunc = Signature("T*", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
inquiry = Signature("T", "i") # typedef int (*inquiry)(PyObject *);
lenfunc = Signature("T", "Z") # typedef Py_ssize_t (*lenfunc)(PyObject *);
# typedef int (*coercion)(PyObject **, PyObject **);
intargfunc = Signature("Ti", "O") # typedef PyObject *(*intargfunc)(PyObject *, int);
ssizeargfunc = Signature("TZ", "O") # typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
intintargfunc = Signature("Tii", "O") # typedef PyObject *(*intintargfunc)(PyObject *, int, int);
ssizessizeargfunc = Signature("TZZ", "O") # typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
intobjargproc = Signature("TiO", 'r') # typedef int(*intobjargproc)(PyObject *, int, PyObject *);
ssizeobjargproc = Signature("TZO", 'r') # typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
intintobjargproc = Signature("TiiO", 'r') # typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *);
ssizessizeobjargproc = Signature("TZZO", 'r') # typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
intintargproc = Signature("Tii", 'r')
ssizessizeargproc = Signature("TZZ", 'r')
objargfunc = Signature("TO", "O")
objobjargproc = Signature("TOO", 'r') # typedef int (*objobjargproc)(PyObject *, PyObject *, PyObject *);
getreadbufferproc = Signature("TiP", 'i') # typedef int (*getreadbufferproc)(PyObject *, int, void **);
getwritebufferproc = Signature("TiP", 'i') # typedef int (*getwritebufferproc)(PyObject *, int, void **);
getsegcountproc = Signature("TI", 'i') # typedef int (*getsegcountproc)(PyObject *, int *);
getcharbufferproc = Signature("TiS", 'i') # typedef int (*getcharbufferproc)(PyObject *, int, const char **);
readbufferproc = Signature("TZP", "Z") # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
writebufferproc = Signature("TZP", "Z") # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
segcountproc = Signature("TZ", "Z") # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
writebufferproc = Signature("TZS", "Z") # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
objargproc = Signature("TO", 'r') # typedef int (*objobjproc)(PyObject *, PyObject *);
# typedef int (*visitproc)(PyObject *, void *);
# typedef int (*traverseproc)(PyObject *, visitproc, void *);
destructor = Signature("T", "v") # typedef void (*destructor)(PyObject *);
# printfunc = Signature("TFi", 'r') # typedef int (*printfunc)(PyObject *, FILE *, int);
# typedef PyObject *(*getattrfunc)(PyObject *, char *);
getattrofunc = Signature("TO", "O") # typedef PyObject *(*getattrofunc)(PyObject *, PyObject *);
# typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
setattrofunc = Signature("TOO", 'r') # typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *);
delattrofunc = Signature("TO", 'r')
cmpfunc = Signature("TO", "i") # typedef int (*cmpfunc)(PyObject *, PyObject *);
reprfunc = Signature("T", "O") # typedef PyObject *(*reprfunc)(PyObject *);
hashfunc = Signature("T", "l") # typedef long (*hashfunc)(PyObject *);
# typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
richcmpfunc = Signature("OOi", "O") # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
getiterfunc = Signature("T", "O") # typedef PyObject *(*getiterfunc) (PyObject *);
iternextfunc = Signature("T", "O") # typedef PyObject *(*iternextfunc) (PyObject *);
descrgetfunc = Signature("TOO", "O") # typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
descrsetfunc = Signature("TOO", 'r') # typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
descrdelfunc = Signature("TO", 'r')
initproc = Signature("T*", 'r') # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
# typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
# typedef PyObject *(*allocfunc)(struct _typeobject *, int);
#------------------------------------------------------------------------------------------
#
# Signatures for accessor methods of properties.
#
#------------------------------------------------------------------------------------------
property_accessor_signatures = {
'__get__': Signature("T", "O"),
'__set__': Signature("TO", 'r'),
'__del__': Signature("T", 'r')
}
#------------------------------------------------------------------------------------------
#
# Descriptor tables for the slots of the various type object
# substructures, in the order they appear in the structure.
#
#------------------------------------------------------------------------------------------
PyNumberMethods = (
MethodSlot(binaryfunc, "nb_add", "__add__"),
MethodSlot(binaryfunc, "nb_subtract", "__sub__"),
MethodSlot(binaryfunc, "nb_multiply", "__mul__"),
MethodSlot(binaryfunc, "nb_divide", "__div__"),
MethodSlot(binaryfunc, "nb_remainder", "__mod__"),
MethodSlot(binaryfunc, "nb_divmod", "__divmod__"),
MethodSlot(ternaryfunc, "nb_power", "__pow__"),
MethodSlot(unaryfunc, "nb_negative", "__neg__"),
MethodSlot(unaryfunc, "nb_positive", "__pos__"),
MethodSlot(unaryfunc, "nb_absolute", "__abs__"),
MethodSlot(inquiry, "nb_nonzero", "__nonzero__"),
MethodSlot(unaryfunc, "nb_invert", "__invert__"),
MethodSlot(binaryfunc, "nb_lshift", "__lshift__"),
MethodSlot(binaryfunc, "nb_rshift", "__rshift__"),
MethodSlot(binaryfunc, "nb_and", "__and__"),
MethodSlot(binaryfunc, "nb_xor", "__xor__"),
MethodSlot(binaryfunc, "nb_or", "__or__"),
EmptySlot("nb_coerce"),
MethodSlot(unaryfunc, "nb_int", "__int__"),
MethodSlot(unaryfunc, "nb_long", "__long__"),
MethodSlot(unaryfunc, "nb_float", "__float__"),
MethodSlot(unaryfunc, "nb_oct", "__oct__"),
MethodSlot(unaryfunc, "nb_hex", "__hex__"),
# Added in release 2.0
MethodSlot(ibinaryfunc, "nb_inplace_add", "__iadd__"),
MethodSlot(ibinaryfunc, "nb_inplace_subtract", "__isub__"),
MethodSlot(ibinaryfunc, "nb_inplace_multiply", "__imul__"),
MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__"),
MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__"),
MethodSlot(ternaryfunc, "nb_inplace_power", "__ipow__"), # NOT iternaryfunc!!!
MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__"),
MethodSlot(ibinaryfunc, "nb_inplace_rshift", "__irshift__"),
MethodSlot(ibinaryfunc, "nb_inplace_and", "__iand__"),
MethodSlot(ibinaryfunc, "nb_inplace_xor", "__ixor__"),
MethodSlot(ibinaryfunc, "nb_inplace_or", "__ior__"),
# Added in release 2.2
# The following require the Py_TPFLAGS_HAVE_CLASS flag
MethodSlot(binaryfunc, "nb_floor_divide", "__floordiv__"),
MethodSlot(binaryfunc, "nb_true_divide", "__truediv__"),
MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__"),
MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"),
MethodSlot(unaryfunc, "nb_index", "__index__", flag = "Py_TPFLAGS_HAVE_INDEX")
)
PySequenceMethods = (
MethodSlot(lenfunc, "sq_length", "__len__"),
EmptySlot("sq_concat"), # nb_add used instead
EmptySlot("sq_repeat"), # nb_multiply used instead
SyntheticSlot("sq_item", ["__getitem__"], "0"), #EmptySlot("sq_item"), # mp_subscript used instead
MethodSlot(ssizessizeargfunc, "sq_slice", "__getslice__"),
EmptySlot("sq_ass_item"), # mp_ass_subscript used instead
SyntheticSlot("sq_ass_slice", ["__setslice__", "__delslice__"], "0"),
MethodSlot(cmpfunc, "sq_contains", "__contains__"),
EmptySlot("sq_inplace_concat"), # nb_inplace_add used instead
EmptySlot("sq_inplace_repeat"), # nb_inplace_multiply used instead
)
PyMappingMethods = (
MethodSlot(lenfunc, "mp_length", "__len__"),
MethodSlot(objargfunc, "mp_subscript", "__getitem__"),
SyntheticSlot("mp_ass_subscript", ["__setitem__", "__delitem__"], "0"),
)
PyBufferProcs = (
MethodSlot(getreadbufferproc, "bf_getreadbuffer", "__getreadbuffer__"),
MethodSlot(getwritebufferproc, "bf_getwritebuffer", "__getwritebuffer__"),
MethodSlot(getsegcountproc, "bf_getsegcount", "__getsegcount__"),
MethodSlot(getcharbufferproc, "bf_getcharbuffer", "__getcharbuffer__"),
)
#------------------------------------------------------------------------------------------
#
# The main slot table. This table contains descriptors for all the
# top-level type slots, beginning with tp_dealloc, in the order they
# appear in the type object.
#
#------------------------------------------------------------------------------------------
slot_table = (
InternalMethodSlot("tp_dealloc"),
EmptySlot("tp_print"), #MethodSlot(printfunc, "tp_print", "__print__"),
EmptySlot("tp_getattr"),
EmptySlot("tp_setattr"),
MethodSlot(cmpfunc, "tp_compare", "__cmp__"),
MethodSlot(reprfunc, "tp_repr", "__repr__"),
SuiteSlot(PyNumberMethods, "PyNumberMethods", "tp_as_number"),
SuiteSlot(PySequenceMethods, "PySequenceMethods", "tp_as_sequence"),
SuiteSlot(PyMappingMethods, "PyMappingMethods", "tp_as_mapping"),
MethodSlot(hashfunc, "tp_hash", "__hash__"),
MethodSlot(callfunc, "tp_call", "__call__"),
MethodSlot(reprfunc, "tp_str", "__str__"),
SyntheticSlot("tp_getattro", ["__getattr__"], "0"), #"PyObject_GenericGetAttr"),
SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"), #"PyObject_GenericSetAttr"),
SuiteSlot(PyBufferProcs, "PyBufferProcs", "tp_as_buffer"),
TypeFlagsSlot("tp_flags"),
DocStringSlot("tp_doc"),
PyAttrDependentSlot("tp_traverse"),
PyAttrDependentSlot("tp_clear"),
# Later -- synthesize a method to split into separate ops?
MethodSlot(richcmpfunc, "tp_richcompare", "__richcmp__"),
EmptySlot("tp_weaklistoffset"),
MethodSlot(getiterfunc, "tp_iter", "__iter__"),
MethodSlot(iternextfunc, "tp_iternext", "__next__"),
MethodTableSlot("tp_methods"),
MemberTableSlot("tp_members"),
GetSetSlot("tp_getset"),
BaseClassSlot("tp_base"), #EmptySlot("tp_base"),
EmptySlot("tp_dict"),
SyntheticSlot("tp_descr_get", ["__get__"], "0"),
SyntheticSlot("tp_descr_set", ["__set__", "__delete__"], "0"),
EmptySlot("tp_dictoffset"),
MethodSlot(initproc, "tp_init", "__init__"),
EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"),
InternalMethodSlot("tp_new"),
# Some versions of Python 2.2 inherit the wrong value for tp_free when the
# type has GC but the base type doesn't, so we explicitly set it ourselves
# in that case.
GCDependentSlot("tp_free", "0", "_PyObject_GC_Del", dynamic = 1),
EmptySlot("tp_is_gc"),
EmptySlot("tp_bases"),
EmptySlot("tp_mro"),
EmptySlot("tp_cache"),
EmptySlot("tp_subclasses"),
EmptySlot("tp_weaklist"),
)
#------------------------------------------------------------------------------------------
#
# Descriptors for special methods which don't appear directly
# in the type object or its substructures. These methods are
# called from slot functions synthesized by Pyrex.
#
#------------------------------------------------------------------------------------------
MethodSlot(initproc, "", "__cinit__")
MethodSlot(destructor, "", "__dealloc__")
MethodSlot(objobjargproc, "", "__setitem__")
MethodSlot(objargproc, "", "__delitem__")
MethodSlot(ssizessizeobjargproc, "", "__setslice__")
MethodSlot(ssizessizeargproc, "", "__delslice__")
MethodSlot(getattrofunc, "", "__getattr__")
MethodSlot(setattrofunc, "", "__setattr__")
MethodSlot(delattrofunc, "", "__delattr__")
MethodSlot(descrgetfunc, "", "__get__")
MethodSlot(descrsetfunc, "", "__set__")
MethodSlot(descrdelfunc, "", "__delete__")

@ -0,0 +1,20 @@
###############################################
#
# Odds and ends for debugging
#
###############################################
def print_call_chain(*args):
import sys
print " ".join(map(str, args))
f = sys._getframe(1)
while f:
name = f.f_code.co_name
s = f.f_locals.get('self', None)
if s:
c = getattr(s, "__class__", None)
if c:
name = "%s.%s" % (c.__name__, name)
print "Called from:", name, f.f_lineno
f = f.f_back
print "-" * 70

@ -0,0 +1,11 @@
# July 2002, Graham Fawcett
#
# this hack was inspired by the way Thomas Heller got py2exe
# to appear as a distutil command
#
# we replace distutils.command.build_ext with our own version
# and keep the old one under the module name _build_ext,
# so that *our* build_ext can make use of it.
from build_ext import build_ext
from extension import Extension

@ -0,0 +1,194 @@
"""Pyrex.Distutils.build_ext
Implements a version of the Distutils 'build_ext' command, for
building Pyrex extension modules."""
# This module should be kept compatible with Python 2.1.
__revision__ = "$Id:$"
import sys, os, string, re
from types import *
from distutils.core import Command
from distutils.errors import *
from distutils.sysconfig import customize_compiler, get_python_version
from distutils.dep_util import newer, newer_group
from distutils import log
from distutils.dir_util import mkpath
try:
from Pyrex.Compiler.Main \
import CompilationOptions, \
default_options as pyrex_default_options, \
compile as pyrex_compile
from Pyrex.Compiler.Errors import PyrexError
except ImportError:
PyrexError = None
from distutils.command import build_ext as _build_ext
extension_name_re = _build_ext.extension_name_re
show_compilers = _build_ext.show_compilers
class build_ext(_build_ext.build_ext):
description = "build C/C++ and Pyrex extensions (compile/link to build directory)"
sep_by = _build_ext.build_ext.sep_by
user_options = _build_ext.build_ext.user_options
boolean_options = _build_ext.build_ext.boolean_options
help_options = _build_ext.build_ext.help_options
# Add the pyrex specific data.
user_options.extend([
('pyrex-cplus', None,
"generate C++ source files"),
('pyrex-create-listing', None,
"write errors to a listing file"),
('pyrex-include-dirs=', None,
"path to the Pyrex include files" + sep_by),
('pyrex-c-in-temp', None,
"put generated C files in temp directory"),
('pyrex-gen-pxi', None,
"generate .pxi file for public declarations"),
])
boolean_options.extend([
'pyrex-cplus', 'pyrex-create-listing', 'pyrex-c-in-temp'
])
def initialize_options(self):
_build_ext.build_ext.initialize_options(self)
self.pyrex_cplus = 0
self.pyrex_create_listing = 0
self.pyrex_include_dirs = None
self.pyrex_c_in_temp = 0
self.pyrex_gen_pxi = 0
def finalize_options (self):
_build_ext.build_ext.finalize_options(self)
if self.pyrex_include_dirs is None:
self.pyrex_include_dirs = []
elif type(self.pyrex_include_dirs) is StringType:
self.pyrex_include_dirs = \
string.split(self.pyrex_include_dirs, os.pathsep)
# finalize_options ()
def build_extensions(self):
# First, sanity-check the 'extensions' list
self.check_extensions_list(self.extensions)
for ext in self.extensions:
ext.sources = self.pyrex_sources(ext.sources, ext)
self.build_extension(ext)
def pyrex_sources(self, sources, extension):
"""
Walk the list of source files in 'sources', looking for Pyrex
source (.pyx) files. Run Pyrex on all that are found, and return
a modified 'sources' list with Pyrex source files replaced by the
generated C (or C++) files.
"""
if PyrexError == None:
raise DistutilsPlatformError, \
("Pyrex does not appear to be installed "
"on platform '%s'") % os.name
new_sources = []
pyrex_sources = []
pyrex_targets = {}
# Setup create_list and cplus from the extension options if
# Pyrex.Distutils.extension.Extension is used, otherwise just
# use what was parsed from the command-line or the configuration file.
# cplus will also be set to true is extension.language is equal to
# 'C++' or 'c++'.
#try:
# create_listing = self.pyrex_create_listing or \
# extension.pyrex_create_listing
# cplus = self.pyrex_cplus or \
# extension.pyrex_cplus or \
# (extension.language != None and \
# extension.language.lower() == 'c++')
#except AttributeError:
# create_listing = self.pyrex_create_listing
# cplus = self.pyrex_cplus or \
# (extension.language != None and \
# extension.language.lower() == 'c++')
create_listing = self.pyrex_create_listing or \
getattr(extension, 'pyrex_create_listing', 0)
cplus = self.pyrex_cplus or getattr(extension, 'pyrex_cplus', 0) or \
(extension.language and extension.language.lower() == 'c++')
pyrex_gen_pxi = self.pyrex_gen_pxi or getattr(extension, 'pyrex_gen_pxi', 0)
# Set up the include_path for the Pyres compiler:
# 1. Start with the command line option.
# 2. Add in any (unique) paths from the extension
# pyrex_include_dirs (if Pyrex.Distutils.extension is used).
# 3. Add in any (unique) paths from the extension include_dirs
includes = self.pyrex_include_dirs
try:
for i in extension.pyrex_include_dirs:
if not i in includes:
includes.append(i)
except AttributeError:
pass
for i in extension.include_dirs:
if not i in includes:
includes.append(i)
# Set the target_ext to '.c'. Pyrex will change this to '.cpp' if
# needed.
if cplus:
target_ext = '.cpp'
else:
target_ext = '.c'
# Decide whether to drop the generated C files into the temp dir
# or the source tree.
if not self.inplace and (self.pyrex_c_in_temp
or getattr(extension, 'pyrex_c_in_temp', 0)):
target_dir = os.path.join(self.build_temp, "pyrex")
else:
target_dir = ""
for source in sources:
(base, ext) = os.path.splitext(source)
if ext == ".pyx": # Pyrex source file
new_sources.append(os.path.join(target_dir, base + target_ext))
pyrex_sources.append(source)
pyrex_targets[source] = new_sources[-1]
else:
new_sources.append(source)
if not pyrex_sources:
return new_sources
for source in pyrex_sources:
target = pyrex_targets[source]
# source_time = os.stat(source).st_mtime
# try:
# target_time = os.stat(target).st_mtime
# newer = source_time > target_time
# except EnvironmentError:
# newer = 1
# if newer:
if self.force or newer(source, target):
log.info("pyrexc %s --> %s", source, target)
self.mkpath(os.path.dirname(target))
options = CompilationOptions(pyrex_default_options,
use_listing_file = create_listing,
include_path = includes,
output_file = target,
cplus = cplus,
generate_pxi = pyrex_gen_pxi)
result = pyrex_compile(source, options=options)
return new_sources
# pyrex_sources ()
# class build_ext

@ -0,0 +1,79 @@
"""Pyrex.Distutils.extension
Provides a modified Extension class, that understands hou to describe
Pyrex extension modules in setup scripts."""
__revision__ = "$Id:$"
import os, string, sys
from types import *
import distutils.extension as _Extension
try:
import warnings
except ImportError:
warnings = None
class Extension(_Extension.Extension):
_Extension.Extension.__doc__ + \
"""pyrex_include_dirs : [string]
list of directories to search for Pyrex header files (.pxd) (in
Unix form for portability)
pyrex_create_listing_file : boolean
write pyrex error messages to a listing (.lis) file.
pyrex_cplus : boolean
use the C++ compiler for compiling and linking.
pyrex_c_in_temp : boolean
put generated C files in temp directory.
pyrex_gen_pxi : boolean
generate .pxi file for public declarations
"""
# When adding arguments to this constructor, be sure to update
# user_options.extend in build_ext.py.
def __init__ (self, name, sources,
include_dirs = None,
define_macros = None,
undef_macros = None,
library_dirs = None,
libraries = None,
runtime_library_dirs = None,
extra_objects = None,
extra_compile_args = None,
extra_link_args = None,
export_symbols = None,
#swig_opts = None,
depends = None,
language = None,
pyrex_include_dirs = None,
pyrex_create_listing = 0,
pyrex_cplus = 0,
pyrex_c_in_temp = 0,
pyrex_gen_pxi = 0,
**kw):
_Extension.Extension.__init__(self, name, sources,
include_dirs = include_dirs,
define_macros = define_macros,
undef_macros = undef_macros,
library_dirs = library_dirs,
libraries = libraries,
runtime_library_dirs = runtime_library_dirs,
extra_objects = extra_objects,
extra_compile_args = extra_compile_args,
extra_link_args = extra_link_args,
export_symbols = export_symbols,
#swig_opts = swig_opts,
depends = depends,
language = language,
**kw)
self.pyrex_include_dirs = pyrex_include_dirs or []
self.pyrex_create_listing = pyrex_create_listing
self.pyrex_cplus = pyrex_cplus
self.pyrex_c_in_temp = pyrex_c_in_temp
self.pyrex_gen_pxi = pyrex_gen_pxi
# class Extension
read_setup_file = _Extension.read_setup_file

@ -0,0 +1,22 @@
# July 2002, Graham Fawcett
#
# this hack was inspired by the way Thomas Heller got py2exe
# to appear as a distutil command
#
# we replace distutils.command.build_ext with our own version
# and keep the old one under the module name _build_ext,
# so that *our* build_ext can make use of it.
from build_ext import build_ext

@ -0,0 +1,63 @@
# Subclasses disutils.command.build_ext,
# replacing it with a Pyrex version that compiles pyx->c
# before calling the original build_ext command.
# July 2002, Graham Fawcett
# Modified by Darrell Gallion <dgallion1@yahoo.com>
# to allow inclusion of .c files along with .pyx files.
# Pyrex is (c) Greg Ewing.
import distutils.command.build_ext
#import Pyrex.Compiler.Main
from Pyrex.Compiler.Main import CompilationOptions, default_options, compile
from Pyrex.Compiler.Errors import PyrexError
from distutils.dep_util import newer
import os
import sys
def replace_suffix(path, new_suffix):
return os.path.splitext(path)[0] + new_suffix
class build_ext (distutils.command.build_ext.build_ext):
description = "compile Pyrex scripts, then build C/C++ extensions (compile/link to build directory)"
def finalize_options (self):
distutils.command.build_ext.build_ext.finalize_options(self)
# The following hack should no longer be needed.
if 0:
# compiling with mingw32 gets an "initializer not a constant" error
# doesn't appear to happen with MSVC!
# so if we are compiling with mingw32,
# switch to C++ mode, to avoid the problem
if self.compiler == 'mingw32':
self.swig_cpp = 1
def swig_sources (self, sources, extension = None):
if not self.extensions:
return
# collect the names of the source (.pyx) files
pyx_sources = []
pyx_sources = [source for source in sources if source.endswith('.pyx')]
other_sources = [source for source in sources if not source.endswith('.pyx')]
#suffix = self.swig_cpp and '.cpp' or '.c'
suffix = '.c'
for pyx in pyx_sources:
# should I raise an exception if it doesn't exist?
if os.path.exists(pyx):
source = pyx
target = replace_suffix(source, suffix)
if newer(source, target) or self.force:
self.pyrex_compile(source)
return [replace_suffix(src, suffix) for src in pyx_sources] + other_sources
def pyrex_compile(self, source):
options = CompilationOptions(default_options,
include_path = self.include_dirs)
result = compile(source, options)
if result.num_errors <> 0:
sys.exit(1)

@ -0,0 +1,85 @@
#
# Pyrex - Darwin system interface
#
verbose = 0
gcc_pendantic = False
gcc_no_long_long = True
gcc_warnings_are_errors = True
gcc_all_warnings = True
gcc_optimize = False
import os, sys
from Pyrex.Utils import replace_suffix
from Pyrex.Compiler.Errors import PyrexError
version_string = "%s.%s" % sys.version_info[:2]
py_include_dirs = [
"/Library/Frameworks/Python.framework/Versions/%s/Headers" % version_string
]
compilers = ["gcc", "g++"]
compiler_options = \
"-g -c -fno-strict-aliasing -Wno-long-double -no-cpp-precomp " \
"-mno-fused-madd -fno-common -dynamic " \
.split()
if gcc_pendantic:
compiler_options.append("-pedantic")
if gcc_no_long_long:
compiler_options.append("-Wno-long-long")
if gcc_warnings_are_errors:
compiler_options.append("-Werror")
if gcc_all_warnings:
compiler_options.append("-Wall")
compiler_options.append("-Wno-unused-function")
if gcc_optimize:
compiler_options.append("-O")
linkers = ["gcc", "g++"]
linker_options = \
"-Wl,-F.,-w -bundle -undefined dynamic_lookup" \
.split()
#linker_options = \
# "-Wl,-F.,-w -bundle -framework Python" \
# .split()
class CCompilerError(PyrexError):
pass
def c_compile(c_file, verbose_flag = 0, cplus = 0, obj_suffix = ".o"):
# Compile the given C source file to produce
# an object file. Returns the pathname of the
# resulting file.
c_file = os.path.join(os.getcwd(), c_file)
o_file = replace_suffix(c_file, obj_suffix)
include_options = []
for dir in py_include_dirs:
include_options.append("-I%s" % dir)
compiler = compilers[bool(cplus)]
args = [compiler] + compiler_options + include_options + [c_file, "-o", o_file]
if verbose_flag or verbose:
print " ".join(args)
#print compiler, args ###
status = os.spawnvp(os.P_WAIT, compiler, args)
if status <> 0:
raise CCompilerError("C compiler returned status %s" % status)
return o_file
def c_link(obj_file, verbose_flag = 0, extra_objects = [], cplus = 0):
return c_link_list([obj_file] + extra_objects, verbose_flag, cplus)
def c_link_list(obj_files, verbose_flag = 0, cplus = 0):
# Link the given object files into a dynamically
# loadable extension file. Returns the pathname
# of the resulting file.
os.environ["MACOSX_DEPLOYMENT_TARGET"] = "10.3"
out_file = replace_suffix(obj_files[0], ".so")
linker = linkers[bool(cplus)]
args = [linker] + linker_options + obj_files + ["-o", out_file]
if verbose_flag or verbose:
print " ".join(args)
status = os.spawnvp(os.P_WAIT, linker, args)
if status <> 0:
raise CCompilerError("Linker returned status %s" % status)
return out_file

@ -0,0 +1,135 @@
#
# Pyrex -- Mac system interface
#
import os, sys, string
import aetools
from aetools import TalkTo
from StdSuites.Standard_Suite import Standard_Suite_Events as Standard_Suite
from Pyrex.Utils import replace_suffix
from Pyrex.Compiler.Errors import PyrexError
c_compiler = "MWCPPC"
c_optimizations = "off"
#c_linker = "PPCLink"
c_linker = "MWLinkPPC"
shared_lib_suffix = ".slb"
#py_home = "Python2.2:Home:"
py_home = sys.exec_prefix
py_include_dirs = (
py_home + "Include:",
py_home + "Mac:Include:"
)
pythoncore = py_home + "PythonCore"
mwlibdir = "MPW:Interfaces&Libraries:Libraries:MWPPCLibraries:"
libraries = (
#mwlibdir + "'MSL C.PPC.Lib'",
#mwlibdir + "'MSL RuntimePPC.Lib'",
mwlibdir + "'MSL ShLibRuntime.Lib'",
mwlibdir + "InterfaceLib",
#mwlibdir + "MathLib",
)
class CCompilerError(PyrexError):
pass
#---------------- ToolServer ---------------------------
from TS_Misc_Suite import TS_Misc_Suite
class ToolServer(Standard_Suite, TS_Misc_Suite, TalkTo):
pass
def send_toolserver_command(cmd):
ts = ToolServer('MPSX', start = 1)
return ts.DoScript(cmd)
def do_toolserver_command(command):
try:
result = send_toolserver_command(command)
except aetools.Error, e:
raise CCompilerError("Apple Event error: %s" % e)
errn, stat, stdout, stderr = result
if errn:
raise CCompilerError("ToolServer error: %s" % errn)
stdout = string.replace(stdout, "\r", "\n")
stderr = string.replace(stderr, "\r", "\n")
if stdout:
#print "<<< Begin ToolServer StdOut >>>"
sys.stderr.write(stdout)
#print "<<< End ToolServer StdOut >>>"
if stderr:
#print "<<< Begin ToolServer StdErr >>>"
sys.stderr.write(stderr)
#print "<<< End ToolServer StdErr >>>"
return stat
#-------------------------------------------------------
def c_compile(c_file):
# Compile the given C source file to produce
# an object file. Returns the pathname of the
# resulting file.
c_file = os.path.join(os.getcwd(), c_file)
#print "c_compile: c_file =", repr(c_file) ###
c_file_dir = os.path.dirname(c_file)
o_file = replace_suffix(c_file, ".o")
include_options = ["-i %s" % c_file_dir]
for dir in py_include_dirs:
include_options.append("-i %s" % dir)
command = "%s -opt %s -nomapcr -w off -r %s %s -o %s" % (
c_compiler,
c_optimizations,
string.join(include_options),
c_file,
o_file,
#e_file
)
#print "...command =", repr(command) ###
stat = do_toolserver_command(command)
if stat:
raise CCompilerError("C compiler returned status %s" % stat)
return o_file
def c_link(obj_file):
return c_link_list([obj_file])
def c_link_list(obj_files):
# Link the given object files into a dynamically
# loadable extension file. Returns the pathname
# of the resulting file.
out_file = replace_suffix(obj_files[0], shared_lib_suffix)
command = "%s -xm s -export all %s %s %s -o %s" % (
c_linker,
string.join(obj_files),
pythoncore,
string.join(libraries),
out_file)
stat = do_toolserver_command(command)
if stat:
raise CCompilerError("Linker returned status %s" % stat)
return out_file
def test_c_compile(link = 0):
objs = []
for arg in sys.argv[1:]:
if arg.endswith(".c"):
try:
obj = c_compile(arg)
except PyrexError, e:
#print "Caught a PyrexError:" ###
#print repr(e) ###
print "%s.%s:" % (e.__class__.__module__,
e.__class__.__name__), e
sys.exit(1)
else:
obj = arg
objs.append(obj)
if link:
c_link_list(objs)

@ -0,0 +1,34 @@
#
# Pyrex -- Misc Mac-specific things
#
import os, MacOS, macfs
def open_new_file(path):
# On the Mac, try to preserve Finder position
# of previously existing file.
fsspec = macfs.FSSpec(path)
try:
old_finfo = fsspec.GetFInfo()
except MacOS.Error, e:
#print "MacUtils.open_new_file:", e ###
old_finfo = None
try:
os.unlink(path)
except OSError:
pass
file = open(path, "w")
new_finfo = fsspec.GetFInfo()
if old_finfo:
#print "MacUtils.open_new_file:", path ###
#print "...old file info =", old_finfo.Creator, old_finfo.Type, old_finfo.Location ###
#print "...new file info =", new_finfo.Creator, new_finfo.Type, new_finfo.Location ###
new_finfo.Location = old_finfo.Location
new_finfo.Flags = old_finfo.Flags
# Make darn sure the type and creator are right. There seems
# to be a bug in MacPython 2.2 that screws them up sometimes.
new_finfo.Creator = "R*ch"
new_finfo.Type = "TEXT"
fsspec.SetFInfo(new_finfo)
return file

@ -0,0 +1,24 @@
# Makefile for Darwin
# Change this to your Python source location
PYTHON := /Local/Build/Pythonic/python/2.6.1
# Version 2.3:
#DYNOPT := -framework Python
# Version 2.4+:
DYNOPT := -undefined dynamic_lookup
INCLUDE := -I$(PYTHON) -I$(PYTHON)/Include -I$(PYTHON)/Mac/Include
CCOPTS := -fno-strict-aliasing -Wno-long-double -no-cpp-precomp \
-mno-fused-madd -fno-common -dynamic
LDOPTS := -Wl,-F.,-w -bundle $(DYNOPT) -framework Carbon
all: _File.so
_File.o: _Filemodule_patched.c
gcc -c $(INCLUDE) $(OPTS) $< -o $@
_File.so: _File.o
gcc $(LDOPTS) $< -o $@

@ -0,0 +1,64 @@
"""Suite Misc Suite: Suite that adds additional features to the Application.
Level 1, version 1
Generated from Macintosh HD:Desktop Folder:ToolServer 3.4.1:ToolServer
AETE/AEUT resource version 1/0, language 0, script 0
"""
import aetools
import MacOS
_code = 'misc'
class TS_Misc_Suite:
def DoScript(self, _object, _attributes={}, **_arguments):
"""DoScript: Execute an MPW command, any command that could be executed from the command line can be sent as a script.
Required argument: The script to execute
Keyword argument _attributes: AppleEvent attribute dictionary
"""
_code = 'misc'
_subcode = 'dosc'
if _arguments: raise TypeError, 'No optional args expected'
_arguments['----'] = _object
_reply, _arguments, _attributes = self.send(_code, _subcode,
_arguments, _attributes)
#if _arguments.has_key('errn'):
# raise aetools.Error, aetools.decodeerror(_arguments)
# XXXX Optionally decode result
#if _arguments.has_key('----'):
# return _arguments['----']
errn = 0
stat = 0
stdout = ""
stderr = ""
if _arguments.has_key('errn'):
errn = _arguments['errn']
if errn:
errn = aetools.decodeerror(_arguments)
if _arguments.has_key('stat'):
stat = _arguments['stat']
if _arguments.has_key('----'):
stdout = _arguments['----']
if _arguments.has_key('diag'):
stderr = _arguments['diag']
return (errn, stat, stdout, stderr)
#
# Indices of types declared in this module
#
_classdeclarations = {
}
_propdeclarations = {
}
_compdeclarations = {
}
_enumdeclarations = {
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,135 @@
/***********************************************************
Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
The Netherlands.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
#ifndef Py_MACGLUE_H
#define Py_MACGLUE_H
#ifdef WITHOUT_FRAMEWORKS
#include <Types.h>
#include <Files.h>
#include <Events.h>
#include <StandardFile.h>
#else
#include <Carbon/Carbon.h>
#endif
#include "pymactoolbox.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Scheduler parameters */
typedef struct {
int check_interrupt; /* if true check for command-dot */
int process_events; /* if nonzero enable evt processing, this mask */
int besocial; /* Be social, give up CPU now and again */
double check_interval; /* how often to check */
double bg_yield; /* yield at most so long when in background */
} PyMacSchedParams;
unsigned char *Pstring(char *str); /* Convert c-string to pascal-string in static buffer */
#ifdef USE_GUSI
extern int PyMac_ConsoleIsDead; /* True when exiting */
extern void PyMac_StopGUSISpin(void); /* Stop eventprocessing during exit() */
#endif
extern short PyMac_AppRefNum; /* RefNum of application rsrcfork (from macmain.c) */
extern FSSpec PyMac_ApplicationFSSpec; /* Application location (from macargv.c) */
extern char PyMac_ApplicationPath[]; /* Application location (from macargv.c) */
extern OSErr PyMac_init_application_location(void); /* Init the above */
extern int PyMac_GetArgv(char ***, int); /* Get argc, argv (from macargv.c) */
extern PyObject *PyMac_OSErrException; /* Exception for OSErr */
PyObject *PyMac_GetOSErrException(void); /* Initialize & return it */
#if !TARGET_API_MAC_OSX
void PyMac_GetSchedParams(PyMacSchedParams *); /* Get schedulers params */
void PyMac_SetSchedParams(PyMacSchedParams *); /* Set schedulers params */
int PyMac_DoYield(int, int); /* Yield cpu. First arg is maxtime, second ok to call python */
#endif
int PyMac_HandleEvent(EventRecord *); /* Handle one event, possibly in Python */
void PyMac_HandleEventIntern(EventRecord *); /* Handle one event internal only */
int PyMac_SetEventHandler(PyObject *); /* set python-coded event handler */
#if !TARGET_API_MAC_OSX
void PyMac_InitMenuBar(void); /* Setup menu bar as we want it */
void PyMac_RestoreMenuBar(void); /* Restore menu bar for ease of exiting */
void PyMac_RaiseConsoleWindow(); /* Bring console window to front, if it exists */
#endif
int PyMac_FindResourceModule(PyStringObject *, char *, char *); /* Test for 'PYC ' resource in a file */
PyObject * PyMac_LoadResourceModule(char *, char *); /* Load 'PYC ' resource from file */
int PyMac_FindCodeResourceModule(PyStringObject *, char *, char *); /* Test for 'PYD ' resource in a file */
PyObject * PyMac_LoadCodeResourceModule(char *, char *); /* Load 'PYD ' resource from file */
struct filedescr *PyMac_FindModuleExtension(char *, size_t *, char *); /* Look for module in single folder */
void PyMac_InitApplet(void); /* Initialize and run an Applet */
void PyMac_Initialize(void); /* Initialize function for embedding Python */
#ifdef USE_GUSI2
short PyMac_OpenPrefFile(void); /* From macgetpath.c, open and return preference file */
#endif
/* From macfiletype.c: */
long PyMac_getfiletype(char *); /* Get file type */
int PyMac_setfiletype(char *, long, long); /* Set file creator and type */
/* from macmain.c: */
void PyMac_Exit(int);
void PyMac_InitApplication(void);
void PyMac_OutputSeen(void);
void PyMac_OutputNotSeen(void);
int PyMac_GetDelayConsoleFlag(void);
#ifdef USE_MAC_APPLET_SUPPORT
void PyMac_InitApplet(void);
#endif
/* from macgetargv: */
OSErr PyMac_init_process_location(void);
char * strdup(const char *str);
#ifdef USE_GUSI2
/* from pyGUSISIOUX.cp */
typedef long (*PyWriteHandler)(char *buffer, long n);
typedef long (*PyReadHandler)(char *buffer, long n);
/* Override routines that normally reads and writes to the
** SIOUX console window. Intended for embedding applications
** that want to forestall a Python console window ever showing up.
*/
void PyMac_SetConsoleHandler(PyReadHandler stdinH, PyWriteHandler stdoutH,
PyWriteHandler stderrH);
/* Courtesy console handlers that drop all output and return
** 0 on reads.
*/
long PyMac_DummyReadHandler(char *, long);
long PyMac_DummyWriteHandler(char *, long);
#endif /* USE_GUSI2 */
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,12 @@
#
# Setup file for compiling _Filemodule_patched.c
#
from distutils.core import setup
from distutils.extension import Extension
setup(
ext_modules = [
Extension("_File", ["_Filemodule_patched.c"])
]
)

@ -0,0 +1,109 @@
#=======================================================================
#
# Python Lexical Analyser
#
# Actions for use in token specifications
#
#=======================================================================
class Action:
def same_as(self, other):
return self is other
class Return(Action):
"""
Internal Plex action which causes |value| to
be returned as the value of the associated token
"""
value = None
def __init__(self, value):
self.value = value
def perform(self, token_stream, text):
return self.value
def same_as(self, other):
return isinstance(other, Return) and self.value == other.value
def __repr__(self):
return "Return(%s)" % repr(self.value)
class Call(Action):
"""
Internal Plex action which causes a function to be called.
"""
function = None
def __init__(self, function):
self.function = function
def perform(self, token_stream, text):
return self.function(token_stream, text)
def __repr__(self):
return "Call(%s)" % self.function.__name__
def same_as(self, other):
return isinstance(other, Call) and self.function is other.function
class Begin(Action):
"""
Begin(state_name) is a Plex action which causes the Scanner to
enter the state |state_name|. See the docstring of Plex.Lexicon
for more information.
"""
state_name = None
def __init__(self, state_name):
self.state_name = state_name
def perform(self, token_stream, text):
token_stream.begin(self.state_name)
def __repr__(self):
return "Begin(%s)" % self.state_name
def same_as(self, other):
return isinstance(other, Begin) and self.state_name == other.state_name
class Ignore(Action):
"""
IGNORE is a Plex action which causes its associated token
to be ignored. See the docstring of Plex.Lexicon for more
information.
"""
def perform(self, token_stream, text):
return None
def __repr__(self):
return "IGNORE"
IGNORE = Ignore()
IGNORE.__doc__ = Ignore.__doc__
class Text(Action):
"""
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.
"""
def perform(self, token_stream, text):
return text
def __repr__(self):
return "TEXT"
TEXT = Text()
TEXT.__doc__ = Text.__doc__

@ -0,0 +1,156 @@
#=======================================================================
#
# Python Lexical Analyser
#
# Converting NFA to DFA
#
#=======================================================================
import Machines
from Machines import LOWEST_PRIORITY
from Transitions import TransitionMap
def nfa_to_dfa(old_machine, debug = None):
"""
Given a nondeterministic Machine, return a new equivalent
Machine which is deterministic.
"""
# We build a new machine whose states correspond to sets of states
# in the old machine. Initially we add a new state corresponding to
# the epsilon-closure of each initial old state. Then we give transitions
# to each new state which are the union of all transitions out of any
# of the corresponding old states. The new state reached on a given
# character is the one corresponding to the set of states reachable
# on that character from any of the old states. As new combinations of
# old states are created, new states are added as needed until closure
# is reached.
new_machine = Machines.FastMachine()
state_map = StateMap(new_machine)
# Seed the process using the initial states of the old machine.
# Make the corresponding new states into initial states of the new
# machine with the same names.
for (key, old_state) in old_machine.initial_states.items():
new_state = state_map.old_to_new(epsilon_closure(old_state))
new_machine.make_initial_state(key, new_state)
# Tricky bit here: we add things to the end of this list while we're
# iterating over it. The iteration stops when closure is achieved.
for new_state in new_machine.states:
transitions = TransitionMap()
for old_state in state_map.new_to_old(new_state).keys():
for event, old_target_states in old_state.transitions.items():
if event and old_target_states:
transitions.add_set(event, set_epsilon_closure(old_target_states))
for event, old_states in transitions.items():
new_machine.add_transitions(new_state, event, state_map.old_to_new(old_states))
if debug:
debug.write("\n===== State Mapping =====\n")
state_map.dump(debug)
return new_machine
def set_epsilon_closure(state_set):
"""
Given a set of states, return the union of the epsilon
closures of its member states.
"""
result = {}
for state1 in state_set.keys():
for state2 in epsilon_closure(state1).keys():
result[state2] = 1
return result
def epsilon_closure(state):
"""
Return the set of states reachable from the given state
by epsilon moves.
"""
# Cache the result
result = state.epsilon_closure
if result is None:
result = {}
state.epsilon_closure = result
add_to_epsilon_closure(result, state)
return result
def add_to_epsilon_closure(state_set, state):
"""
Recursively add to |state_set| states reachable from the given state
by epsilon moves.
"""
if not state_set.get(state, 0):
state_set[state] = 1
state_set_2 = state.transitions.get_epsilon()
if state_set_2:
for state2 in state_set_2.keys():
add_to_epsilon_closure(state_set, state2)
class StateMap:
"""
Helper class used by nfa_to_dfa() to map back and forth between
sets of states from the old machine and states of the new machine.
"""
new_machine = None # Machine
old_to_new_dict = None # {(old_state,...) : new_state}
new_to_old_dict = None # {id(new_state) : old_state_set}
def __init__(self, new_machine):
self.new_machine = new_machine
self.old_to_new_dict = {}
self.new_to_old_dict= {}
def old_to_new(self, old_state_set):
"""
Return the state of the new machine corresponding to the
set of old machine states represented by |state_set|. A new
state will be created if necessary. If any of the old states
are accepting states, the new state will be an accepting state
with the highest priority action from the old states.
"""
key = self.make_key(old_state_set)
new_state = self.old_to_new_dict.get(key, None)
if not new_state:
action = self.highest_priority_action(old_state_set)
new_state = self.new_machine.new_state(action)
self.old_to_new_dict[key] = new_state
self.new_to_old_dict[id(new_state)] = old_state_set
#for old_state in old_state_set.keys():
#new_state.merge_actions(old_state)
return new_state
def highest_priority_action(self, state_set):
best_action = None
best_priority = LOWEST_PRIORITY
for state in state_set.keys():
priority = state.action_priority
if priority > best_priority:
best_action = state.action
best_priority = priority
return best_action
# def old_to_new_set(self, old_state_set):
# """
# Return the new state corresponding to a set of old states as
# a singleton set.
# """
# return {self.old_to_new(old_state_set):1}
def new_to_old(self, new_state):
"""Given a new state, return a set of corresponding old states."""
return self.new_to_old_dict[id(new_state)]
def make_key(self, state_set):
"""
Convert a set of states into a uniquified
sorted tuple suitable for use as a dictionary key.
"""
lst = state_set.keys()
lst.sort()
return tuple(lst)
def dump(self, file):
from Transitions import state_set_str
for new_state in self.new_machine.states:
old_state_set = self.new_to_old_dict[id(new_state)]
file.write(" State %s <-- %s\n" % (
new_state['number'], state_set_str(old_state_set)))

@ -0,0 +1,52 @@
#=======================================================================
#
# Python Lexical Analyser
#
# Exception classes
#
#=======================================================================
import exceptions
class PlexError(exceptions.Exception):
message = ""
class PlexTypeError(PlexError, TypeError):
pass
class PlexValueError(PlexError, ValueError):
pass
class InvalidRegex(PlexError):
pass
class InvalidToken(PlexError):
def __init__(self, token_number, message):
PlexError.__init__(self, "Token number %d: %s" % (token_number, message))
class InvalidScanner(PlexError):
pass
class AmbiguousAction(PlexError):
message = "Two tokens with different actions can match the same string"
def __init__(self):
pass
class UnrecognizedInput(PlexError):
scanner = None
position = None
state_name = None
def __init__(self, scanner, state_name):
self.scanner = scanner
self.position = scanner.position()
self.state_name = state_name
def __str__(self):
return ("'%s', line %d, char %d: Token not recognised in state %s"
% (self.position + (repr(self.state_name),)))

@ -0,0 +1,192 @@
#=======================================================================
#
# Python Lexical Analyser
#
# Lexical Analyser Specification
#
#=======================================================================
import types
import Actions
import DFA
import Errors
import Machines
import Regexps
# debug_flags for Lexicon constructor
DUMP_NFA = 1
DUMP_DFA = 2
class State:
"""
This class is used as part of a Plex.Lexicon specification to
introduce a user-defined state.
Constructor:
State(name, token_specifications)
"""
name = None
tokens = None
def __init__(self, name, tokens):
self.name = name
self.tokens = tokens
class Lexicon:
"""
Lexicon(specification) builds a lexical analyser from the given
|specification|. The specification consists of a list of
specification items. Each specification item may be either:
1) A token definition, which is a tuple:
(pattern, action)
The |pattern| is a regular axpression built using the
constructors defined in the Plex module.
The |action| is the action to be performed when this pattern
is recognised (see below).
2) A state definition:
State(name, tokens)
where |name| is a character string naming the state,
and |tokens| is a list of token definitions as
above. The meaning and usage of states is described
below.
Actions
-------
The |action| in a token specication may be one of three things:
1) A function, which is called as follows:
function(scanner, text)
where |scanner| is the relevant Scanner instance, and |text|
is the matched text. If the function returns anything
other than None, that value is returned as the value of the
token. If it returns None, scanning continues as if the IGNORE
action were specified (see below).
2) One of the following special actions:
IGNORE means that the recognised characters will be treated as
white space and ignored. Scanning will continue until
the next non-ignored token is recognised before returning.
TEXT causes the scanned text itself to be returned as the
value of the token.
3) Any other value, which is returned as the value of the token.
States
------
At any given time, the scanner is in one of a number of states.
Associated with each state is a set of possible tokens. When scanning,
only tokens associated with the current state are recognised.
There is a default state, whose name is the empty string. Token
definitions which are not inside any State definition belong to
the default state.
The initial state of the scanner is the default state. The state can
be changed in one of two ways:
1) Using Begin(state_name) as the action of a token.
2) Calling the begin(state_name) method of the Scanner.
To change back to the default state, use '' as the state name.
"""
machine = None # Machine
tables = None # StateTableMachine
def __init__(self, specifications, debug = None, debug_flags = 7, timings = None):
if type(specifications) <> types.ListType:
raise Errors.InvalidScanner("Scanner definition is not a list")
if timings:
from Timing import time
total_time = 0.0
time1 = time()
nfa = Machines.Machine()
default_initial_state = nfa.new_initial_state('')
token_number = 1
for spec in specifications:
if isinstance(spec, State):
user_initial_state = nfa.new_initial_state(spec.name)
for token in spec.tokens:
self.add_token_to_machine(
nfa, user_initial_state, token, token_number)
token_number = token_number + 1
elif type(spec) == types.TupleType:
self.add_token_to_machine(
nfa, default_initial_state, spec, token_number)
token_number = token_number + 1
else:
raise Errors.InvalidToken(
token_number,
"Expected a token definition (tuple) or State instance")
if timings:
time2 = time()
total_time = total_time + (time2 - time1)
time3 = time()
if debug and (debug_flags & 1):
debug.write("\n============= NFA ===========\n")
nfa.dump(debug)
dfa = DFA.nfa_to_dfa(nfa, debug = (debug_flags & 3) == 3 and debug)
if timings:
time4 = time()
total_time = total_time + (time4 - time3)
if debug and (debug_flags & 2):
debug.write("\n============= DFA ===========\n")
dfa.dump(debug)
if timings:
timings.write("Constructing NFA : %5.2f\n" % (time2 - time1))
timings.write("Converting to DFA: %5.2f\n" % (time4 - time3))
timings.write("TOTAL : %5.2f\n" % total_time)
self.machine = dfa
def add_token_to_machine(self, machine, initial_state, token_spec, token_number):
try:
(re, action_spec) = self.parse_token_definition(token_spec)
# Disabled this -- matching empty strings can be useful
#if re.nullable:
# raise Errors.InvalidToken(
# token_number, "Pattern can match 0 input symbols")
if isinstance(action_spec, Actions.Action):
action = action_spec
elif callable(action_spec):
action = Actions.Call(action_spec)
else:
action = Actions.Return(action_spec)
final_state = machine.new_state()
re.build_machine(machine, initial_state, final_state,
match_bol = 1, nocase = 0)
final_state.set_action(action, priority = -token_number)
except Errors.PlexError, e:
raise e.__class__("Token number %d: %s" % (token_number, e))
def parse_token_definition(self, token_spec):
if type(token_spec) <> types.TupleType:
raise Errors.InvalidToken("Token definition is not a tuple")
if len(token_spec) <> 2:
raise Errors.InvalidToken("Wrong number of items in token definition")
pattern, action = token_spec
if not isinstance(pattern, Regexps.RE):
raise Errors.InvalidToken("Pattern is not an RE instance")
return (pattern, action)
def get_initial_state(self, name):
return self.machine.get_initial_state(name)

@ -0,0 +1,326 @@
#=======================================================================
#
# Python Lexical Analyser
#
# Classes for building NFAs and DFAs
#
#=======================================================================
import string
import sys
from sys import maxint
from types import TupleType
from Transitions import TransitionMap
LOWEST_PRIORITY = -sys.maxint
class Machine:
"""A collection of Nodes representing an NFA or DFA."""
states = None # [Node]
next_state_number = 1
initial_states = None # {(name, bol): Node}
def __init__(self):
self.states = []
self.initial_states = {}
def __del__(self):
#print "Destroying", self ###
for state in self.states:
state.destroy()
def new_state(self):
"""Add a new state to the machine and return it."""
s = Node()
n = self.next_state_number
self.next_state_number = n + 1
s.number = n
self.states.append(s)
return s
def new_initial_state(self, name):
state = self.new_state()
self.make_initial_state(name, state)
return state
def make_initial_state(self, name, state):
self.initial_states[name] = state
def get_initial_state(self, name):
return self.initial_states[name]
def dump(self, file):
file.write("Plex.Machine:\n")
if self.initial_states is not None:
file.write(" Initial states:\n")
for (name, state) in self.initial_states.items():
file.write(" '%s': %d\n" % (name, state.number))
for s in self.states:
s.dump(file)
class Node:
"""A state of an NFA or DFA."""
transitions = None # TransitionMap
action = None # Action
action_priority = None # integer
number = 0 # for debug output
epsilon_closure = None # used by nfa_to_dfa()
def __init__(self):
# Preinitialise the list of empty transitions, because
# the nfa-to-dfa algorithm needs it
#self.transitions = {'':[]}
self.transitions = TransitionMap()
self.action_priority = LOWEST_PRIORITY
def destroy(self):
#print "Destroying", self ###
self.transitions = None
self.action = None
self.epsilon_closure = None
def add_transition(self, event, new_state):
self.transitions.add(event, new_state)
def link_to(self, state):
"""Add an epsilon-move from this state to another state."""
self.add_transition('', state)
def set_action(self, action, priority):
"""Make this an accepting state with the given action. If
there is already an action, choose the action with highest
priority."""
if priority > self.action_priority:
self.action = action
self.action_priority = priority
def get_action(self):
return self.action
def get_action_priority(self):
return self.action_priority
# def merge_actions(self, other_state):
# """Merge actions of other state into this state according
# to their priorities."""
# action = other_state.get_action()
# priority = other_state.get_action_priority()
# self.set_action(action, priority)
def is_accepting(self):
return self.action is not None
def __str__(self):
return "State %d" % self.number
def dump(self, file):
import string
# Header
file.write(" State %d:\n" % self.number)
# Transitions
# self.dump_transitions(file)
self.transitions.dump(file)
# Action
action = self.action
priority = self.action_priority
if action is not None:
file.write(" %s [priority %d]\n" % (action, priority))
class FastMachine:
"""
FastMachine is a deterministic machine represented in a way that
allows fast scanning.
"""
initial_states = None # {state_name:state}
states = None # [state]
# where state = {event:state, 'else':state, 'action':Action}
next_number = 1 # for debugging
new_state_template = {
'':None, 'bol':None, 'eol':None, 'eof':None, 'else':None
}
def __init__(self, old_machine = None):
self.initial_states = initial_states = {}
self.states = []
if old_machine:
self.old_to_new = old_to_new = {}
for old_state in old_machine.states:
new_state = self.new_state()
old_to_new[old_state] = new_state
for name, old_state in old_machine.initial_states.items():
initial_states[name] = old_to_new[old_state]
for old_state in old_machine.states:
new_state = old_to_new[old_state]
for event, old_state_set in old_state.transitions.items():
if old_state_set:
new_state[event] = old_to_new[old_state_set.keys()[0]]
else:
new_state[event] = None
new_state['action'] = old_state.action
def __del__(self):
for state in self.states:
state.clear()
def new_state(self, action = None):
number = self.next_number
self.next_number = number + 1
result = self.new_state_template.copy()
result['number'] = number
result['action'] = action
self.states.append(result)
return result
def make_initial_state(self, name, state):
self.initial_states[name] = state
def add_transitions(self, state, event, new_state):
if type(event) == TupleType:
code0, code1 = event
if code0 == -maxint:
state['else'] = new_state
elif code1 <> maxint:
while code0 < code1:
state[chr(code0)] = new_state
code0 = code0 + 1
else:
state[event] = new_state
def get_initial_state(self, name):
return self.initial_states[name]
def dump(self, file):
file.write("Plex.FastMachine:\n")
file.write(" Initial states:\n")
for name, state in self.initial_states.items():
file.write(" %s: %s\n" % (repr(name), state['number']))
for state in self.states:
self.dump_state(state, file)
def dump_state(self, state, file):
import string
# Header
file.write(" State %d:\n" % state['number'])
# Transitions
self.dump_transitions(state, file)
# Action
action = state['action']
if action is not None:
file.write(" %s\n" % action)
def dump_transitions(self, state, file):
chars_leading_to_state = {}
special_to_state = {}
for (c, s) in state.items():
if len(c) == 1:
chars = chars_leading_to_state.get(id(s), None)
if chars is None:
chars = []
chars_leading_to_state[id(s)] = chars
chars.append(c)
elif len(c) <= 4:
special_to_state[c] = s
ranges_to_state = {}
for state in self.states:
char_list = chars_leading_to_state.get(id(state), None)
if char_list:
ranges = self.chars_to_ranges(char_list)
ranges_to_state[ranges] = state
ranges_list = ranges_to_state.keys()
ranges_list.sort()
for ranges in ranges_list:
key = self.ranges_to_string(ranges)
state = ranges_to_state[ranges]
file.write(" %s --> State %d\n" % (key, state['number']))
for key in ('bol', 'eol', 'eof', 'else'):
state = special_to_state.get(key, None)
if state:
file.write(" %s --> State %d\n" % (key, state['number']))
def chars_to_ranges(self, char_list):
char_list.sort()
i = 0
n = len(char_list)
result = []
while i < n:
c1 = ord(char_list[i])
c2 = c1
i = i + 1
while i < n and ord(char_list[i]) == c2 + 1:
i = i + 1
c2 = c2 + 1
result.append((chr(c1), chr(c2)))
return tuple(result)
def ranges_to_string(self, range_list):
return string.join(map(self.range_to_string, range_list), ",")
def range_to_string(self, (c1, c2)):
if c1 == c2:
return repr(c1)
else:
return "%s..%s" % (repr(c1), repr(c2))
##
## (Superseded by Machines.FastMachine)
##
## class StateTableMachine:
## """
## StateTableMachine is an alternative representation of a Machine
## that can be run more efficiently.
## """
## initial_states = None # {state_name:state_index}
## states = None # [([state] indexed by char code, Action)]
## special_map = {'bol':256, 'eol':257, 'eof':258}
## def __init__(self, m):
## """
## Initialise StateTableMachine from Machine |m|.
## """
## initial_states = self.initial_states = {}
## states = self.states = [None]
## old_to_new = {}
## i = 1
## for old_state in m.states:
## new_state = ([0] * 259, old_state.get_action())
## states.append(new_state)
## old_to_new[old_state] = i # new_state
## i = i + 1
## for name, old_state in m.initial_states.items():
## initial_states[name] = old_to_new[old_state]
## for old_state in m.states:
## new_state_index = old_to_new[old_state]
## new_table = states[new_state_index][0]
## transitions = old_state.transitions
## for c, old_targets in transitions.items():
## if old_targets:
## old_target = old_targets[0]
## new_target_index = old_to_new[old_target]
## if len(c) == 1:
## a = ord(c)
## else:
## a = self.special_map[c]
## new_table[a] = states[new_target_index]
## def dump(self, f):
## f.write("Plex.StateTableMachine:\n")
## f.write(" Initial states:\n")
## for name, index in self.initial_states.items():
## f.write(" %s: State %d\n" % (
## repr(name), id(self.states[index])))
## for i in xrange(1, len(self.states)):
## table, action = self.states[i]
## f.write(" State %d:" % i)
## if action:
## f.write("%s" % action)
## f.write("\n")
## f.write(" %s\n" % map(id,table))

@ -0,0 +1,557 @@
#=======================================================================
#
# Python Lexical Analyser
#
# Regular Expressions
#
#=======================================================================
import array
import string
import types
from sys import maxint
import Errors
#
# Constants
#
BOL = 'bol'
EOL = 'eol'
EOF = 'eof'
nl_code = ord('\n')
#
# Helper functions
#
def chars_to_ranges(s):
"""
Return a list of character codes consisting of pairs
[code1a, code1b, code2a, code2b,...] which cover all
the characters in |s|.
"""
char_list = list(s)
char_list.sort()
i = 0
n = len(char_list)
result = []
while i < n:
code1 = ord(char_list[i])
code2 = code1 + 1
i = i + 1
while i < n and code2 >= ord(char_list[i]):
code2 = code2 + 1
i = i + 1
result.append(code1)
result.append(code2)
return result
def uppercase_range(code1, code2):
"""
If the range of characters from code1 to code2-1 includes any
lower case letters, return the corresponding upper case range.
"""
code3 = max(code1, ord('a'))
code4 = min(code2, ord('z') + 1)
if code3 < code4:
d = ord('A') - ord('a')
return (code3 + d, code4 + d)
else:
return None
def lowercase_range(code1, code2):
"""
If the range of characters from code1 to code2-1 includes any
upper case letters, return the corresponding lower case range.
"""
code3 = max(code1, ord('A'))
code4 = min(code2, ord('Z') + 1)
if code3 < code4:
d = ord('a') - ord('A')
return (code3 + d, code4 + d)
else:
return None
def CodeRanges(code_list):
"""
Given a list of codes as returned by chars_to_ranges, return
an RE which will match a character in any of the ranges.
"""
re_list = []
for i in xrange(0, len(code_list), 2):
re_list.append(CodeRange(code_list[i], code_list[i + 1]))
return apply(Alt, tuple(re_list))
def CodeRange(code1, code2):
"""
CodeRange(code1, code2) is an RE which matches any character
with a code |c| in the range |code1| <= |c| < |code2|.
"""
if code1 <= nl_code < code2:
return Alt(RawCodeRange(code1, nl_code),
RawNewline,
RawCodeRange(nl_code + 1, code2))
else:
return RawCodeRange(code1, code2)
#
# Abstract classes
#
class RE:
"""RE is the base class for regular expression constructors.
The following operators are defined on REs:
re1 + re2 is an RE which matches |re1| followed by |re2|
re1 | re2 is an RE which matches either |re1| or |re2|
"""
nullable = 1 # True if this RE can match 0 input symbols
match_nl = 1 # True if this RE can match a string ending with '\n'
str = None # Set to a string to override the class's __str__ result
def build_machine(self, machine, initial_state, final_state,
match_bol, nocase):
"""
This method should add states to |machine| to implement this
RE, starting at |initial_state| and ending at |final_state|.
If |match_bol| is true, the RE must be able to match at the
beginning of a line. If nocase is true, upper and lower case
letters should be treated as equivalent.
"""
raise exceptions.UnimplementedMethod("%s.build_machine not implemented" %
self.__class__.__name__)
def build_opt(self, m, initial_state, c):
"""
Given a state |s| of machine |m|, return a new state
reachable from |s| on character |c| or epsilon.
"""
s = m.new_state()
initial_state.link_to(s)
initial_state.add_transition(c, s)
return s
def __add__(self, other):
return Seq(self, other)
def __or__(self, other):
return Alt(self, other)
def __str__(self):
if self.str:
return self.str
else:
return self.calc_str()
def check_re(self, num, value):
if not isinstance(value, RE):
self.wrong_type(num, value, "Plex.RE instance")
def check_string(self, num, value):
if type(value) <> type(''):
self.wrong_type(num, value, "string")
def check_char(self, num, value):
self.check_string(num, value)
if len(value) <> 1:
raise Errors.PlexValueError("Invalid value for argument %d of Plex.%s."
"Expected a string of length 1, got: %s" % (
num, self.__class__.__name__, repr(value)))
def wrong_type(self, num, value, expected):
if type(value) == types.InstanceType:
got = "%s.%s instance" % (
value.__class__.__module__, value.__class__.__name__)
else:
got = type(value).__name__
raise Errors.PlexTypeError("Invalid type for argument %d of Plex.%s "
"(expected %s, got %s" % (
num, self.__class__.__name__, expected, got))
#
# Primitive RE constructors
# -------------------------
#
# These are the basic REs from which all others are built.
#
## class Char(RE):
## """
## Char(c) is an RE which matches the character |c|.
## """
## nullable = 0
## def __init__(self, char):
## self.char = char
## self.match_nl = char == '\n'
## def build_machine(self, m, initial_state, final_state, match_bol, nocase):
## c = self.char
## if match_bol and c <> BOL:
## s1 = self.build_opt(m, initial_state, BOL)
## else:
## s1 = initial_state
## if c == '\n' or c == EOF:
## s1 = self.build_opt(m, s1, EOL)
## if len(c) == 1:
## code = ord(self.char)
## s1.add_transition((code, code+1), final_state)
## if nocase and is_letter_code(code):
## code2 = other_case_code(code)
## s1.add_transition((code2, code2+1), final_state)
## else:
## s1.add_transition(c, final_state)
## def calc_str(self):
## return "Char(%s)" % repr(self.char)
def Char(c):
"""
Char(c) is an RE which matches the character |c|.
"""
if len(c) == 1:
result = CodeRange(ord(c), ord(c) + 1)
else:
result = SpecialSymbol(c)
result.str = "Char(%s)" % repr(c)
return result
class RawCodeRange(RE):
"""
RawCodeRange(code1, code2) is a low-level RE which matches any character
with a code |c| in the range |code1| <= |c| < |code2|, where the range
does not include newline. For internal use only.
"""
nullable = 0
match_nl = 0
range = None # (code, code)
uppercase_range = None # (code, code) or None
lowercase_range = None # (code, code) or None
def __init__(self, code1, code2):
self.range = (code1, code2)
self.uppercase_range = uppercase_range(code1, code2)
self.lowercase_range = lowercase_range(code1, code2)
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
if match_bol:
initial_state = self.build_opt(m, initial_state, BOL)
initial_state.add_transition(self.range, final_state)
if nocase:
if self.uppercase_range:
initial_state.add_transition(self.uppercase_range, final_state)
if self.lowercase_range:
initial_state.add_transition(self.lowercase_range, final_state)
def calc_str(self):
return "CodeRange(%d,%d)" % (self.code1, self.code2)
class _RawNewline(RE):
"""
RawNewline is a low-level RE which matches a newline character.
For internal use only.
"""
nullable = 0
match_nl = 1
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
if match_bol:
initial_state = self.build_opt(m, initial_state, BOL)
s = self.build_opt(m, initial_state, EOL)
s.add_transition((nl_code, nl_code + 1), final_state)
RawNewline = _RawNewline()
class SpecialSymbol(RE):
"""
SpecialSymbol(sym) is an RE which matches the special input
symbol |sym|, which is one of BOL, EOL or EOF.
"""
nullable = 0
match_nl = 0
sym = None
def __init__(self, sym):
self.sym = sym
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
# Sequences 'bol bol' and 'bol eof' are impossible, so only need
# to allow for bol if sym is eol
if match_bol and self.sym == EOL:
initial_state = self.build_opt(m, initial_state, BOL)
initial_state.add_transition(self.sym, final_state)
class Seq(RE):
"""Seq(re1, re2, re3...) is an RE which matches |re1| followed by
|re2| followed by |re3|..."""
def __init__(self, *re_list):
nullable = 1
for i in xrange(len(re_list)):
re = re_list[i]
self.check_re(i, re)
nullable = nullable and re.nullable
self.re_list = re_list
self.nullable = nullable
i = len(re_list)
match_nl = 0
while i:
i = i - 1
re = re_list[i]
if re.match_nl:
match_nl = 1
break
if not re.nullable:
break
self.match_nl = match_nl
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
re_list = self.re_list
if len(re_list) == 0:
initial_state.link_to(final_state)
else:
s1 = initial_state
n = len(re_list)
for i in xrange(n):
if i < n - 1:
s2 = m.new_state()
else:
s2 = final_state
re = re_list[i]
re.build_machine(m, s1, s2, match_bol, nocase)
s1 = s2
match_bol = re.match_nl or (match_bol and re.nullable)
def calc_str(self):
return "Seq(%s)" % string.join(map(str, self.re_list), ",")
class Alt(RE):
"""Alt(re1, re2, re3...) is an RE which matches either |re1| or
|re2| or |re3|..."""
def __init__(self, *re_list):
self.re_list = re_list
nullable = 0
match_nl = 0
nullable_res = []
non_nullable_res = []
i = 1
for re in re_list:
self.check_re(i, re)
if re.nullable:
nullable_res.append(re)
nullable = 1
else:
non_nullable_res.append(re)
if re.match_nl:
match_nl = 1
i = i + 1
self.nullable_res = nullable_res
self.non_nullable_res = non_nullable_res
self.nullable = nullable
self.match_nl = match_nl
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
for re in self.nullable_res:
re.build_machine(m, initial_state, final_state, match_bol, nocase)
if self.non_nullable_res:
if match_bol:
initial_state = self.build_opt(m, initial_state, BOL)
for re in self.non_nullable_res:
re.build_machine(m, initial_state, final_state, 0, nocase)
def calc_str(self):
return "Alt(%s)" % string.join(map(str, self.re_list), ",")
class Rep1(RE):
"""Rep1(re) is an RE which matches one or more repetitions of |re|."""
def __init__(self, re):
self.check_re(1, re)
self.re = re
self.nullable = re.nullable
self.match_nl = re.match_nl
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
s1 = m.new_state()
s2 = m.new_state()
initial_state.link_to(s1)
self.re.build_machine(m, s1, s2, match_bol or self.re.match_nl, nocase)
s2.link_to(s1)
s2.link_to(final_state)
def calc_str(self):
return "Rep1(%s)" % self.re
class SwitchCase(RE):
"""
SwitchCase(re, nocase) is an RE which matches the same strings as RE,
but treating upper and lower case letters according to |nocase|. If
|nocase| is true, case is ignored, otherwise it is not.
"""
re = None
nocase = None
def __init__(self, re, nocase):
self.re = re
self.nocase = nocase
self.nullable = re.nullable
self.match_nl = re.match_nl
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
self.re.build_machine(m, initial_state, final_state, match_bol,
self.nocase)
def calc_str(self):
if self.nocase:
name = "NoCase"
else:
name = "Case"
return "%s(%s)" % (name, self.re)
#
# Composite RE constructors
# -------------------------
#
# These REs are defined in terms of the primitive REs.
#
Empty = Seq()
Empty.__doc__ = \
"""
Empty is an RE which matches the empty string.
"""
Empty.str = "Empty"
def Str1(s):
"""
Str1(s) is an RE which matches the literal string |s|.
"""
result = apply(Seq, tuple(map(Char, s)))
result.str = "Str(%s)" % repr(s)
return result
def Str(*strs):
"""
Str(s) is an RE which matches the literal string |s|.
Str(s1, s2, s3, ...) is an RE which matches any of |s1| or |s2| or |s3|...
"""
if len(strs) == 1:
return Str1(strs[0])
else:
result = apply(Alt, tuple(map(Str1, strs)))
result.str = "Str(%s)" % string.join(map(repr, strs), ",")
return result
def Any(s):
"""
Any(s) is an RE which matches any character in the string |s|.
"""
#result = apply(Alt, tuple(map(Char, s)))
result = CodeRanges(chars_to_ranges(s))
result.str = "Any(%s)" % repr(s)
return result
def AnyBut(s):
"""
AnyBut(s) is an RE which matches any character (including
newline) which is not in the string |s|.
"""
ranges = chars_to_ranges(s)
ranges.insert(0, -maxint)
ranges.append(maxint)
result = CodeRanges(ranges)
result.str = "AnyBut(%s)" % repr(s)
return result
AnyChar = AnyBut("")
AnyChar.__doc__ = \
"""
AnyChar is an RE which matches any single character (including a newline).
"""
AnyChar.str = "AnyChar"
def Range(s1, s2 = None):
"""
Range(c1, c2) is an RE which matches any single character in the range
|c1| to |c2| inclusive.
Range(s) where |s| is a string of even length is an RE which matches
any single character in the ranges |s[0]| to |s[1]|, |s[2]| to |s[3]|,...
"""
if s2:
result = CodeRange(ord(s1), ord(s2) + 1)
result.str = "Range(%s,%s)" % (s1, s2)
else:
ranges = []
for i in range(0, len(s1), 2):
ranges.append(CodeRange(ord(s1[i]), ord(s1[i+1]) + 1))
result = apply(Alt, tuple(ranges))
result.str = "Range(%s)" % repr(s1)
return result
def Opt(re):
"""
Opt(re) is an RE which matches either |re| or the empty string.
"""
result = Alt(re, Empty)
result.str = "Opt(%s)" % re
return result
def Rep(re):
"""
Rep(re) is an RE which matches zero or more repetitions of |re|.
"""
result = Opt(Rep1(re))
result.str = "Rep(%s)" % re
return result
def NoCase(re):
"""
NoCase(re) is an RE which matches the same strings as RE, but treating
upper and lower case letters as equivalent.
"""
return SwitchCase(re, nocase = 1)
def Case(re):
"""
Case(re) is an RE which matches the same strings as RE, but treating
upper and lower case letters as distinct, i.e. it cancels the effect
of any enclosing NoCase().
"""
return SwitchCase(re, nocase = 0)
#
# RE Constants
#
Bol = Char(BOL)
Bol.__doc__ = \
"""
Bol is an RE which matches the beginning of a line.
"""
Bol.str = "Bol"
Eol = Char(EOL)
Eol.__doc__ = \
"""
Eol is an RE which matches the end of a line.
"""
Eol.str = "Eol"
Eof = Char(EOF)
Eof.__doc__ = \
"""
Eof is an RE which matches the end of the file.
"""
Eof.str = "Eof"

@ -0,0 +1,377 @@
#=======================================================================
#
# Python Lexical Analyser
#
#
# Scanning an input stream
#
#=======================================================================
import Errors
from Regexps import BOL, EOL, EOF
class Scanner:
"""
A Scanner is used to read tokens from a stream of characters
using the token set specified by a Plex.Lexicon.
Constructor:
Scanner(lexicon, stream, name = '')
See the docstring of the __init__ method for details.
Methods:
See the docstrings of the individual methods for more
information.
read() --> (value, text)
Reads the next lexical token from the stream.
position() --> (name, line, col)
Returns the position of the last token read using the
read() method.
begin(state_name)
Causes scanner to change state.
produce(value [, text])
Causes return of a token value to the caller of the
Scanner.
"""
lexicon = None # Lexicon
stream = None # file-like object
name = ''
buffer = ''
buf_start_pos = 0 # position in input of start of buffer
next_pos = 0 # position in input of next char to read
cur_pos = 0 # position in input of current char
cur_line = 1 # line number of current char
cur_line_start = 0 # position in input of start of current line
start_pos = 0 # position in input of start of token
start_line = 0 # line number of start of token
start_col = 0 # position in line of start of token
text = None # text of last token read
initial_state = None # Node
state_name = '' # Name of initial state
queue = None # list of tokens to be returned
trace = 0
def __init__(self, lexicon, stream, name = ''):
"""
Scanner(lexicon, stream, name = '')
|lexicon| is a Plex.Lexicon instance specifying the lexical tokens
to be recognised.
|stream| can be a file object or anything which implements a
compatible read() method.
|name| is optional, and may be the name of the file being
scanned or any other identifying string.
"""
self.lexicon = lexicon
self.stream = stream
self.name = name
self.queue = []
self.initial_state = None
self.begin('')
self.next_pos = 0
self.cur_pos = 0
self.cur_line_start = 0
self.cur_char = BOL
self.input_state = 1
def read(self):
"""
Read the next lexical token from the stream and return a
tuple (value, text), where |value| is the value associated with
the token as specified by the Lexicon, and |text| is the actual
string read from the stream. Returns (None, '') on end of file.
"""
queue = self.queue
while not queue:
self.text, action = self.scan_a_token()
if action is None:
self.produce(None)
self.eof()
else:
value = action.perform(self, self.text)
if value is not None:
self.produce(value)
result = queue[0]
del queue[0]
return result
def scan_a_token(self):
"""
Read the next input sequence recognised by the machine
and return (text, action). Returns ('', None) on end of
file.
"""
self.start_pos = self.cur_pos
self.start_line = self.cur_line
self.start_col = self.cur_pos - self.cur_line_start
# if self.trace:
# action = self.run_machine()
# else:
# action = self.run_machine_inlined()
action = self.run_machine_inlined()
if action:
if self.trace:
print "Scanner: read: Performing", action, "%d:%d" % (
self.start_pos, self.cur_pos)
base = self.buf_start_pos
text = self.buffer[self.start_pos - base : self.cur_pos - base]
return (text, action)
else:
if self.cur_pos == self.start_pos:
if self.cur_char == EOL:
self.next_char()
if not self.cur_char or self.cur_char == EOF:
return ('', None)
raise Errors.UnrecognizedInput(self, self.state_name)
def run_machine(self):
"""
Run the machine until no more transitions are possible.
"""
self.state = self.initial_state
self.backup_state = None
while self.transition():
pass
return self.back_up()
def run_machine_inlined(self):
"""
Inlined version of run_machine for speed.
"""
state = self.initial_state
cur_pos = self.cur_pos
cur_line = self.cur_line
cur_line_start = self.cur_line_start
cur_char = self.cur_char
input_state = self.input_state
next_pos = self.next_pos
buffer = self.buffer
buf_start_pos = self.buf_start_pos
buf_len = len(buffer)
backup_state = None
trace = self.trace
while 1:
if trace: #TRACE#
print "State %d, %d/%d:%s -->" % ( #TRACE#
state['number'], input_state, cur_pos, repr(cur_char)), #TRACE#
# Begin inlined self.save_for_backup()
#action = state.action #@slow
action = state['action'] #@fast
if action:
backup_state = (
action, cur_pos, cur_line, cur_line_start, cur_char, input_state, next_pos)
# End inlined self.save_for_backup()
c = cur_char
#new_state = state.new_state(c) #@slow
new_state = state.get(c, -1) #@fast
if new_state == -1: #@fast
new_state = c and state.get('else') #@fast
if new_state:
if trace: #TRACE#
print "State %d" % new_state['number'] #TRACE#
state = new_state
# Begin inlined: self.next_char()
if input_state == 1:
cur_pos = next_pos
# Begin inlined: c = self.read_char()
buf_index = next_pos - buf_start_pos
if buf_index < buf_len:
c = buffer[buf_index]
next_pos = next_pos + 1
else:
discard = self.start_pos - buf_start_pos
data = self.stream.read(0x1000)
buffer = self.buffer[discard:] + data
self.buffer = buffer
buf_start_pos = buf_start_pos + discard
self.buf_start_pos = buf_start_pos
buf_len = len(buffer)
buf_index = buf_index - discard
if data:
c = buffer[buf_index]
next_pos = next_pos + 1
else:
c = ''
# End inlined: c = self.read_char()
if c == '\n':
cur_char = EOL
input_state = 2
elif not c:
cur_char = EOL
input_state = 4
else:
cur_char = c
elif input_state == 2:
cur_char = '\n'
input_state = 3
elif input_state == 3:
cur_line = cur_line + 1
cur_line_start = cur_pos = next_pos
cur_char = BOL
input_state = 1
elif input_state == 4:
cur_char = EOF
input_state = 5
else: # input_state = 5
cur_char = ''
# End inlined self.next_char()
else: # not new_state
if trace: #TRACE#
print "blocked" #TRACE#
# Begin inlined: action = self.back_up()
if backup_state:
(action, cur_pos, cur_line, cur_line_start,
cur_char, input_state, next_pos) = backup_state
else:
action = None
break # while 1
# End inlined: action = self.back_up()
self.cur_pos = cur_pos
self.cur_line = cur_line
self.cur_line_start = cur_line_start
self.cur_char = cur_char
self.input_state = input_state
self.next_pos = next_pos
if trace: #TRACE#
if action: #TRACE#
print "Doing", action #TRACE#
return action
# def transition(self):
# self.save_for_backup()
# c = self.cur_char
# new_state = self.state.new_state(c)
# if new_state:
# if self.trace:
# print "Scanner: read: State %d: %s --> State %d" % (
# self.state.number, repr(c), new_state.number)
# self.state = new_state
# self.next_char()
# return 1
# else:
# if self.trace:
# print "Scanner: read: State %d: %s --> blocked" % (
# self.state.number, repr(c))
# return 0
# def save_for_backup(self):
# action = self.state.get_action()
# if action:
# if self.trace:
# print "Scanner: read: Saving backup point at", self.cur_pos
# self.backup_state = (
# action, self.cur_pos, self.cur_line, self.cur_line_start,
# self.cur_char, self.input_state, self.next_pos)
# def back_up(self):
# backup_state = self.backup_state
# if backup_state:
# (action, self.cur_pos, self.cur_line, self.cur_line_start,
# self.cur_char, self.input_state, self.next_pos) = backup_state
# if self.trace:
# print "Scanner: read: Backing up to", self.cur_pos
# return action
# else:
# return None
def next_char(self):
input_state = self.input_state
if self.trace:
print "Scanner: next:", " "*20, "[%d] %d" % (input_state, self.cur_pos),
if input_state == 1:
self.cur_pos = self.next_pos
c = self.read_char()
if c == '\n':
self.cur_char = EOL
self.input_state = 2
elif not c:
self.cur_char = EOL
self.input_state = 4
else:
self.cur_char = c
elif input_state == 2:
self.cur_char = '\n'
self.input_state = 3
elif input_state == 3:
self.cur_line = self.cur_line + 1
self.cur_line_start = self.cur_pos = self.next_pos
self.cur_char = BOL
self.input_state = 1
elif input_state == 4:
self.cur_char = EOF
self.input_state = 5
else: # input_state = 5
self.cur_char = ''
if self.trace:
print "--> [%d] %d %s" % (input_state, self.cur_pos, repr(self.cur_char))
# def read_char(self):
# """
# Get the next input character, filling the buffer if necessary.
# Returns '' at end of file.
# """
# next_pos = self.next_pos
# buf_index = next_pos - self.buf_start_pos
# if buf_index == len(self.buffer):
# discard = self.start_pos - self.buf_start_pos
# data = self.stream.read(0x1000)
# self.buffer = self.buffer[discard:] + data
# self.buf_start_pos = self.buf_start_pos + discard
# buf_index = buf_index - discard
# if not data:
# return ''
# c = self.buffer[buf_index]
# self.next_pos = next_pos + 1
# return c
def position(self):
"""
Return a tuple (name, line, col) representing the location of
the last token read using the read() method. |name| is the
name that was provided to the Scanner constructor; |line|
is the line number in the stream (1-based); |col| is the
position within the line of the first character of the token
(0-based).
"""
return (self.name, self.start_line, self.start_col)
def begin(self, state_name):
"""Set the current state of the scanner to the named state."""
self.initial_state = (
self.lexicon.get_initial_state(state_name))
self.state_name = state_name
def produce(self, value, text = None):
"""
Called from an action procedure, causes |value| to be returned
as the token value from read(). If |text| is supplied, it is
returned in place of the scanned text.
produce() can be called more than once during a single call to an action
procedure, in which case the tokens are queued up and returned one
at a time by subsequent calls to read(), until the queue is empty,
whereupon scanning resumes.
"""
if text is None:
text = self.text
self.queue.append((value, text))
def eof(self):
"""
Override this method if you want something to be done at
end of file.
"""
# For backward compatibility:
setattr(Scanner, "yield", Scanner.produce)

@ -0,0 +1,22 @@
#
# Get time in platform-dependent way
#
import os
from sys import platform, exit, stderr
if platform == 'mac':
import MacOS
def time():
return MacOS.GetTicks() / 60.0
timekind = "real"
elif hasattr(os, 'times'):
def time():
t = os.times()
return t[0] + t[1]
timekind = "cpu"
else:
stderr.write(
"Don't know how to get time on platform %s\n" % repr(platform))
exit(1)

@ -0,0 +1,154 @@
#=======================================================================
#
# Python Lexical Analyser
#
# Traditional Regular Expression Syntax
#
#=======================================================================
from Regexps import *
from Errors import PlexError
class RegexpSyntaxError(PlexError):
pass
def re(s):
"""
Convert traditional string representation of regular expression |s|
into Plex representation.
"""
return REParser(s).parse_re()
class REParser:
def __init__(self, s):
self.s = s
self.i = -1
self.end = 0
self.next()
def parse_re(self):
re = self.parse_alt()
if not self.end:
self.error("Unexpected %s" % repr(self.c))
return re
def parse_alt(self):
"""Parse a set of alternative regexps."""
re = self.parse_seq()
if self.c == '|':
re_list = [re]
while self.c == '|':
self.next()
re_list.append(self.parse_seq())
re = apply(Alt, tuple(re_list))
return re
def parse_seq(self):
"""Parse a sequence of regexps."""
re_list = []
while not self.end and not self.c in "|)":
re_list.append(self.parse_mod())
return apply(Seq, tuple(re_list))
def parse_mod(self):
"""Parse a primitive regexp followed by *, +, ? modifiers."""
re = self.parse_prim()
while not self.end and self.c in "*+?":
if self.c == '*':
re = Rep(re)
elif self.c == '+':
re = Rep1(re)
else: # self.c == '?'
re = Opt(re)
self.next()
return re
def parse_prim(self):
"""Parse a primitive regexp."""
c = self.get()
if c == '.':
re = AnyBut("\n")
elif c == '^':
re = Bol
elif c == '$':
re = Eol
elif c == '(':
re = self.parse_alt()
self.expect(')')
elif c == '[':
re = self.parse_charset()
self.expect(']')
else:
if c == '\\':
c = self.get()
re = Char(c)
return re
def parse_charset(self):
"""Parse a charset. Does not include the surrounding []."""
char_list = []
invert = 0
if self.c == '^':
invert = 1
self.next()
if self.c == ']':
char_list.append(']')
self.next()
while not self.end and self.c <> ']':
c1 = self.get()
if self.c == '-' and self.lookahead(1) <> ']':
self.next()
c2 = self.get()
for a in xrange(ord(c1), ord(c2) + 1):
char_list.append(chr(a))
else:
char_list.append(c1)
chars = string.join(char_list, "")
if invert:
return AnyBut(chars)
else:
return Any(chars)
def next(self):
"""Advance to the next char."""
s = self.s
i = self.i = self.i + 1
if i < len(s):
self.c = s[i]
else:
self.c = ''
self.end = 1
def get(self):
if self.end:
self.error("Premature end of string")
c = self.c
self.next()
return c
def lookahead(self, n):
"""Look ahead n chars."""
j = self.i + n
if j < len(self.s):
return self.s[j]
else:
return ''
def expect(self, c):
"""
Expect to find character |c| at current position.
Raises an exception otherwise.
"""
if self.c == c:
self.next()
else:
self.error("Missing %s" % repr(c))
def error(self, mess):
"""Raise exception to signal syntax error in regexp."""
raise RegexpSyntaxError("Syntax error in regexp %s at position %d: %s" % (
repr(self.s), self.i, mess))

@ -0,0 +1,253 @@
#
# Plex - Transition Maps
#
# This version represents state sets direcly as dicts
# for speed.
#
from copy import copy
import string
from sys import maxint
from types import TupleType
class TransitionMap:
"""
A TransitionMap maps an input event to a set of states.
An input event is one of: a range of character codes,
the empty string (representing an epsilon move), or one
of the special symbols BOL, EOL, EOF.
For characters, this implementation compactly represents
the map by means of a list:
[code_0, states_0, code_1, states_1, code_2, states_2,
..., code_n-1, states_n-1, code_n]
where |code_i| is a character code, and |states_i| is a
set of states corresponding to characters with codes |c|
in the range |code_i| <= |c| <= |code_i+1|.
The following invariants hold:
n >= 1
code_0 == -maxint
code_n == maxint
code_i < code_i+1 for i in 0..n-1
states_0 == states_n-1
Mappings for the special events '', BOL, EOL, EOF are
kept separately in a dictionary.
"""
map = None # The list of codes and states
special = None # Mapping for special events
def __init__(self, map = None, special = None):
if not map:
map = [-maxint, {}, maxint]
if not special:
special = {}
self.map = map
self.special = special
#self.check() ###
def add(self, event, new_state,
TupleType = TupleType):
"""
Add transition to |new_state| on |event|.
"""
if type(event) == TupleType:
code0, code1 = event
i = self.split(code0)
j = self.split(code1)
map = self.map
while i < j:
map[i + 1][new_state] = 1
i = i + 2
else:
self.get_special(event)[new_state] = 1
def add_set(self, event, new_set,
TupleType = TupleType):
"""
Add transitions to the states in |new_set| on |event|.
"""
if type(event) == TupleType:
code0, code1 = event
i = self.split(code0)
j = self.split(code1)
map = self.map
while i < j:
map[i + 1].update(new_set)
i = i + 2
else:
self.get_special(event).update(new_set)
def get_epsilon(self,
none = None):
"""
Return the mapping for epsilon, or None.
"""
return self.special.get('', none)
def items(self,
len = len):
"""
Return the mapping as a list of ((code1, code2), state_set) and
(special_event, state_set) pairs.
"""
result = []
map = self.map
else_set = map[1]
i = 0
n = len(map) - 1
code0 = map[0]
while i < n:
set = map[i + 1]
code1 = map[i + 2]
if set or else_set:
result.append(((code0, code1), set))
code0 = code1
i = i + 2
for event, set in self.special.items():
if set:
result.append((event, set))
return result
# ------------------- Private methods --------------------
def split(self, code,
len = len, maxint = maxint):
"""
Search the list for the position of the split point for |code|,
inserting a new split point if necessary. Returns index |i| such
that |code| == |map[i]|.
"""
# We use a funky variation on binary search.
map = self.map
hi = len(map) - 1
# Special case: code == map[-1]
if code == maxint:
return hi
# General case
lo = 0
# loop invariant: map[lo] <= code < map[hi] and hi - lo >= 2
while hi - lo >= 4:
# Find midpoint truncated to even index
mid = ((lo + hi) / 2) & ~1
if code < map[mid]:
hi = mid
else:
lo = mid
# map[lo] <= code < map[hi] and hi - lo == 2
if map[lo] == code:
return lo
else:
map[hi:hi] = [code, map[hi - 1].copy()]
#self.check() ###
return hi
def get_special(self, event):
"""
Get state set for special event, adding a new entry if necessary.
"""
special = self.special
set = special.get(event, None)
if not set:
set = {}
special[event] = set
return set
# --------------------- Conversion methods -----------------------
def __str__(self):
map_strs = []
map = self.map
n = len(map)
i = 0
while i < n:
code = map[i]
if code == -maxint:
code_str = "-inf"
elif code == maxint:
code_str = "inf"
else:
code_str = str(code)
map_strs.append(code_str)
i = i + 1
if i < n:
map_strs.append(state_set_str(map[i]))
i = i + 1
special_strs = {}
for event, set in self.special.items():
special_strs[event] = state_set_str(set)
return "[%s]+%s" % (
string.join(map_strs, ","),
special_strs
)
# --------------------- Debugging methods -----------------------
def check(self):
"""Check data structure integrity."""
if not self.map[-3] < self.map[-1]:
print self
assert 0
def dump(self, file):
map = self.map
i = 0
n = len(map) - 1
while i < n:
self.dump_range(map[i], map[i + 2], map[i + 1], file)
i = i + 2
for event, set in self.special.items():
if set:
if not event:
event = 'empty'
self.dump_trans(event, set, file)
def dump_range(self, code0, code1, set, file):
if set:
if code0 == -maxint:
if code1 == maxint:
k = "any"
else:
k = "< %s" % self.dump_char(code1)
elif code1 == maxint:
k = "> %s" % self.dump_char(code0 - 1)
elif code0 == code1 - 1:
k = self.dump_char(code0)
else:
k = "%s..%s" % (self.dump_char(code0),
self.dump_char(code1 - 1))
self.dump_trans(k, set, file)
def dump_char(self, code):
if 0 <= code <= 255:
return repr(chr(code))
else:
return "chr(%d)" % code
def dump_trans(self, key, set, file):
file.write(" %s --> %s\n" % (key, self.dump_set(set)))
def dump_set(self, set):
return state_set_str(set)
#
# State set manipulation functions
#
#def merge_state_sets(set1, set2):
# for state in set2.keys():
# set1[state] = 1
def state_set_str(set):
state_list = set.keys()
str_list = []
for state in state_list:
str_list.append("S%d" % state.number)
return "[%s]" % string.join(str_list, ",")

@ -0,0 +1,40 @@
#=======================================================================
#
# Python Lexical Analyser
#
#=======================================================================
"""
The Plex module provides lexical analysers with similar capabilities
to GNU Flex. The following classes and functions are exported;
see the attached docstrings for more information.
Scanner For scanning a character stream under the
direction of a Lexicon.
Lexicon For constructing a lexical definition
to be used by a Scanner.
Str, Any, AnyBut, AnyChar, Seq, Alt, Opt, Rep, Rep1,
Bol, Eol, Eof, Empty
Regular expression constructors, for building pattern
definitions for a Lexicon.
State For defining scanner states when creating a
Lexicon.
TEXT, IGNORE, Begin
Actions for associating with patterns when
creating a Lexicon.
"""
from Actions import TEXT, IGNORE, Begin
from Lexicons import Lexicon, State
from Regexps import RE, Seq, Alt, Rep1, Empty, Str, Any, AnyBut, AnyChar, Range
from Regexps import Opt, Rep, Bol, Eol, Eof, Case, NoCase
from Scanners import Scanner

@ -0,0 +1,24 @@
import sys
sys.stderr = sys.stdout
from TransitionMaps import TransitionMap
m = TransitionMap()
print m
def add(c, s):
print
print "adding", repr(c), "-->", repr(s)
m.add_transition(c, s)
print m
print "keys:", m.keys()
add('a','alpha')
add('e', 'eta')
add('f', 'foo')
add('i', 'iota')
add('i', 'imp')
add('eol', 'elephant')

@ -0,0 +1,74 @@
#
# Pyrex - Linux system interface
#
verbose = 0
gcc_pendantic = True
gcc_warnings_are_errors = True
gcc_all_warnings = True
import os, sys
from Pyrex.Utils import replace_suffix
from Pyrex.Compiler.Errors import PyrexError
version = "%s.%s" % sys.version[:2]
py_include_dirs = [
"%s/include/python%s" % (sys.prefix, version)
]
compilers = ["gcc", "g++"]
compiler_options = \
"-g -c -fno-strict-aliasing -Wno-long-double -no-cpp-precomp " \
"-mno-fused-madd -fno-common -dynamic " \
.split()
if gcc_pendantic:
compiler_options.extend(["-pedantic", "-Wno-long-long"])
if gcc_warnings_are_errors:
compiler_options.append("-Werror")
if gcc_all_warnings:
compiler_options.append("-Wall")
compiler_options.append("-Wno-unused-function")
linkers = ["gcc", "g++"]
linker_options = \
"-shared" \
.split()
class CCompilerError(PyrexError):
pass
def c_compile(c_file, verbose_flag = 0, cplus = 0, obj_suffix = ".o"):
# Compile the given C source file to produce
# an object file. Returns the pathname of the
# resulting file.
c_file = os.path.join(os.getcwd(), c_file)
o_file = replace_suffix(c_file, obj_suffix)
include_options = []
for dir in py_include_dirs:
include_options.append("-I%s" % dir)
compiler = compilers[bool(cplus)]
args = [compiler] + compiler_options + include_options + [c_file, "-o", o_file]
if verbose_flag or verbose:
print " ".join(args)
#print compiler, args ###
status = os.spawnvp(os.P_WAIT, compiler, args)
if status <> 0:
raise CCompilerError("C compiler returned status %s" % status)
return o_file
def c_link(obj_file, verbose_flag = 0, extra_objects = [], cplus = 0):
return c_link_list([obj_file] + extra_objects, verbose_flag, cplus)
def c_link_list(obj_files, verbose_flag = 0, cplus = 0):
# Link the given object files into a dynamically
# loadable extension file. Returns the pathname
# of the resulting file.
out_file = replace_suffix(obj_files[0], ".so")
linker = linkers[bool(cplus)]
args = [linker] + linker_options + obj_files + ["-o", out_file]
if verbose_flag or verbose:
print " ".join(args)
status = os.spawnvp(os.P_WAIT, linker, args)
if status <> 0:
raise CCompilerError("Linker returned status %s" % status)
return out_file

@ -0,0 +1,55 @@
#
# Pyrex -- Things that don't belong
# anywhere else in particular
#
import os, sys
try:
from __builtin__ import set
except ImportError:
from sets import Set as set
def has_suffix(path, suffixes):
for suffix in suffixes:
if path.endswith(suffix):
return True
return False
def replace_suffix(path, newsuf):
base, _ = os.path.splitext(path)
return base + newsuf
def map_suffix(path, mapping, default):
base, suffix = os.path.splitext(path)
return base + mapping.get(suffix, default)
def open_new_file(path):
# Open and truncate existing file to
# preserve metadata on the Mac.
return open(path, "w+")
def castrate_file(path, st):
# Remove junk contents from an output file after a
# failed compilation, but preserve metadata on Mac.
# Also sets access and modification times earlier
# than those specified by st (a stat struct).
try:
f = open(path, "r+")
except EnvironmentError:
pass
else:
f.seek(0, 0)
f.truncate()
f.write(
"#error Do not use this file, it is the result of a failed Pyrex compilation.\n")
f.close()
if st:
os.utime(path, (st.st_atime - 1, st.st_mtime - 1))
def modification_time(path):
st = os.stat(path)
return st.st_mtime
def file_newer_than(path, time):
ftime = modification_time(path)
return ftime > time

@ -0,0 +1,37 @@
Welcome to Pyrex!
=================
This is a development version of Pyrex, a language
for writing Python extension modules.
For more info, see:
Doc/About.html for a description of the language
INSTALL.txt for installation instructions
USAGE.txt for usage instructions
Demos for usage examples
Comments, suggestions, bug reports, etc. are
welcome!
License
-------
Pyrex is open source. You may use it, redistribute it, modify
it and distribute modified versions without restriction.
If you require a more formal license statement, you may use
Pyrex under the terms of the Apache License Version 2.0, a copy
of which is included in the file LICENSE.txt.
Updates
-------
The latest version of Pyrex can be found here:
http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/
Gregory Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
greg.ewing@canterbury.ac.nz

@ -0,0 +1,164 @@
Const types.
Tuple/list construction: Evaluate & store items one at a time?
Varargs argument traversal.
Optimise abs() on integer or float.
Optional semicolons after C declarations.
Multiple C declarations on one line?
Optimise return without value outside of try-finally.
exec statement.
Use iterator protocol for unpacking.
In-place operators (+=, etc).
Check for lack of return with value in non-void C functions?
Make C structs callable as constructors.
When calling user __dealloc__ func, save & restore exception.
Complex number parsetuple format?
Provide a way of declaring a C function as returning a
borrowed Python reference.
Provide a way of declaring a C function as stealing a
Python reference.
Provide a way of specifying whether a Python object obtained
by casting a pointer should be treated as a new reference
or not.
Make sizeof() take types as well as variables.
Allow "unsigned" to be used alone as a type name.
Do something about installing proper version of pyrexc
script according to platform in setup.py.
Recognise #line directives?
Catch floating point exceptions?
Generate type test when casting from one Python type
to another.
Allow ranges of exception values.
Support "complex double" and "complex float"?
Allow module-level Python variables to be declared extern.
Consider:
>cdef extern from "foo.h":
> int dosomething() except -1 raise MyException
Properties for Python types?
Find a way to make classmethod and staticmethod work better.
Statically initialised C arrays & structs.
Make docstrings of extension type special methods work.
Treat result of getting C attribute of extension type as non-ephemeral.
Teach it about common builtin types.
Option for generating a main() function?
Do something about external C functions declared as returning
const * types?
Use PyString_FromStringAndSize for string literals? (For efficiency
and so that they can contain nulls.)
What to do about __name__ etc. attributes of a module (they are
currently assumed to be built-in names).
Use PyDict_GetItem etc. on module & builtins dicts for speed.
Intern all string literals used as Python strings?
[Koshy <jkoshy@freebsd.org>]
Disallow a filename which results in an illegal identifier when
used as a module name.
Provide an easy way of exposing a set of enum values as Python names.
[John J Lee <jjl@pobox.com>]
Prevent user from returning a value from special methods that
return an error indicator only.
Allow * in cimport? [John J Lee <jjl@pobox.com>]
Make Python class construction work more like it does in Python.
Give the right module name to Python classes.
Command line switch for full pathnames in backtraces?
Peephole optimisation? [Vladislav Bulatov <vrbulatov@list.ru>]
Avoid PyArg_ParseTuple call when a function takes no positional args.
Can a faster way of instantiating extension types be found?
Use PySequence_GetItem instead of PyObject_GetItem when index
is an integer.
If a __getitem__ method is declared with an int index, use the
sq_item slot instead of the mp_subscript slot.
Provide some way of controlling the argument list passed to
an extension type's base __new__ method?
[Alain Pointdexter <alainpoint@yahoo.fr>]
Implement a true __new__ for extension types.
Way to provide constructors for extension types that are not
available to Python and can accept C types directly?
Support generators by turning them into extension types?
List comprehensions.
Variable declarations inside inner code blocks?
Initial values when declaring variables?
Support class methods in extension types using METH_CLASS flag.
Disallow defaulting types to 'object' in C declarations?
C globals with static initialisers.
Find a way of providing C-only initialisers for extension types.
Metaclasses for extension types?
Make extension types use Py_TPFLAGS_HEAPTYPE so their __module__
will get set dynamically?
Track GIL state.
Private fields of extension types in a separate struct.
Private vtable entries in a separate struct.
Specialised constructors for builtin types.
Special-case integer indexing and slicing.
Allow "extern api".
Lockstep iteration syntax.
True division? Future import?

@ -0,0 +1 @@
;;;; `Pyrex' mode. (add-to-list 'auto-mode-alist '("\\.pyx\\'" . pyrex-mode)) (define-derived-mode pyrex-mode python-mode "Pyrex" (font-lock-add-keywords nil `((,(concat "\\<\\(NULL" "\\|c\\(def\\|har\\|typedef\\)" "\\|e\\(num\\|xtern\\)" "\\|float" "\\|in\\(clude\\|t\\)" "\\|object\\|public\\|struct\\|type\\|union\\|void" "\\)\\>") 1 font-lock-keyword-face t))))

@ -0,0 +1 @@
/** * Name: pyrex * Description: Pyrex - a Language for Writing Python Extension Modules * Author: Markku Rossi <mtr@iki.fi> */ state pyrex extends python { /* Additional keywords. (build-re '( NULL as cdef char ctypedef double enum extern float include int long private public short signed sizeof struct union unsigned void )) */ /\b(NULL|as|c(def|har|typedef)|double|e(num|xtern)|float|in(clude|t)\ |long|p(rivate|ublic)|s(hort|i(gned|zeof)|truct)|un(ion|signed)|void)\b/ { keyword_face(true); language_print($0); keyword_face(false); } } /* Local variables: mode: c End: */

@ -0,0 +1,69 @@
Pyrex - Usage Instructions
==========================
Building Pyrex extensions using distutils
-----------------------------------------
Pyrex comes with an experimental distutils extension for compiling
Pyrex modules, contributed by Graham Fawcett of the University of
Windsor (fawcett@uwindsor.ca).
The Demos directory contains a setup.py file demonstrating its use. To
compile the demos:
(1) cd Demos
(2) python setup.py build_ext --inplace
or
python setup.py build --build-lib=.
(You may get a screed of warnings from the C compiler, but you can
ignore these -- as long as there are no actual errors, things are
probably okay.)
Try out the extensions with:
python run_primes.py
python run_spam.py
python run_numeric_demo.py
Building Pyrex extensions by hand
---------------------------------
You can also invoke the Pyrex compiler on its own to translate a .pyx
file to a .c file. On Unix,
pyrexc filename.pyx
On other platforms,
python pyrexc.py filename.pyx
It's then up to you to compile and link the .c file using whatever
procedure is appropriate for your platform. The file
Makefile.nodistutils in the Demos directory shows how to do this for
one particular Unix system.
Command line options
--------------------
The pyrexc command supports the following options:
Short Long Argument Description
-----------------------------------------------------------------------------
-v --version Display version number of pyrex compiler
-l --create-listing Write error messages to a .lis file
-I --include-dir <directory> Search for include files in named
directory (may be repeated)
-o --output-file <filename> Specify name of generated C file (only
one source file allowed if this is used)
Anything else is taken as the name of a Pyrex source file and compiled
to a C source file. Multiple Pyrex source files can be specified
(unless -o is used), in which case each source file is treated as the
source of a distinct extension module and compiled separately to
produce its own C file.

@ -0,0 +1,8 @@
#!/usr/bin/env python
#
# Pyrex -- Main Program, Unix
#
from Pyrex.Compiler.Main import main
main(command_line = 1)

@ -0,0 +1,8 @@
#!/usr/bin/env python2.5
#
# Pyrex -- Main Program, Unix
#
from Pyrex.Compiler.Main import main
main(command_line = 1)

@ -0,0 +1,8 @@
#!/usr/bin/env python2.6
#
# Pyrex -- Main Program, Unix
#
from Pyrex.Compiler.Main import main
main(command_line = 1)

@ -0,0 +1,15 @@
#!/bin/sh
export MACOSX_DEPLOYMENT_TARGET=10.3
ver=2.3
if [ $1 == -p ]; then
ver=$2
shift 2
fi
base=$1
gcc -g -c -fno-strict-aliasing -Wno-long-double -no-cpp-precomp \
-mno-fused-madd -fno-common -dynamic -Wno-long-long \
-Wno-unused-function \
-I/Library/Frameworks/Python.framework/Versions/$ver/Headers \
$base.c
gcc -Wl,-F.,-w -bundle -undefined dynamic_lookup \
$base.o -o $base.so

@ -0,0 +1,7 @@
#!/usr/bin/env python2.5
#
# runtests -- Run all the tests.
#
from Pyrex.Testing import Testing
Testing.run_tests()

@ -0,0 +1,7 @@
#!/usr/bin/env python2.6
#
# runtests -- Run all the tests.
#
from Pyrex.Testing import Testing
Testing.run_tests()

@ -0,0 +1,49 @@
#!/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()

@ -0,0 +1,333 @@
pyrex (0.9.9-1~0debian11.0.0+0~a) bullseye; urgency=medium
* Temporarily added to the Trinity repository.
* Change python binary to python2 instead of python.
* Add python2-dev | python-all-dev as alternatives to python-dev dependency.
-- Slávek Banko <slavek.banko@axis.cz> Tue, 02 Mar 2021 15:37:49 +0100
pyrex (0.9.9-1) unstable; urgency=medium
* New upstream release (closes: #582561, #610386)
* Bump debian/compat to 7
* Acknowledge NMU (Closes: #616980)
* debian/compat: bump from 5 to 9
* debian/patches: removed, integrated upstream
* debian/control: add X-Python-Version, remove dpatch, add dh-python
* debian/control: bump Standards-Version to 3.9.8, strip trailing space
* debian/rules: update (closes: #668804, #831938), strip trailing spaces
* debian/control: add python-dev to depends (closes: #648800)
* debian/patches/baseexception.patch: add patch from ubuntu, thanks to
Michael Vogt (closes: #604965)
-- Paul Brossier <piem@debian.org> Thu, 01 Sep 2016 12:04:51 +0200
pyrex (0.9.8.5-2.1) unstable; urgency=low
* Non-maintainer upload.
* Convert to dh_python2. (Closes: #616980)
-- Andrea Colangelo <warp10@ubuntu.com> Fri, 28 Jun 2013 17:03:29 +0200
pyrex (0.9.8.5-2) unstable; urgency=low
* Acknowledge NMU (closes: #519951)
* Adjust pyrex-mode depends for emacs22 (closes: #485766)
* Fix Vcs-* fields (closes: #536808)
* Bump Standards-Version to 3.8.3
-- Paul Brossier <piem@debian.org> Tue, 08 Dec 2009 01:11:36 +0100
pyrex (0.9.8.5-1.1) unstable; urgency=low
* Non-maintainer upload.
* Prepare for the upcoming Python 2.6 transition; thanks to Evan Broder for
the report; Closes: #519951
- debian/control
+ tight b-d on python-all-dev to '(>= 2.5.4-1~)'
- debian/rules
+ include python.mk
+ pass py_setup_install_args to setup.py install
-- Sandro Tosi <morph@debian.org> Wed, 25 Nov 2009 23:28:41 +0100
pyrex (0.9.8.5-1) unstable; urgency=low
* New upstream release.
* Acknowledge non-maintainer upload (closes: #483035).
* Bump Standards-version to 3.8.1
* Add ${misc:Depends} for debhelper
* Complete debian/copyright
-- Paul Brossier <piem@debian.org> Thu, 19 Mar 2009 16:11:15 +0100
pyrex (0.9.7.2-0.1) unstable; urgency=high
* NMU because maintainer is MIA.
* New upstream release fixing an integer indexing optimisation problem
(0.9.7.1 and 0.9.7.2 contain this fix only, so this is safe for
Lenny release) (Closes: #483035).
-- Marc Dequènes (Duck) <Duck@DuckCorp.org> Fri, 29 Aug 2008 03:00:52 +0200
pyrex (0.9.7-1) unstable; urgency=low
* New upstream release.
* remove dh_python from debian/rules, add XB-Python-Version
(closes: #460253)
* remove auto-mode-alist from debian/pyrex-mode.el (ubuntu #73904)
* add provide to debian/pyrex-mode.el (ubuntu #73903)
* debian/control: added Homepage field
* debian/rules, debian/control: add dpatch
* debian/patches: add hash patch, thanks to Jakub Wilk (closes: #469735)
* debian/control: drop Suggests: python-numeric (closes: #478455)
* debian/python-pyrex.doc-base: switch to section Programming/Pyrex
* debian/control: added fields Vcs-Browser and Vcs-Hg
* debian/control: fix typo python -> Python
-- Paul Brossier <piem@debian.org> Sun, 11 May 2008 16:19:48 +0200
pyrex (0.9.6.4-1) unstable; urgency=low
* New upstream release (closes:#406025)
* Move python-all-dev to Build-Depends since python gets called in
debian/rules:clean
* Delete empty usr/lib from python-pyrex
* Delete blank lines from debian/python-pyrex.doc-base
* Remove empty binary-arch target
* Bump Standards-Version to 3.7.3
-- Paul Brossier <piem@debian.org> Fri, 11 Jan 2008 11:50:29 +0100
pyrex (0.9.5.1a-1) unstable; urgency=low
* New upstream release (closes: #411004)
* Provide only ${python:Provides} (closes: #399937)
* Drop Conflicts and Replaces against oldstable packages
* Bumpep Build-depends on debhelper to 5.0.37.2
* Added debian/pycompat, set to 2
* Moved DH_COMPAT=5 to debian/compat
-- Paul Brossier <piem@debian.org> Sat, 21 Apr 2007 15:16:07 +0200
pyrex (0.9.4.1-2) unstable; urgency=low
* Correct pyrex-mode emacsen-startup script: load python-mode, not
python-mode. Add support for .pxi/.pxd extensions (thanks to Lukasz
Pankowski, closes: #375861). Avoid loading pyrex-mode when package has
been removed but not purged, do not touch load-path.
* Move dh_pycentral call right before dh_python.
-- Paul Brossier <piem@debian.org> Tue, 4 Jul 2006 15:44:27 +0200
pyrex (0.9.4.1-1) unstable; urgency=low
* New upstream release
* Update to new Python policy (closes: #373505)
-- Paul Brossier <piem@debian.org> Wed, 14 Jun 2006 18:21:15 +0200
pyrex (0.9.4-1) unstable; urgency=low
* New upstream release
-- Paul Brossier <piem@debian.org> Thu, 20 Apr 2006 15:54:27 +0200
pyrex (0.9.3.1-2) unstable; urgency=low
* Add missing gcc 4.0 patch (closes: #343533)
-- Paul Brossier <piem@debian.org> Mon, 19 Dec 2005 09:01:29 +0000
pyrex (0.9.3.1-1) unstable; urgency=low
* New upstream release, integrates some of the gcc-4.x changes:
- adopted changes in Pyrex/Compiler/Nodes.py
- changed casts from PyObject* to void* in Pyrex/Compiler/Code.py
- removed Demos/{callback,embed} and Tools as in upstream
(closes: #328871)
* Keep a copy of pyrex-mode.el to debian/
* Added missing emacscen-startup script for pyrex-mode (closes: #337054)
-- Paul Brossier <piem@debian.org> Sun, 11 Dec 2005 15:45:59 +0000
pyrex (0.9.3-3) unstable; urgency=low
* Drop python2.2-pyrex
* Update copyright file
* Bump to new Standards-Version
-- Paul Brossier <piem@debian.org> Wed, 13 Jul 2005 17:48:17 +0100
pyrex (0.9.3-2) unstable; urgency=low
* Added python2.4-pyrex (closes: #292257)
* Patch to get friendlier code for gcc 4.0 (closes: #298084)
Author is Jeremy Katz, sent to pyrex ML via John (J5) Palmieri
* Also add additional patch from Martijn Faassen
* Fix swig_sources function in Pyrex/Distutils for python2.4
* Correct the email in previous changelog entry 0.9.2.1-4
* Move pyrexc link to python-pyrex
* Remove Guenter from the uploaders (thanks for the uploads)
-- Paul Brossier <piem@debian.org> Tue, 21 Jun 2005 20:02:11 +0100
pyrex (0.9.3-1) unstable; urgency=low
* New upstream release
* Created watch file and pyrex-mode package
* Removed long unsigned patch (fixed upstream)
* Removed DH_VERBOSE mode, debug and nostrip opts in rules
-- Paul Brossier <piem@altern.org> Thu, 12 Aug 2004 13:08:21 +0200
pyrex (0.9.2.1-4) unstable; urgency=low
* Fixed python Build-Depends: for amd64 (closes: #255603)
-- Paul Brossier <piem@altern.org> Mon, 28 Jun 2004 12:01:14 +0100
pyrex (0.9.2.1-3) unstable; urgency=low
* Fixed patch (closes: #251572, #255279)
* Fixed override disparity (now in section python)
-- Paul Brossier <piem@altern.org> Mon, 21 Jun 2004 11:31:58 +0100
pyrex (0.9.2.1-2) unstable; urgency=low
* Really includes a patch for dbus now (closes: #251572)
* Bump debian-policy to 3.6.1.0
-- Paul Brossier <piem@altern.org> Wed, 16 Jun 2004 15:55:44 +0100
pyrex (0.9.2.1-1) unstable; urgency=low
* New upstream release (closes: #252819)
* Fixes namespace collision (closes: #233596)
* Added lamont patch (closes: #249881)
* Clean *.pyc to allow recompile
-- Paul Brossier <piem@altern.org> Wed, 9 Jun 2004 12:16:04 +0100
pyrex (0.9.0-4) unstable; urgency=low
* Fixed upstream archive (permissions set to -x, removed .DS_Store garbage).
* Added missing cheesfinder.c as found in 0.7.2 release (closes: #232655).
* Corrected Makefile* in Demos.
* Added Tools in doc (enscript and emacs style files)
-- Paul Brossier <piem@altern.org> Wed, 18 Feb 2004 03:13:59 +0000
pyrex (0.9.0-3) unstable; urgency=low
* Fixed debian/rules clean (Gregor Hoffleit)
-- Paul Brossier <piem@altern.org> Fri, 30 Jan 2004 01:05:20 +0000
pyrex (0.9.0-2) unstable; urgency=low
* chmod -x on Pyrex/Compiler/Lexicon.pickle and some other files
* fixed carriage return Changes.txt and ToDo.txt (s/\r/\r/g)
-- Paul Brossier <piem@altern.org> Sat, 10 Jan 2004 17:02:43 +0000
pyrex (0.9.0-1) unstable; urgency=low
* New upstream release.
-- Paul Brossier <piem@altern.org> Sat, 15 Nov 2003 11:51:47 +0000
pyrex (0.8.2-5) unstable; urgency=low
* Fixed Doc problem in python2.3-pyrex
* Added 2.2 2.3 diversions for /usr/bin/pyrexc
-- Paul Brossier <piem@altern.org> Mon, 22 Sep 2003 19:52:39 +0100
pyrex (0.8.2-4) unstable; urgency=low
* Added virtual package python-pyrex
* Added compilation for python2.2
* Removed dirs file
-- Paul Brossier <piem@altern.org> Tue, 16 Sep 2003 02:46:40 +0100
pyrex (0.8.2-3) unstable; urgency=low
* Fixed compilation warning at postinst in Plex/Transitions.py
* Header corrected to #!/urs/bin/python2.3 in pyrexc
* Fixed wrong placement of dh_python in debian/rules
* Removed Replaces: pyrex in control file
* Removed redundant Build-Depends-Indep on python
* Removed obsolete /usr/share/doc/pyrex in dirs
-- Paul Brossier <piem@altern.org> Tue, 16 Sep 2003 01:06:09 +0100
pyrex (0.8.2-2) unstable; urgency=low
* Renamed binary from pyrex to python2.3-pyrex
* Added Replaces: pyrex
* Added missing changelog entries
* Added build dependancie to python2.3-dev
* Corrected dependancies to use dh_python
* Updated rules to use distutil and dh_python
* Removed old prerm to let dh_python handle it
* Specify manpage in debian/rules
-- Paul Brossier <piem@altern.org> Sat, 13 Sep 2003 11:39:51 +0100
pyrex (0.8.2-1) unstable; urgency=low
* New upstream release
* Fixed broken distutils
* Removed obsolote README.Debian
* Updated maintainer
-- Paul Brossier <piem@altern.org> Wed, 3 Sep 2003 12:26:29 +0100
pyrex (0.8.1-1) unstable; urgency=low
* New upstream release
-- Paul Brossier <piem@altern.org> Mon, 30 Jun 2003 17:05:37 +0100
pyrex (0.7.2-1) unstable; urgency=low
* New upstream release
* Renamed my version of setup.py in the Demos directory to setup_all.py
-- Peter Harris <scav@blueyonder.co.uk> Thu, 24 Apr 2003 10:03:55 +0100
pyrex (0.7-1) unstable; urgency=low
* New upstream release
-- Peter Harris <scav@blueyonder.co.uk> Thu, 10 Apr 2003 22:28:34 +0100
pyrex (0.6.1-2) unstable; urgency=low
* Added Makefile.debian in Demos directory, uses python2.2 explicitly.
* Changed setup.py in demos directory to be an example of a setup.py that
builds all .pyx files in current directory.
-- Peter Harris <scav@blueyonder.co.uk> Wed, 9 Apr 2003 23:01:13 +0100
pyrex (0.6.1-1) unstable; urgency=low
* New upstream release
-- Peter Harris <scav@blueyonder.co.uk> Fri, 4 Apr 2003 21:54:54 +0100
pyrex (0.5-1) unstable; urgency=low
* 0.5-1
Upstream bug-fix release
* Initial Release.
Makefiles in Demos directory changed to refer explicitly to python2.2
where it is expected to be installed on Debian.
-- Peter Harris <scav@blueyonder.co.uk> Fri, 06 Dec 2002 16:30:00 +0000

@ -0,0 +1,35 @@
Source: pyrex
Section: deps-r14/python
Priority: optional
Maintainer: Paul Brossier <piem@debian.org>
Build-Depends: debhelper (>= 5.0.37.2),
python-all-dev (>= 2.6.6-3~),
dh-python
Standards-Version: 3.9.8
Homepage: http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
Vcs-Bzr: http://bzr.debian.org/users/piem/pyrex/
Vcs-Browser: http://bzr.debian.org/loggerhead/users/piem/pyrex/
X-Python-Version: 2.7
Package: python-pyrex
Architecture: all
Depends: ${python:Depends}, ${misc:Depends}, python-dev | python2-dev | python-all-dev
Provides: ${python:Provides}
Recommends: python-all-dev
Description: compile native-code modules for Python from Python-like syntax
Pyrex lets you write code that mixes Python and C data types any way you want,
and compiles it into a C extension for Python.
.
You can get very large speedups for tasks that don't need all the dynamic
features of Python, with very small differences in syntax and much less
hassle than writing your modules from scratch in C.
Package: pyrex-mode
Architecture: all
Depends: python-mode | emacs22, ${misc:Depends}
Description: emacs-lisp pyrex-mode for pyrex
Pyrex lets you write code that mixes Python and C data types any way you want,
and compiles it into a C extension for Python.
.
This Emacs mode is derived from the Python language mode, python-mode,
and provides syntax highlighting for Pyrex scripts.

@ -0,0 +1,44 @@
This package was first debianized by Peter Harris <scav@blueyonder.co.uk> on
Tue, 26 Nov 2002 11:08:39 +0000.
It is now maintained by Paul Brossier <piem@debian.org>
This version was downloaded from
http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/
Upstream Author: Greg Ewing <greg@cosc.canterbury.ac.nz>
Copyright:
Copyright 2004-2009 greg@cosc.canterbury.ac.nz
Pyrex is free of restrictions. You can use, redistribute or modify it however
you want.
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
Except for the file Pyrex/Mac/macglue.h:
Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
The Netherlands.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

@ -0,0 +1,24 @@
--- pyrex-0.9.8.5~/Pyrex/Plex/Errors.py 2003-07-08 18:35:31.000000000 +1000
+++ pyrex-0.9.8.5/Pyrex/Plex/Errors.py 2009-05-24 00:53:54.000000000 +1000
@@ -9,7 +9,7 @@
import exceptions
class PlexError(exceptions.Exception):
- message = ""
+ pass
class PlexTypeError(PlexError, TypeError):
pass
@@ -29,10 +29,10 @@
pass
class AmbiguousAction(PlexError):
- message = "Two tokens with different actions can match the same string"
def __init__(self):
- pass
+ PlexError.__init__(self, "Two tokens with different actions can match the same string")
+
class UnrecognizedInput(PlexError):
scanner = None

@ -0,0 +1 @@
baseexception.patch

@ -0,0 +1,15 @@
;;;; `Pyrex' mode.
(provide 'pyrex-mode)
(define-derived-mode pyrex-mode python-mode "Pyrex"
(font-lock-add-keywords
nil
`((,(concat "\\<\\(NULL"
"\\|c\\(def\\|har\\|typedef\\)"
"\\|e\\(num\\|xtern\\)"
"\\|float"
"\\|in\\(clude\\|t\\)"
"\\|object\\|public\\|struct\\|type\\|union\\|void"
"\\)\\>")
1 font-lock-keyword-face t))))

@ -0,0 +1,23 @@
;; -*-emacs-lisp-*-
;;
;; Emacs startup file, e.g. /etc/emacs/site-start.d/50pyrex-mode.el
;; for the Debian pyrex-mode package
;;
;; The pyrex-mode package follows the Debian/GNU Linux 'emacsen' policy and
;; byte-compiles its elisp files for each 'emacs flavor' (emacs19,
;; xemacs19, emacs20, xemacs20...). The compiled code is then installed
;; in a subdirectory of the respective site-lisp directory.
;; If package-dir does not exist, the pyrex-mode package must have
;; been removed but not purged, and we should skip the setup.
(if (not (file-exists-p "/usr/share/emacs/site-lisp/pyrex-mode.el"))
(message "Package pyrex-mode removed but not purged. Skipping setup")
;; Otherwise, autoload the pyrex-mode for the following extensions
(autoload 'pyrex-mode "pyrex-mode" "Pyrex editing mode." t)
(add-to-list 'auto-mode-alist '("\\.pyx$" . pyrex-mode))
(add-to-list 'auto-mode-alist '("\\.pxd$" . pyrex-mode))
(add-to-list 'auto-mode-alist '("\\.pxi$" . pyrex-mode))
;; endif
)

@ -0,0 +1 @@
debian/pyrex-mode.el usr/share/emacs/site-lisp

@ -0,0 +1,43 @@
.\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH PYREXC 1 "November 26, 2002"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh disable hyphenation
.\" .hy enable hyphenation
.\" .ad l left justify
.\" .ad b justify to both left and right margins
.\" .nf disable filling
.\" .fi enable filling
.\" .br insert line break
.\" .sp <n> insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
pyrexc \- compile python-like .pyx file to C for use as python module
.SH SYNOPSIS
.B pyrexc
.RI " files" ...
.SH DESCRIPTION
This manual page documents briefly the
.B pyrexc
command.
This manual page was written for the Debian distribution
because the original program does not have a manual page.
.PP
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
.\" respectively.
\fBpyrexc\fP is a python script that converts a .pyx file to C, so it can
be compiled for use as a Python module.
.PP
You then need to compile the .c file along with the include files for
Python, and link it into a shared library.
.PP
The HTML documentation explains this better, and the Demo examples show how
to automate the compile and link stages more easily.
.SH AUTHOR
This manual page was written by Peter Harris <scav@blueyonder.co.uk>,
for the Debian GNU/Linux system (but may be used by others).

@ -0,0 +1,10 @@
Document: python-pyrex
Title: Debian pyrex Manual
Author: various
Abstract: These HTML pages describes what pyrex is
and how it can be used.
Section: Programming/Python
Format: HTML
Index: /usr/share/doc/python-pyrex/Doc/index.html
Files: /usr/share/doc/python-pyrex/Doc/*.html

@ -0,0 +1,5 @@
README.txt
ToDo.txt
USAGE.txt
Doc
Demos

@ -0,0 +1,7 @@
#! /bin/sh
if which python#VERS# > /dev/null; then
exec python#VERS# -c 'from Pyrex.Compiler.Main import main; main(command_line = 1)' $*
else
echo python#VERS# not found
exit 1
fi

@ -0,0 +1,93 @@
#!/usr/bin/make -f
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
include /usr/share/python/python.mk
PYTHON := /usr/bin/python2
PYVERS := $(shell pyversions -vr debian/control)
PYVER := $(shell python -c 'import sys; print sys.version[:3]')
PYREXC=pyrexc
post-patches:
# make sure that python binary exists
# since the existing code is still dependent on python2
# and cdbs uses python as the default binary name
test -x /usr/bin/python || ln -s python2 /usr/bin/python
configure: configure-stamp
configure-stamp:
dh_testdir
# nothing to do
touch configure-stamp
build-arch: build
build-indep: build
build: build-stamp
build-stamp: configure-stamp
# make sure most files are not executable
find [DPTCs]* -type f -exec chmod -x {} \;
dh_testdir
# nothing to do
touch build-stamp
clean: clean1st
clean1st:
dh_testdir
dh_testroot
rm -f build-stamp configure-stamp
$(PYTHON) setup.py clean --all ;\
# delete *.pyc generated by setup.py
find . -name '*.pyc' -exec rm -rf {} \;
rm -f build-stamp
dh_clean
install: build
dh_testdir
dh_testroot
dh_prep
dh_installdirs
# fix executable file : headers, names
# $$file -> python$$version-$$file
$(PYTHON) setup.py install --root=$(CURDIR)/debian/python-pyrex --no-compile $(py_setup_install_args)
for python in $(PYVERS); do \
sed 's/#VERS#/'$$python'/g' debian/pythonX.Y-pyrexc > debian/python-pyrex/usr/bin/python$$python-pyrexc ; \
chmod 755 debian/python-pyrex/usr/bin/python$$python-pyrexc ; \
done
dh_install -p pyrex-mode
binary-arch:
binary-indep: build install
dh_testdir
dh_testroot
dh_installdebconf
dh_installchangelogs CHANGES.txt
dh_installdocs
dh_installemacsen
dh_installexamples
dh_installman debian/pyrexc.1
# default version link for binary and manpage
for python in $(PYVERS); \
do dh_link -ppython-pyrex \
usr/share/man/man1/$(PYREXC).1.gz \
usr/share/man/man1/python$$python-$(PYREXC).1.gz ;\
done
dh_strip
dh_compress
dh_fixperms
dh_python2
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-arch binary-indep
.PHONY: build clean binary-indep binary-arch binary install configure clean1st

@ -0,0 +1,3 @@
# Use xz instead of gzip
compression = "xz"
compression-level = 9

@ -0,0 +1,2 @@
version=2
http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/ Pyrex-([0-9\.]*)\.tar\.gz

@ -0,0 +1,10 @@
glob:*.pyc
glob:*.o
glob:*.so
glob:.DS_Store
glob:*.pickle
glob:*.dep
glob:*.orig
glob:*.new
glob:*_copy.c
tags

@ -0,0 +1,6 @@
#
# Pyrex -- Main Program, generic
#
from Pyrex.Compiler.Main import main
main(command_line = 1)

@ -0,0 +1,48 @@
#
# Pyrex setup file
#
import distutils
from distutils.core import setup
from distutils.sysconfig import get_python_lib
import os, sys
execfile(distutils.util.convert_path('Pyrex/Compiler/Version.py'))
compiler_dir = os.path.join(get_python_lib(prefix=''), 'Pyrex', 'Compiler')
# Workaround for problem with distutils wininst
if sys.platform == "win32" and 'bdist_wininst' in sys.argv:
compiler_dir = compiler_dir[len(sys.prefix)+1:]
def packages():
result = []
def find_packages(dir, parent_names):
for name in os.listdir(dir):
subdir = os.path.join(dir, name)
if os.path.isdir(subdir) and os.path.exists(os.path.join(subdir, "__init__.py")):
pkg_names = parent_names + [name]
result.append(".".join(pkg_names))
find_packages(subdir, pkg_names)
source_dir = os.path.dirname(__file__) or os.curdir
find_packages(source_dir, [])
return result
def scripts():
if os.name == "posix":
return ["bin/pyrexc"]
else:
return ["pyrexc.py"]
setup(
name = 'Pyrex',
version = version,
url = 'http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/',
author = 'Greg Ewing',
author_email = 'greg.ewing@canterbury.ac.nz',
scripts = scripts(),
packages = packages(),
data_files=[
(compiler_dir, ['Pyrex/Compiler/Lexicon.pickle'])
]
)

Binary file not shown.
Loading…
Cancel
Save