diff options
Diffstat (limited to 'Cython/Compiler')
-rw-r--r-- | Cython/Compiler/Code.py | 18 | ||||
-rw-r--r-- | Cython/Compiler/ExprNodes.py | 2 | ||||
-rw-r--r-- | Cython/Compiler/ModuleNode.py | 2 | ||||
-rw-r--r-- | Cython/Compiler/Nodes.py | 40 | ||||
-rw-r--r-- | Cython/Compiler/PyrexTypes.py | 2 | ||||
-rw-r--r-- | Cython/Compiler/Symtab.py | 17 | ||||
-rw-r--r-- | Cython/Compiler/TypeSlots.py | 30 | ||||
-rw-r--r-- | Cython/Compiler/Version.py | 2 |
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' |