summaryrefslogtreecommitdiff
path: root/Cython/Compiler
diff options
context:
space:
mode:
Diffstat (limited to 'Cython/Compiler')
-rw-r--r--Cython/Compiler/Code.py18
-rw-r--r--Cython/Compiler/ExprNodes.py2
-rw-r--r--Cython/Compiler/ModuleNode.py2
-rw-r--r--Cython/Compiler/Nodes.py40
-rw-r--r--Cython/Compiler/PyrexTypes.py2
-rw-r--r--Cython/Compiler/Symtab.py17
-rw-r--r--Cython/Compiler/TypeSlots.py30
-rw-r--r--Cython/Compiler/Version.py2
8 files changed, 99 insertions, 14 deletions
diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py
index 196c4172e..f52f69627 100644
--- a/Cython/Compiler/Code.py
+++ b/Cython/Compiler/Code.py
@@ -6,6 +6,7 @@ import Naming
import Options
from Cython.Utils import open_new_file
from PyrexTypes import py_object_type, typecast
+from TypeSlots import method_coexist
class CCodeWriter:
# f file output file
@@ -288,12 +289,17 @@ class CCodeWriter:
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))
+ method_flags = entry.signature.method_flags()
+ if method_flags:
+ if entry.is_special:
+ method_flags += [method_coexist]
+ self.putln(
+ '{"%s", (PyCFunction)%s, %s, %s}%s' % (
+ entry.name,
+ entry.func_cname,
+ "|".join(method_flags),
+ doc_code,
+ term))
def put_error_if_neg(self, pos, value):
# return self.putln("if (unlikely(%s < 0)) %s" % (value, self.error_goto(pos))) # TODO this path is almost _never_ taken, yet this macro makes is slower!
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index f3eeeeb02..80b0845ed 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -699,6 +699,8 @@ class NameNode(AtomicExprNode):
#print "NameNode.analyse_target_declaration:", self.name ###
#print "...declaring as py_object_type" ###
self.entry = env.declare_var(self.name, py_object_type, self.pos)
+ if self.entry.is_declared_generic:
+ self.result_ctype = py_object_type
def analyse_types(self, env):
self.entry = env.lookup(self.name)
diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py
index d2d1d2923..1e5f09aeb 100644
--- a/Cython/Compiler/ModuleNode.py
+++ b/Cython/Compiler/ModuleNode.py
@@ -173,6 +173,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(" #define PY_SSIZE_T_MIN INT_MIN")
code.putln(" #define PyInt_FromSsize_t(z) PyInt_FromLong(z)")
code.putln(" #define PyInt_AsSsize_t(o) PyInt_AsLong(o)")
+ code.putln(" #define PyNumber_Index(o) PyNumber_Int(o)")
+ code.putln(" #define PyIndex_Check(o) PyNumber_Check(o)")
code.putln("#endif")
self.generate_extern_c_macro_definition(code)
code.putln("%s double pow(double, double);" % Naming.extern_c_macro)
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index 19e62970d..c447968a7 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -8,6 +8,7 @@ import Code
from Errors import error, warning, InternalError
import Naming
import PyrexTypes
+import TypeSlots
from PyrexTypes import py_object_type, error_type, CTypedefType
from Symtab import ModuleScope, LocalScope, \
StructOrUnionScope, PyClassScope, CClassScope
@@ -819,6 +820,18 @@ class DefNode(FuncDefNode):
def analyse_signature(self, env):
any_type_tests_needed = 0
+ # Use the simpler calling signature for zero- and one-argument functions.
+ if not self.entry.is_special and not self.star_arg and not self.starstar_arg:
+ if self.entry.signature is TypeSlots.pyfunction_signature:
+ if len(self.args) == 0:
+ self.entry.signature = TypeSlots.pyfunction_noargs
+ elif len(self.args) == 1 and self.args[0].default is None:
+ self.entry.signature = TypeSlots.pyfunction_onearg
+ elif self.entry.signature is TypeSlots.pymethod_signature:
+ if len(self.args) == 1:
+ self.entry.signature = TypeSlots.unaryfunc
+ elif len(self.args) == 2 and self.args[1].default is None:
+ self.entry.signature = TypeSlots.ibinaryfunc
sig = self.entry.signature
nfixed = sig.num_fixed_args()
for i in range(nfixed):
@@ -851,6 +864,12 @@ class DefNode(FuncDefNode):
if arg.is_generic and arg.type.is_extension_type:
arg.needs_type_test = 1
any_type_tests_needed = 1
+ elif arg.type is PyrexTypes.c_py_ssize_t_type:
+ # Want to use __index__ rather than __int__ method
+ # that PyArg_ParseTupleAndKeywords calls
+ arg.needs_conversion = 1
+ arg.hdr_type = PyrexTypes.py_object_type
+ arg.hdr_cname = Naming.arg_prefix + arg.name
if any_type_tests_needed:
env.use_utility_code(arg_type_test_utility_code)
@@ -957,6 +976,8 @@ class DefNode(FuncDefNode):
else:
arg_code_list.append(
arg.hdr_type.declaration_code(arg.hdr_cname))
+ if not self.entry.is_special and sig.method_flags() == [TypeSlots.method_noargs]:
+ arg_code_list.append("PyObject *unused")
if sig.has_generic_args:
arg_code_list.append(
"PyObject *%s, PyObject *%s"
@@ -980,7 +1001,10 @@ class DefNode(FuncDefNode):
def generate_argument_declarations(self, env, code):
for arg in self.args:
if arg.is_generic: # or arg.needs_conversion:
- code.put_var_declaration(arg.entry)
+ if arg.needs_conversion:
+ code.putln("PyObject *%s = 0;" % arg.hdr_cname)
+ else:
+ code.put_var_declaration(arg.entry)
def generate_keyword_list(self, code):
if self.entry.signature.has_generic_args:
@@ -994,7 +1018,7 @@ class DefNode(FuncDefNode):
arg.name)
code.putln(
"0};")
-
+
def generate_argument_parsing_code(self, code):
# Generate PyArg_ParseTuple call for generic
# arguments, if any.
@@ -1015,8 +1039,12 @@ class DefNode(FuncDefNode):
default_seen = 1
elif default_seen:
error(arg.pos, "Non-default argument following default argument")
- arg_addrs.append("&" + arg_entry.cname)
- format = arg_entry.type.parsetuple_format
+ if arg.needs_conversion:
+ arg_addrs.append("&" + arg.hdr_cname)
+ format = arg.hdr_type.parsetuple_format
+ else:
+ arg_addrs.append("&" + arg_entry.cname)
+ format = arg_entry.type.parsetuple_format
if format:
arg_formats.append(format)
else:
@@ -1088,7 +1116,9 @@ class DefNode(FuncDefNode):
old_type = arg.hdr_type
new_type = arg.type
if old_type.is_pyobject:
+ code.putln("if (likely(%s)) {" % arg.hdr_cname)
self.generate_arg_conversion_from_pyobject(arg, code)
+ code.putln("}")
elif new_type.is_pyobject:
self.generate_arg_conversion_to_pyobject(arg, code)
else:
@@ -2602,6 +2632,8 @@ typedef struct {const char *s; const void **p;} __Pyx_CApiTabEntry; /*proto*/
typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/
typedef struct {PyObject **p; char *s; long n; int is_unicode;} __Pyx_StringTabEntry; /*proto*/
+#define __pyx_PyIndex_AsSsize_t(b) PyInt_AsSsize_t(PyNumber_Index(b))
+
#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
static INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
if (x == Py_True) return 1;
diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py
index a7a6ca0ca..238cc6329 100644
--- a/Cython/Compiler/PyrexTypes.py
+++ b/Cython/Compiler/PyrexTypes.py
@@ -352,7 +352,7 @@ class CBIntType(CIntType):
class CPySSizeTType(CIntType):
to_py_function = "PyInt_FromSsize_t"
- from_py_function = "PyInt_AsSsize_t"
+ from_py_function = "__pyx_PyIndex_AsSsize_t"
class CUIntType(CIntType):
diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py
index 22122abf2..592b56982 100644
--- a/Cython/Compiler/Symtab.py
+++ b/Cython/Compiler/Symtab.py
@@ -7,6 +7,7 @@ from Errors import error, InternalError, warning
import Options
import Naming
from PyrexTypes import *
+import TypeSlots
from TypeSlots import \
pyfunction_signature, pymethod_signature, \
get_special_method_signature, get_property_accessor_signature
@@ -28,6 +29,7 @@ class Entry:
# is_pyglobal boolean Is a Python module-level variable
# or class attribute during
# class construction
+ # is_special boolean Is a special class method
# is_variable boolean Is a variable
# is_cfunction boolean Is a C function
# is_cmethod boolean Is a C method of an extension type
@@ -68,6 +70,7 @@ class Entry:
is_builtin = 0
is_cglobal = 0
is_pyglobal = 0
+ is_special = 0
is_variable = 0
is_cfunction = 0
is_cmethod = 0
@@ -198,6 +201,9 @@ class Scope:
# Create new entry, and add to dictionary if
# name is not None. Reports a warning if already
# declared.
+ if not self.in_cinclude and cname and re.match("^_[_A-Z]+$", cname):
+ # See http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html#Reserved-Names
+ warning(pos, "'%s' is a reserved name in C." % cname, -1)
dict = self.entries
if name and dict.has_key(name):
warning(pos, "'%s' redeclared " % name, 0)
@@ -1076,14 +1082,21 @@ class CClassScope(ClassScope):
def declare_pyfunction(self, name, pos):
# Add an entry for a method.
+ if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'):
+ error(pos, "Special method %s must be implemented via __richcmp__"
+% name)
entry = self.declare(name, name, py_object_type, pos)
special_sig = get_special_method_signature(name)
if special_sig:
+ # Special methods get put in the method table with a particular
+ # signature declared in advance.
entry.signature = special_sig
- # Special methods don't get put in the method table
+ entry.is_special = 1
else:
entry.signature = pymethod_signature
- self.pyfunc_entries.append(entry)
+ entry.is_special = 0
+
+ self.pyfunc_entries.append(entry)
return entry
def declare_cfunction(self, name, type, pos,
diff --git a/Cython/Compiler/TypeSlots.py b/Cython/Compiler/TypeSlots.py
index 530daa2c8..1f1d414db 100644
--- a/Cython/Compiler/TypeSlots.py
+++ b/Cython/Compiler/TypeSlots.py
@@ -82,6 +82,18 @@ class Signature:
def return_type(self):
return self.format_map[self.ret_format]
+
+ def method_flags(self):
+ if self.ret_format == "O":
+ full_args = "O" + self.fixed_arg_format if self.has_dummy_arg else self.fixed_arg_format
+ if full_args in ["O", "T"]:
+ if self.has_generic_args:
+ return [method_varargs, method_keywords]
+ else:
+ return [method_noargs]
+ elif full_args in ["OO", "TO"] and not self.has_generic_args:
+ return [method_onearg]
+ return None
class SlotDescriptor:
@@ -344,6 +356,15 @@ pymethod_signature = Signature("T*", "O")
#------------------------------------------------------------------------------------------
#
+# Signatures for simple Python functions.
+#
+#------------------------------------------------------------------------------------------
+
+pyfunction_noargs = Signature("-", "O")
+pyfunction_onearg = Signature("-O", "O")
+
+#------------------------------------------------------------------------------------------
+#
# Signatures for the various kinds of function that
# can appear in the type object and its substructures.
#
@@ -590,3 +611,12 @@ MethodSlot(delattrofunc, "", "__delattr__")
MethodSlot(descrgetfunc, "", "__get__")
MethodSlot(descrsetfunc, "", "__set__")
MethodSlot(descrdelfunc, "", "__delete__")
+
+
+# Method flags for python-exposed methods.
+
+method_noargs = "METH_NOARGS"
+method_onearg = "METH_O"
+method_varargs = "METH_VARARGS"
+method_keywords = "METH_KEYWORDS"
+method_coexist = "METH_COEXIST"
diff --git a/Cython/Compiler/Version.py b/Cython/Compiler/Version.py
index 54e34e5c4..47d6addf6 100644
--- a/Cython/Compiler/Version.py
+++ b/Cython/Compiler/Version.py
@@ -1 +1 @@
-version = '0.9.6'
+version = '0.9.6.4'