Commit 1b78c83c authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

merge

parents 7fa1a3b4 139823ed
...@@ -15,7 +15,7 @@ class CythonScope(ModuleScope): ...@@ -15,7 +15,7 @@ class CythonScope(ModuleScope):
pos=None, pos=None,
defining = 1, defining = 1,
cname='<error>') cname='<error>')
def lookup_type(self, name): def lookup_type(self, name):
# This function should go away when types are all first-level objects. # This function should go away when types are all first-level objects.
type = parse_basic_type(name) type = parse_basic_type(name)
...@@ -23,4 +23,27 @@ class CythonScope(ModuleScope): ...@@ -23,4 +23,27 @@ class CythonScope(ModuleScope):
return type return type
def create_cython_scope(context): def create_cython_scope(context):
create_utility_scope(context)
return CythonScope(context) return CythonScope(context)
def create_utility_scope(context):
global utility_scope
utility_scope = ModuleScope(u'utility', None, context)
# These are used to optimize isinstance in FinalOptimizePhase
type_object = utility_scope.declare_typedef('PyTypeObject',
base_type = c_void_type,
pos = None,
cname = 'PyTypeObject')
type_object.is_void = True
utility_scope.declare_cfunction(
'PyObject_TypeCheck',
CFuncType(c_bint_type, [CFuncTypeArg("o", py_object_type, None),
CFuncTypeArg("t", c_ptr_type(type_object), None)]),
pos = None,
defining = 1,
cname = 'PyObject_TypeCheck')
return utility_scope
...@@ -9,6 +9,7 @@ from Errors import hold_errors, release_errors, held_errors, report_error ...@@ -9,6 +9,7 @@ from Errors import hold_errors, release_errors, held_errors, report_error
from Cython.Utils import UtilityCode from Cython.Utils import UtilityCode
import StringEncoding import StringEncoding
import Naming import Naming
import Nodes
from Nodes import Node from Nodes import Node
import PyrexTypes import PyrexTypes
from PyrexTypes import py_object_type, c_long_type, typecast, error_type from PyrexTypes import py_object_type, c_long_type, typecast, error_type
...@@ -384,6 +385,7 @@ class ExprNode(Node): ...@@ -384,6 +385,7 @@ class ExprNode(Node):
# this must be a temp node and the specified variable # this must be a temp node and the specified variable
# is used as the result instead of allocating a new # is used as the result instead of allocating a new
# one. # one.
assert result is None, "deprecated, contact dagss if this triggers"
if debug_temp_alloc: if debug_temp_alloc:
print("%s Allocating temps" % self) print("%s Allocating temps" % self)
self.allocate_subexpr_temps(env) self.allocate_subexpr_temps(env)
...@@ -620,7 +622,6 @@ class RemoveAllocateTemps(type): ...@@ -620,7 +622,6 @@ class RemoveAllocateTemps(type):
setattr(cls, 'release_temp', noop) setattr(cls, 'release_temp', noop)
class NewTempExprNode(ExprNode): class NewTempExprNode(ExprNode):
backwards_compatible_result = None
temp_code = None temp_code = None
old_temp = None # error checker for multiple frees etc. old_temp = None # error checker for multiple frees etc.
...@@ -643,8 +644,8 @@ class NewTempExprNode(ExprNode): ...@@ -643,8 +644,8 @@ class NewTempExprNode(ExprNode):
self.release_subexpr_temps(env) self.release_subexpr_temps(env)
def allocate_temps(self, env, result = None): def allocate_temps(self, env, result = None):
assert result is None, "deprecated, contact dagss if this triggers"
self.allocate_subexpr_temps(env) self.allocate_subexpr_temps(env)
self.backwards_compatible_result = result
if self.is_temp: if self.is_temp:
self.release_subexpr_temps(env) self.release_subexpr_temps(env)
...@@ -664,11 +665,8 @@ class NewTempExprNode(ExprNode): ...@@ -664,11 +665,8 @@ class NewTempExprNode(ExprNode):
if not type.is_void: if not type.is_void:
if type.is_pyobject: if type.is_pyobject:
type = PyrexTypes.py_object_type type = PyrexTypes.py_object_type
if self.backwards_compatible_result: self.temp_code = code.funcstate.allocate_temp(
self.temp_code = self.backwards_compatible_result type, manage_ref=True)
else:
self.temp_code = code.funcstate.allocate_temp(
type, manage_ref=True)
else: else:
self.temp_code = None self.temp_code = None
...@@ -4265,7 +4263,14 @@ class DivNode(NumBinopNode): ...@@ -4265,7 +4263,14 @@ class DivNode(NumBinopNode):
# '/' or '//' operator. # '/' or '//' operator.
cdivision = None cdivision = None
cdivision_warnings = False
def analyse_types(self, env):
NumBinopNode.analyse_types(self, env)
if not self.type.is_pyobject and env.directives['cdivision_warnings']:
self.operand1 = self.operand1.coerce_to_simple(env)
self.operand2 = self.operand2.coerce_to_simple(env)
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
if not self.type.is_pyobject: if not self.type.is_pyobject:
if self.cdivision is None: if self.cdivision is None:
...@@ -4273,11 +4278,27 @@ class DivNode(NumBinopNode): ...@@ -4273,11 +4278,27 @@ class DivNode(NumBinopNode):
or not self.type.signed or not self.type.signed
or self.type.is_float) or self.type.is_float)
if not self.cdivision: if not self.cdivision:
code.globalstate.use_utility_code(div_utility_code.specialize(self.type)) code.globalstate.use_utility_code(div_int_utility_code.specialize(self.type))
NumBinopNode.generate_evaluation_code(self, code) NumBinopNode.generate_evaluation_code(self, code)
if not self.type.is_pyobject and code.globalstate.directives['cdivision_warnings']:
self.generate_div_warning_code(code)
def generate_div_warning_code(self, code):
code.globalstate.use_utility_code(cdivision_warning_utility_code)
code.putln("if ((%s < 0) ^ (%s < 0)) {" % (
self.operand1.result(),
self.operand2.result()))
code.putln(code.set_error_info(self.pos));
code.put("if (__Pyx_cdivision_warning()) ")
code.put_goto(code.error_label)
code.putln("}")
def calculate_result_code(self): def calculate_result_code(self):
if self.cdivision: if self.type.is_float and self.operator == '//':
return "floor(%s / %s)" % (
self.operand1.result(),
self.operand2.result())
elif self.cdivision:
return "(%s / %s)" % ( return "(%s / %s)" % (
self.operand1.result(), self.operand1.result(),
self.operand2.result()) self.operand2.result())
...@@ -4288,11 +4309,9 @@ class DivNode(NumBinopNode): ...@@ -4288,11 +4309,9 @@ class DivNode(NumBinopNode):
self.operand2.result()) self.operand2.result())
class ModNode(NumBinopNode): class ModNode(DivNode):
# '%' operator. # '%' operator.
cdivision = None
def is_py_operation(self): def is_py_operation(self):
return (self.operand1.type.is_string return (self.operand1.type.is_string
or self.operand2.type.is_string or self.operand2.type.is_string
...@@ -4303,11 +4322,14 @@ class ModNode(NumBinopNode): ...@@ -4303,11 +4322,14 @@ class ModNode(NumBinopNode):
if self.cdivision is None: if self.cdivision is None:
self.cdivision = code.globalstate.directives['cdivision'] or not self.type.signed self.cdivision = code.globalstate.directives['cdivision'] or not self.type.signed
if not self.cdivision: if not self.cdivision:
math_h_modifier = getattr(self.type, 'math_h_modifier', '__Pyx_INT')
if self.type.is_int: if self.type.is_int:
code.globalstate.use_utility_code(mod_int_helper_macro) code.globalstate.use_utility_code(mod_int_utility_code.specialize(self.type))
code.globalstate.use_utility_code(mod_utility_code.specialize(self.type, math_h_modifier=math_h_modifier)) else:
code.globalstate.use_utility_code(
mod_float_utility_code.specialize(self.type, math_h_modifier=self.type.math_h_modifier))
NumBinopNode.generate_evaluation_code(self, code) NumBinopNode.generate_evaluation_code(self, code)
if not self.type.is_pyobject and code.globalstate.directives['cdivision_warnings']:
self.generate_div_warning_code(code)
def calculate_result_code(self): def calculate_result_code(self):
if self.cdivision: if self.cdivision:
...@@ -4510,32 +4532,9 @@ class CondExprNode(ExprNode): ...@@ -4510,32 +4532,9 @@ class CondExprNode(ExprNode):
if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject: if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject:
self.true_val = self.true_val.coerce_to(self.type, env) self.true_val = self.true_val.coerce_to(self.type, env)
self.false_val = self.false_val.coerce_to(self.type, env) self.false_val = self.false_val.coerce_to(self.type, env)
# must be tmp variables so they can share a result
self.true_val = self.true_val.coerce_to_temp(env)
self.false_val = self.false_val.coerce_to_temp(env)
self.is_temp = 1 self.is_temp = 1
if self.type == PyrexTypes.error_type: if self.type == PyrexTypes.error_type:
self.type_error() self.type_error()
def allocate_temps(self, env, result_code = None):
# We only ever evaluate one side, and this is
# after evaluating the truth value, so we may
# use an allocation strategy here which results in
# this node and both its operands sharing the same
# result variable. This allows us to avoid some
# assignments and increfs/decrefs that would otherwise
# be necessary.
self.allocate_temp(env, result_code)
self.test.allocate_temps(env, result_code)
self.true_val.allocate_temps(env, self.result())
self.false_val.allocate_temps(env, self.result())
# We haven't called release_temp on either value,
# because although they are temp nodes, they don't own
# their result variable. And because they are temp
# nodes, any temps in their subnodes will have been
# released before their allocate_temps returned.
# Therefore, they contain no temp vars that need to
# be released.
def compute_result_type(self, type1, type2): def compute_result_type(self, type1, type2):
if type1 == type2: if type1 == type2:
...@@ -4567,15 +4566,27 @@ class CondExprNode(ExprNode): ...@@ -4567,15 +4566,27 @@ class CondExprNode(ExprNode):
self.false_val.check_const() self.false_val.check_const()
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
# Because subexprs may not be evaluated we can use a more optimal
# subexpr allocation strategy than the default, so override evaluation_code.
code.mark_pos(self.pos)
#self.allocate_temp_result(code) # uncomment this when we switch to new temps
self.test.generate_evaluation_code(code) self.test.generate_evaluation_code(code)
code.putln("if (%s) {" % self.test.result() ) code.putln("if (%s) {" % self.test.result() )
self.true_val.generate_evaluation_code(code) self.eval_and_get(code, self.true_val)
code.putln("} else {") code.putln("} else {")
self.false_val.generate_evaluation_code(code) self.eval_and_get(code, self.false_val)
code.putln("}") code.putln("}")
self.test.generate_disposal_code(code) self.test.generate_disposal_code(code)
self.test.free_temps(code) self.test.free_temps(code)
def eval_and_get(self, code, expr):
expr.generate_evaluation_code(code)
expr.make_owned_reference(code)
code.putln("%s = %s;" % (self.result(), expr.result()))
expr.generate_post_assignment_code(code)
expr.free_temps(code)
richcmp_constants = { richcmp_constants = {
"<" : "Py_LT", "<" : "Py_LT",
"<=": "Py_LE", "<=": "Py_LE",
...@@ -5716,31 +5727,58 @@ static INLINE %(type)s %(func_name)s(%(type)s b, %(type)s e) { ...@@ -5716,31 +5727,58 @@ static INLINE %(type)s %(func_name)s(%(type)s b, %(type)s e) {
# ------------------------------ Division ------------------------------------ # ------------------------------ Division ------------------------------------
# This is so we can treat floating point and integer mod simultaneously. div_int_utility_code = UtilityCode(
mod_int_helper_macro = UtilityCode(proto=""" proto="""
#define fmod__Pyx_INT(a, b) ((a) % (b)) static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s, %(type)s); /* proto */
""",
impl="""
static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) {
%(type)s q = a / b;
%(type)s r = a - q*b;
q -= ((r != 0) & ((r ^ b) < 0));
return q;
}
""") """)
mod_utility_code = UtilityCode( mod_int_utility_code = UtilityCode(
proto=""" proto="""
static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */ static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */
""", """,
impl=""" impl="""
static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) { static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) {
%(type)s res = fmod%(math_h_modifier)s(a, b); %(type)s r = a %% b;
res += (res * b < 0) * b; r += ((r != 0) & ((r ^ b) < 0)) * b;
return res; return r;
} }
""") """)
div_utility_code = UtilityCode( mod_float_utility_code = UtilityCode(
proto=""" proto="""
static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s, %(type)s); /* proto */ static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */
""", """,
impl=""" impl="""
static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) { static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) {
%(type)s res = a / b; %(type)s r = fmod%(math_h_modifier)s(a, b);
res -= (res < 0); r += ((r != 0) & ((r < 0) ^ (b < 0))) * b;
return res; return r;
} }
""") """)
cdivision_warning_utility_code = UtilityCode(
proto="""
static int __Pyx_cdivision_warning(void); /* proto */
""",
impl="""
static int __Pyx_cdivision_warning(void) {
return PyErr_WarnExplicit(PyExc_RuntimeWarning,
"division with oppositely signed operands, C and Python semantics differ",
%(FILENAME)s,
%(LINENO)s,
%(MODULENAME)s,
NULL);
}
""" % {
'FILENAME': Naming.filename_cname,
'MODULENAME': Naming.modulename_cname,
'LINENO': Naming.lineno_cname,
})
...@@ -253,6 +253,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -253,6 +253,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.globalstate.use_utility_code(refcount_utility_code) code.globalstate.use_utility_code(refcount_utility_code)
code.putln('const char *%s = "%s";' % (Naming.modulename_cname, self.full_module_name))
code.putln("") code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name) code.putln("/* Implementation of %s */" % env.qualified_name)
......
...@@ -53,6 +53,7 @@ preimport_cname = pyrex_prefix + "i" ...@@ -53,6 +53,7 @@ preimport_cname = pyrex_prefix + "i"
moddict_cname = pyrex_prefix + "d" moddict_cname = pyrex_prefix + "d"
dummy_cname = pyrex_prefix + "dummy" dummy_cname = pyrex_prefix + "dummy"
filename_cname = pyrex_prefix + "filename" filename_cname = pyrex_prefix + "filename"
modulename_cname = pyrex_prefix + "modulename"
filetable_cname = pyrex_prefix + "f" filetable_cname = pyrex_prefix + "f"
filenames_cname = pyrex_prefix + "filenames" filenames_cname = pyrex_prefix + "filenames"
fileinit_cname = pyrex_prefix + "init_filenames" fileinit_cname = pyrex_prefix + "init_filenames"
......
...@@ -515,7 +515,8 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -515,7 +515,8 @@ class CFuncDeclaratorNode(CDeclaratorNode):
if self.optional_arg_count: if self.optional_arg_count:
scope = StructOrUnionScope() scope = StructOrUnionScope()
scope.declare_var('%sn' % Naming.pyrex_prefix, PyrexTypes.c_int_type, self.pos) arg_count_member = '%sn' % Naming.pyrex_prefix
scope.declare_var(arg_count_member, PyrexTypes.c_int_type, self.pos)
for arg in func_type_args[len(func_type_args)-self.optional_arg_count:]: for arg in func_type_args[len(func_type_args)-self.optional_arg_count:]:
scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject = 1) scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject = 1)
struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name) struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name)
...@@ -541,6 +542,7 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -541,6 +542,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
exc_val = self.exception_value.get_constant_result_code() exc_val = self.exception_value.get_constant_result_code()
if self.exception_check == '+': if self.exception_check == '+':
exc_val_type = self.exception_value.type exc_val_type = self.exception_value.type
env.add_include_file('stdexcept')
if not exc_val_type.is_error and \ if not exc_val_type.is_error and \
not exc_val_type.is_pyobject and \ not exc_val_type.is_pyobject and \
not (exc_val_type.is_cfunction and not exc_val_type.return_type.is_pyobject and len(exc_val_type.args)==0): not (exc_val_type.is_cfunction and not exc_val_type.return_type.is_pyobject and len(exc_val_type.args)==0):
...@@ -1354,6 +1356,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -1354,6 +1356,7 @@ class CFuncDefNode(FuncDefNode):
error(self.pos, "Function declared nogil has Python locals or temporaries") error(self.pos, "Function declared nogil has Python locals or temporaries")
def analyse_expressions(self, env): def analyse_expressions(self, env):
self.local_scope.directives = env.directives
if self.py_func is not None: if self.py_func is not None:
# this will also analyse the default values # this will also analyse the default values
self.py_func.analyse_expressions(env) self.py_func.analyse_expressions(env)
...@@ -1410,6 +1413,8 @@ class CFuncDefNode(FuncDefNode): ...@@ -1410,6 +1413,8 @@ class CFuncDefNode(FuncDefNode):
code.putln('if (%s) {' % Naming.optional_args_cname) code.putln('if (%s) {' % Naming.optional_args_cname)
for arg in self.args: for arg in self.args:
if arg.default: if arg.default:
# FIXME: simple name prefixing doesn't work when
# argument name mangling is in place
code.putln('if (%s->%sn > %s) {' % (Naming.optional_args_cname, Naming.pyrex_prefix, i)) code.putln('if (%s->%sn > %s) {' % (Naming.optional_args_cname, Naming.pyrex_prefix, i))
declarator = arg.declarator declarator = arg.declarator
while not hasattr(declarator, 'name'): while not hasattr(declarator, 'name'):
...@@ -1778,6 +1783,7 @@ class DefNode(FuncDefNode): ...@@ -1778,6 +1783,7 @@ class DefNode(FuncDefNode):
env.control_flow.set_state((), (arg.name, 'initalized'), True) env.control_flow.set_state((), (arg.name, 'initalized'), True)
def analyse_expressions(self, env): def analyse_expressions(self, env):
self.local_scope.directives = env.directives
self.analyse_default_values(env) self.analyse_default_values(env)
if env.is_py_class_scope: if env.is_py_class_scope:
self.synthesize_assignment_node(env) self.synthesize_assignment_node(env)
...@@ -4943,7 +4949,8 @@ static int __Pyx_PrintOne(PyObject *o) { ...@@ -4943,7 +4949,8 @@ static int __Pyx_PrintOne(PyObject *o) {
} }
#endif #endif
""") """,
requires=[printing_utility_code])
...@@ -5308,32 +5315,6 @@ bad: ...@@ -5308,32 +5315,6 @@ bad:
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
unraisable_exception_utility_code = UtilityCode(
proto = """
static void __Pyx_WriteUnraisable(const char *name); /*proto*/
""",
impl = """
static void __Pyx_WriteUnraisable(const char *name) {
PyObject *old_exc, *old_val, *old_tb;
PyObject *ctx;
__Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
#if PY_MAJOR_VERSION < 3
ctx = PyString_FromString(name);
#else
ctx = PyUnicode_FromString(name);
#endif
__Pyx_ErrRestore(old_exc, old_val, old_tb);
if (!ctx) {
PyErr_WriteUnraisable(Py_None);
} else {
PyErr_WriteUnraisable(ctx);
Py_DECREF(ctx);
}
}
""")
#------------------------------------------------------------------------------------
traceback_utility_code = UtilityCode( traceback_utility_code = UtilityCode(
proto = """ proto = """
static void __Pyx_AddTraceback(const char *funcname); /*proto*/ static void __Pyx_AddTraceback(const char *funcname); /*proto*/
...@@ -5478,6 +5459,33 @@ static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject ** ...@@ -5478,6 +5459,33 @@ static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
unraisable_exception_utility_code = UtilityCode(
proto = """
static void __Pyx_WriteUnraisable(const char *name); /*proto*/
""",
impl = """
static void __Pyx_WriteUnraisable(const char *name) {
PyObject *old_exc, *old_val, *old_tb;
PyObject *ctx;
__Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
#if PY_MAJOR_VERSION < 3
ctx = PyString_FromString(name);
#else
ctx = PyUnicode_FromString(name);
#endif
__Pyx_ErrRestore(old_exc, old_val, old_tb);
if (!ctx) {
PyErr_WriteUnraisable(Py_None);
} else {
PyErr_WriteUnraisable(ctx);
Py_DECREF(ctx);
}
}
""",
requires=[restore_exception_utility_code])
#------------------------------------------------------------------------------------
set_vtable_utility_code = UtilityCode( set_vtable_utility_code = UtilityCode(
proto = """ proto = """
static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/ static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
......
...@@ -655,11 +655,9 @@ class FinalOptimizePhase(Visitor.CythonTransform): ...@@ -655,11 +655,9 @@ class FinalOptimizePhase(Visitor.CythonTransform):
if node.function.name == 'isinstance': if node.function.name == 'isinstance':
type_arg = node.args[1] type_arg = node.args[1]
if type_arg.type.is_builtin_type and type_arg.type.name == 'type': if type_arg.type.is_builtin_type and type_arg.type.name == 'type':
object_module = self.context.find_module('python_object') from CythonScope import utility_scope
node.function.entry = object_module.lookup('PyObject_TypeCheck') node.function.entry = utility_scope.lookup('PyObject_TypeCheck')
if node.function.entry is None:
return node # only happens when there was an error earlier
node.function.type = node.function.entry.type node.function.type = node.function.entry.type
PyTypeObjectPtr = PyrexTypes.CPtrType(object_module.lookup('PyTypeObject').type) PyTypeObjectPtr = PyrexTypes.CPtrType(utility_scope.lookup('PyTypeObject').type)
node.args[1] = ExprNodes.CastNode(node.args[1], PyTypeObjectPtr) node.args[1] = ExprNodes.CastNode(node.args[1], PyTypeObjectPtr)
return node return node
...@@ -62,6 +62,7 @@ option_defaults = { ...@@ -62,6 +62,7 @@ option_defaults = {
'locals' : {}, 'locals' : {},
'auto_cpdef': False, 'auto_cpdef': False,
'cdivision': True, # Will be False in 0.12 'cdivision': True, # Will be False in 0.12
'cdivision_warnings': False,
} }
# Override types possibilities above, if needed # Override types possibilities above, if needed
......
...@@ -23,6 +23,19 @@ except NameError: ...@@ -23,6 +23,19 @@ except NameError:
possible_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match possible_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match
ansi_c_keywords = set(
['auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do',
'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if',
'int', 'long', 'register', 'return', 'short', 'signed', 'sizeof',
'static', 'struct', 'switch', 'typedef', 'union', 'unsigned', 'void',
'volatile', 'while'])
def c_safe_identifier(cname):
# There are some C limitations on struct entry names.
if (cname[:2] == '__' and not cname.startswith(Naming.pyrex_prefix)) or cname in ansi_c_keywords:
cname = Naming.pyrex_prefix + cname
return cname
class BufferAux(object): class BufferAux(object):
writable_needed = False writable_needed = False
...@@ -1125,6 +1138,8 @@ class StructOrUnionScope(Scope): ...@@ -1125,6 +1138,8 @@ class StructOrUnionScope(Scope):
# Add an entry for an attribute. # Add an entry for an attribute.
if not cname: if not cname:
cname = name cname = name
if visibility == 'private':
cname = c_safe_identifier(cname)
if type.is_cfunction: if type.is_cfunction:
type = PyrexTypes.CPtrType(type) type = PyrexTypes.CPtrType(type)
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility)
...@@ -1259,6 +1274,8 @@ class CClassScope(ClassScope): ...@@ -1259,6 +1274,8 @@ class CClassScope(ClassScope):
% name) % name)
if not cname: if not cname:
cname = name cname = name
if visibility == 'private':
cname = c_safe_identifier(cname)
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1 entry.is_variable = 1
self.var_entries.append(entry) self.var_entries.append(entry)
......
...@@ -6,6 +6,19 @@ def empty_decorator(x): ...@@ -6,6 +6,19 @@ def empty_decorator(x):
def locals(**arg_types): def locals(**arg_types):
return empty_decorator return empty_decorator
# Special functions
def cdiv(a, b):
q = a / b
if q < 0:
q += 1
def cmod(a, b):
r = a % b
if (a*b) < 0:
r -= b
return r
# Emulated language constructs # Emulated language constructs
......
...@@ -106,6 +106,7 @@ setup( ...@@ -106,6 +106,7 @@ setup(
"Operating System :: OS Independent", "Operating System :: OS Independent",
"Programming Language :: Python", "Programming Language :: Python",
"Programming Language :: C", "Programming Language :: C",
"Programming Language :: Cython",
"Topic :: Software Development :: Code Generators", "Topic :: Software Development :: Code Generators",
"Topic :: Software Development :: Compilers", "Topic :: Software Development :: Compilers",
"Topic :: Software Development :: Libraries :: Python Modules" "Topic :: Software Development :: Libraries :: Python Modules"
......
"""
>>> constants(4)
1
>>> constants(5)
10
>>> temps(4)
1
>>> temps(5)
10
>>> nested(1)
1
>>> nested(2)
2
>>> nested(3)
3
"""
def ident(x): return x
def constants(x):
a = 1 if x < 5 else 10
return a
def temps(x):
return ident(1) if ident(x) < ident(5) else ident(10)
def nested(x):
return 1 if x == 1 else (2 if x == 2 else 3)
cdef class Album
cdef class SessionStruct:
cdef Album _create_album(self, void* album, bint take_owner):
pass
cdef class Album(SessionStruct):
pass
_ERROR = u"""
"""
cdef f(void=None):
pass
cdef struct foo:
int void
cdef class Foo:
cdef int void
...@@ -23,9 +23,9 @@ else: ...@@ -23,9 +23,9 @@ else:
_ERRORS = u''' _ERRORS = u'''
2:0: break statement not inside loop 2:0: break statement not inside loop
5:4: break statement not inside loop 5:4: break statement not inside loop
8:4: break statement not inside loop 8:4: break statement not inside loop
11:4: break statement not inside loop 11:4: break statement not inside loop
16:5: break statement not inside loop 16:5: break statement not inside loop
20:4: break statement not inside loop 20:4: break statement not inside loop
......
...@@ -10,6 +10,6 @@ NEW_ERRORS = u""" ...@@ -10,6 +10,6 @@ NEW_ERRORS = u"""
""" """
_ERRORS = u""" _ERRORS = u"""
:5:16: Cannot coerce list to type 'list' 5:16: Cannot coerce list to type 'list'
""" """
...@@ -23,9 +23,9 @@ else: ...@@ -23,9 +23,9 @@ else:
_ERRORS = u''' _ERRORS = u'''
2:0: continue statement not inside loop 2:0: continue statement not inside loop
5:4: continue statement not inside loop 5:4: continue statement not inside loop
8:4: continue statement not inside loop 8:4: continue statement not inside loop
11:4: continue statement not inside loop 11:4: continue statement not inside loop
16:5: continue statement not inside loop 16:5: continue statement not inside loop
20:4: continue statement not inside loop 20:4: continue statement not inside loop
......
...@@ -5,6 +5,6 @@ cdef void foo(obj): ...@@ -5,6 +5,6 @@ cdef void foo(obj):
i1 = p1 # error i1 = p1 # error
p2 = obj # error p2 = obj # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_ass.pyx:5:16: Cannot assign type 'char *' to 'int' 5:16: Cannot assign type 'char *' to 'int'
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_ass.pyx:6:17: Cannot convert Python object to 'int *' 6:17: Cannot convert Python object to 'int *'
""" """
cdef void spam(): cdef void spam():
None = 42 None = 42
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_assnone.pyx:2:1: Cannot assign to or delete this 2:1: Cannot assign to or delete this
""" """
...@@ -3,5 +3,5 @@ cdef struct Foo ...@@ -3,5 +3,5 @@ cdef struct Foo
def f(Foo *p): def f(Foo *p):
pass pass
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_badpyparam.pyx:3:6: Cannot convert Python object argument to type 'Foo *' 3:6: Cannot convert Python object argument to type 'Foo *'
""" """
...@@ -3,5 +3,5 @@ def f(): ...@@ -3,5 +3,5 @@ def f():
cdef char *ptr cdef char *ptr
int1 = int2 | ptr # error int1 = int2 | ptr # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_bitop.pyx:4:13: Invalid operand types for '|' (int; char *) 4:13: Invalid operand types for '|' (int; char *)
""" """
...@@ -28,8 +28,8 @@ if union_not_boolean: ...@@ -28,8 +28,8 @@ if union_not_boolean:
_ERRORS = u""" _ERRORS = u"""
5:26: 'struct_type_not_boolean' is not a constant, variable or function identifier 5:26: 'struct_type_not_boolean' is not a constant, variable or function identifier
5:26: Type 'struct_type_not_boolean' not acceptable as a boolean 5:26: Type 'struct_type_not_boolean' not acceptable as a boolean
12:21: 'struct_not_boolean' is not a constant, variable or function identifier 12:21: 'struct_not_boolean' is not a constant, variable or function identifier
12:21: Type 'struct_not_boolean' not acceptable as a boolean 12:21: Type 'struct_not_boolean' not acceptable as a boolean
......
...@@ -14,6 +14,6 @@ a.some_method(1, 2) ...@@ -14,6 +14,6 @@ a.some_method(1, 2)
a.some_method(1, y=2) a.some_method(1, y=2)
_ERRORS = u""" _ERRORS = u"""
:9:13: Keyword arguments not allowed in cdef functions. 9:13: Keyword arguments not allowed in cdef functions.
:14:13: Keyword arguments not allowed in cdef functions. 14:13: Keyword arguments not allowed in cdef functions.
""" """
...@@ -3,5 +3,5 @@ cdef int ...@@ -3,5 +3,5 @@ cdef int
cdef extern from *: cdef extern from *:
void f(int) void f(int)
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_cdef_missing_declarator.pyx:1:8: Empty declarator 1:8: Empty declarator
""" """
...@@ -7,7 +7,7 @@ ctypedef union eggs: ...@@ -7,7 +7,7 @@ ctypedef union eggs:
cdef enum ham: cdef enum ham:
pass pass
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cdefemptysue.pyx:1:5: Empty struct or union definition not allowed outside a 'cdef extern from' block 1:5: Empty struct or union definition not allowed outside a 'cdef extern from' block
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cdefemptysue.pyx:4:0: Empty struct or union definition not allowed outside a 'cdef extern from' block 4:0: Empty struct or union definition not allowed outside a 'cdef extern from' block
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cdefemptysue.pyx:7:5: Empty enum definition not allowed outside a 'cdef extern from' block 7:5: Empty enum definition not allowed outside a 'cdef extern from' block
""" """
...@@ -6,5 +6,5 @@ cdef void f(): ...@@ -6,5 +6,5 @@ cdef void f():
a = 42 # assignment to non-lvalue a = 42 # assignment to non-lvalue
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cenum.pyx:6:3: Assignment to non-lvalue 'a' 6:3: Assignment to non-lvalue 'a'
""" """
...@@ -6,6 +6,6 @@ cdef class D(C): ...@@ -6,6 +6,6 @@ cdef class D(C):
cdef void f(self, int x): cdef void f(self, int x):
pass pass
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_cmethbasematch.pyx:6:6: Signature not compatible with previous declaration 6:6: Signature not compatible with previous declaration
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_cmethbasematch.pyx:2:6: Previous declaration is here 2:6: Previous declaration is here
""" """
...@@ -5,6 +5,6 @@ cdef void foo(): ...@@ -5,6 +5,6 @@ cdef void foo():
bool = int1 == ptr2 # error bool = int1 == ptr2 # error
bool = ptr2 == ptr3 # error bool = ptr2 == ptr3 # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cmp.pyx:5:13: Invalid types for '==' (int, char *) 5:13: Invalid types for '==' (int, char *)
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cmp.pyx:6:13: Invalid types for '==' (char *, int *) 6:13: Invalid types for '==' (char *, int *)
""" """
...@@ -20,12 +20,12 @@ cdef void eggs(Spam s): ...@@ -20,12 +20,12 @@ cdef void eggs(Spam s):
j = gp.x # error - incomplete type j = gp.x # error - incomplete type
gp.x = j # error - incomplete type gp.x = j # error - incomplete type
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cstruct.pyx:5:36: C struct/union member cannot be a Python object 5:36: C struct/union member cannot be a Python object
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cstruct.pyx:15:6: Object of type 'Spam' has no attribute 'k' 15:6: Object of type 'Spam' has no attribute 'k'
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cstruct.pyx:16:6: Cannot assign type 'float *[42]' to 'int' 16:6: Cannot assign type 'float *[42]' to 'int'
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cstruct.pyx:17:21: Cannot assign type 'int' to 'float *[42]' 17:21: Cannot assign type 'int' to 'float *[42]'
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cstruct.pyx:18:6: Object of type 'int' has no attribute 'i' 18:6: Object of type 'int' has no attribute 'i'
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cstruct.pyx:19:2: Object of type 'int' has no attribute 'i' 19:2: Object of type 'int' has no attribute 'i'
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cstruct.pyx:20:7: Cannot select attribute of incomplete type 'Grail' 20:7: Cannot select attribute of incomplete type 'Grail'
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_cstruct.pyx:21:3: Cannot select attribute of incomplete type 'Grail' 21:3: Cannot select attribute of incomplete type 'Grail'
""" """
...@@ -13,6 +13,6 @@ ctypedef class Eggs: ...@@ -13,6 +13,6 @@ ctypedef class Eggs:
ctypedef struct Spam ctypedef struct Spam
ctypedef class Eggs ctypedef class Eggs
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_ctypedefforward.pyx:1:0: Forward-referenced type must use 'cdef', not 'ctypedef' 1:0: Forward-referenced type must use 'cdef', not 'ctypedef'
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_ctypedefforward.pyx:2:0: Forward-referenced type must use 'cdef', not 'ctypedef' 2:0: Forward-referenced type must use 'cdef', not 'ctypedef'
""" """
...@@ -17,7 +17,7 @@ cdef Foo f ...@@ -17,7 +17,7 @@ cdef Foo f
cdef Blarg b cdef Blarg b
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_ctypedefornot.pyx:3:0: 'Foo' previously declared using 'cdef' 3:0: 'Foo' previously declared using 'cdef'
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_ctypedefornot.pyx:9:5: 'Blarg' previously declared using 'ctypedef' 9:5: 'Blarg' previously declared using 'ctypedef'
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_ctypedefornot.pyx:13:0: 'Spam' previously declared using 'cdef' 13:0: 'Spam' previously declared using 'cdef'
""" """
...@@ -8,9 +8,9 @@ cdef void f(): ...@@ -8,9 +8,9 @@ cdef void f():
h = <int ()()>f # this is an error h = <int ()()>f # this is an error
h = <int (*)()>f # this is OK h = <int (*)()>f # this is OK
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_declarations.pyx:1:19: Array element cannot be a function 1:19: Array element cannot be a function
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_declarations.pyx:2:18: Function cannot return an array 2:18: Function cannot return an array
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_declarations.pyx:3:18: Function cannot return a function 3:18: Function cannot return a function
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_declarations.pyx:8:10: Function cannot return a function 8:10: Function cannot return a function
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_declarations.pyx:8:5: Cannot cast to a function type 8:5: Cannot cast to a function type
""" """
...@@ -12,9 +12,9 @@ def f(a): ...@@ -12,9 +12,9 @@ def f(a):
del x[i] # error: deletion of non-Python object del x[i] # error: deletion of non-Python object
del s.m # error: deletion of non-Python object del s.m # error: deletion of non-Python object
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_del.pyx:8:6: Cannot assign to or delete this 8:6: Cannot assign to or delete this
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_del.pyx:9:45: Deletion of non-Python object 9:45: Deletion of non-Python object
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_del.pyx:12:6: Deletion of non-Python object 12:6: Deletion of non-Python object
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_del.pyx:13:6: Deletion of non-Python object 13:6: Deletion of non-Python object
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_del.pyx:11:52: Deletion of local or C global name not supported 11:52: Deletion of local or C global name not supported
""" """
...@@ -11,6 +11,6 @@ except AttributeError: ...@@ -11,6 +11,6 @@ except AttributeError:
pass pass
_ERRORS = u""" _ERRORS = u"""
8:0: default 'except:' must be last 8:0: default 'except:' must be last
10:0: default 'except:' must be last 10:0: default 'except:' must be last
""" """
...@@ -7,6 +7,6 @@ cdef spamfunc spam ...@@ -7,6 +7,6 @@ cdef spamfunc spam
grail = spam # type mismatch grail = spam # type mismatch
spam = grail # type mismatch spam = grail # type mismatch
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_excvalfunctype.pyx:7:28: Cannot assign type 'e_excvalfunctype.spamfunc' to 'e_excvalfunctype.grailfunc' 7:28: Cannot assign type 'e_excvalfunctype.spamfunc' to 'e_excvalfunctype.grailfunc'
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_excvalfunctype.pyx:8:28: Cannot assign type 'e_excvalfunctype.grailfunc' to 'e_excvalfunctype.spamfunc' 8:28: Cannot assign type 'e_excvalfunctype.grailfunc' to 'e_excvalfunctype.spamfunc'
""" """
...@@ -13,8 +13,8 @@ cdef void f(): ...@@ -13,8 +13,8 @@ cdef void f():
x = c.__weakref__ x = c.__weakref__
c.__weakref__ = x c.__weakref__ = x
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_extweakref.pyx:5:20: Special attribute __weakref__ cannot be exposed to Python 5:20: Special attribute __weakref__ cannot be exposed to Python
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_extweakref.pyx:8:22: Special attribute __weakref__ cannot be exposed to Python 8:22: Special attribute __weakref__ cannot be exposed to Python
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_extweakref.pyx:13:6: Illegal use of special attribute __weakref__ 13:6: Illegal use of special attribute __weakref__
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_extweakref.pyx:14:2: Illegal use of special attribute __weakref__ 14:2: Illegal use of special attribute __weakref__
""" """
...@@ -7,8 +7,8 @@ def f(obj1, obj2): ...@@ -7,8 +7,8 @@ def f(obj1, obj2):
int1 = int2[int3] # error int1 = int2[int3] # error
obj1 = obj2[ptr1] # error obj1 = obj2[ptr1] # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_index.pyx:5:14: Invalid index type 'float' 5:14: Invalid index type 'float'
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_index.pyx:6:14: Invalid index type 'float *' 6:14: Invalid index type 'float *'
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_index.pyx:7:12: Attempting to index non-array type 'int' 7:12: Attempting to index non-array type 'int'
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_index.pyx:8:17: Cannot convert 'float *' to Python object 8:17: Cannot convert 'float *' to Python object
""" """
...@@ -3,5 +3,5 @@ def f(obj1a, obj1b): ...@@ -3,5 +3,5 @@ def f(obj1a, obj1b):
cdef int *ptr2 cdef int *ptr2
int1, int3, obj1a = int2, ptr2, obj1b # error int1, int3, obj1a = int2, ptr2, obj1b # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_multass.pyx:4:31: Cannot assign type 'int *' to 'int' 4:31: Cannot assign type 'int *' to 'int'
""" """
...@@ -8,9 +8,9 @@ cdef f(): ...@@ -8,9 +8,9 @@ cdef f():
spam() # too few args spam() # too few args
spam("blarg") # too few args spam("blarg") # too few args
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_nargs.pyx:5:6: Call with wrong number of arguments (expected 2, got 0) 5:6: Call with wrong number of arguments (expected 2, got 0)
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_nargs.pyx:6:6: Call with wrong number of arguments (expected 2, got 1) 6:6: Call with wrong number of arguments (expected 2, got 1)
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_nargs.pyx:7:6: Call with wrong number of arguments (expected 2, got 3) 7:6: Call with wrong number of arguments (expected 2, got 3)
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_nargs.pyx:8:5: Call with wrong number of arguments (expected at least 2, got 0) 8:5: Call with wrong number of arguments (expected at least 2, got 0)
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_nargs.pyx:9:5: Call with wrong number of arguments (expected at least 2, got 1) 9:5: Call with wrong number of arguments (expected at least 2, got 1)
""" """
...@@ -3,6 +3,6 @@ cdef class C: ...@@ -3,6 +3,6 @@ cdef class C:
pass pass
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_nogilcmeth.pyx:2:6: Signature not compatible with previous declaration 2:6: Signature not compatible with previous declaration
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_nogilcmeth.pxd:2:12: Previous declaration is here 2:12: Previous declaration is here
""" """
...@@ -4,5 +4,5 @@ cdef extern from *: ...@@ -4,5 +4,5 @@ cdef extern from *:
fp = f fp = f
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors3/e_nogilfunctype.pyx:5:6: Cannot assign type 'void (void)' to 'void (*)(void) nogil' 5:6: Cannot assign type 'void (void)' to 'void (*)(void) nogil'
""" """
...@@ -3,5 +3,5 @@ cdef extern class Grail.Shrubbery ...@@ -3,5 +3,5 @@ cdef extern class Grail.Shrubbery
cdef void spam(Shrubbery sh not None): cdef void spam(Shrubbery sh not None):
pass pass
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_notnone.pyx:3:15: 'not None' only allowed in Python functions 3:15: 'not None' only allowed in Python functions
""" """
def eggs(int x not None, y not None): def eggs(int x not None, y not None):
pass pass
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_notnone2.pyx:1:0: Only extension type arguments can have 'not None' 1:0: Only extension type arguments can have 'not None'
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_notnone2.pyx:1:0: Only extension type arguments can have 'not None' 1:0: Only extension type arguments can have 'not None'
""" """
...@@ -3,5 +3,5 @@ def f(): ...@@ -3,5 +3,5 @@ def f():
cdef int *ptr cdef int *ptr
int1 = int2 * ptr # error int1 = int2 * ptr # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_numop.pyx:4:13: Invalid operand types for '*' (int; int *) 4:13: Invalid operand types for '*' (int; int *)
""" """
...@@ -7,5 +7,5 @@ def f(): ...@@ -7,5 +7,5 @@ def f():
cdef spam s cdef spam s
s.parrot = x s.parrot = x
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_pyobinstruct.pyx:4:8: C struct/union member cannot be a Python object 4:8: C struct/union member cannot be a Python object
""" """
...@@ -4,5 +4,5 @@ class C: ...@@ -4,5 +4,5 @@ class C:
def f(self): def f(self):
pass pass
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_redeclmeth.pyx:4:1: 'f' already declared 4:1: 'f' already declared
""" """
...@@ -7,7 +7,7 @@ cdef int h(): ...@@ -7,7 +7,7 @@ cdef int h():
return # error return # error
return p # error return p # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_return.pyx:3:17: Return with value in void function 3:17: Return with value in void function
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_return.pyx:7:1: Return value required 7:1: Return value required
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_return.pyx:8:17: Cannot assign type 'int *' to 'int' 8:17: Cannot assign type 'int *' to 'int'
""" """
...@@ -2,5 +2,5 @@ cdef struct unbekannt ...@@ -2,5 +2,5 @@ cdef struct unbekannt
cdef int n cdef int n
n = sizeof(unbekannt) n = sizeof(unbekannt)
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_sizeofincomplete.pyx:3:4: Cannot take sizeof incomplete type 'unbekannt' 3:4: Cannot take sizeof incomplete type 'unbekannt'
""" """
...@@ -4,7 +4,7 @@ def f(obj2): ...@@ -4,7 +4,7 @@ def f(obj2):
obj1 = obj2[:ptr1:] # error obj1 = obj2[:ptr1:] # error
obj1 = obj2[::ptr1] # error obj1 = obj2[::ptr1] # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_slice.pyx:3:17: Cannot convert 'int *' to Python object 3:17: Cannot convert 'int *' to Python object
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_slice.pyx:4:18: Cannot convert 'int *' to Python object 4:18: Cannot convert 'int *' to Python object
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_slice.pyx:5:19: Cannot convert 'int *' to Python object 5:19: Cannot convert 'int *' to Python object
""" """
...@@ -4,6 +4,6 @@ def f(): ...@@ -4,6 +4,6 @@ def f():
ptr1 = int2 - ptr3 # error ptr1 = int2 - ptr3 # error
ptr1 = ptr2 - ptr3 # error ptr1 = ptr2 - ptr3 # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_subop.pyx:4:13: Invalid operand types for '-' (int; char *) 4:13: Invalid operand types for '-' (int; char *)
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_subop.pyx:5:13: Cannot assign type 'int' to 'char *' 5:13: Cannot assign type 'int' to 'char *'
""" """
...@@ -5,5 +5,5 @@ def foo(obj): ...@@ -5,5 +5,5 @@ def foo(obj):
p = <int *>blarg # okay p = <int *>blarg # okay
p = <int *>(foo + blarg) # error - temporary p = <int *>(foo + blarg) # error - temporary
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_tempcast.pyx:6:5: Casting temporary Python object to non-numeric non-Python type 6:5: Casting temporary Python object to non-numeric non-Python type
""" """
cdef class Spam cdef class Spam
cdef extern class external.Eggs cdef extern class external.Eggs
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_undefexttype.pyx:1:5: C class 'Spam' is declared but not defined 1:5: C class 'Spam' is declared but not defined
/Local/Projects/D/Pyrex/Source/Tests/Errors1/e_undefexttype.pyx:2:5: C class 'Eggs' is declared but not defined 2:5: C class 'Eggs' is declared but not defined
""" """
...@@ -4,6 +4,6 @@ def f(): ...@@ -4,6 +4,6 @@ def f():
int1 = -str2 # error int1 = -str2 # error
int1 = ~str2 # error int1 = ~str2 # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_unop.pyx:4:8: Invalid operand type for '-' (char *) 4:8: Invalid operand type for '-' (char *)
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_unop.pyx:5:8: Invalid operand type for '~' (char *) 5:8: Invalid operand type for '~' (char *)
""" """
...@@ -3,6 +3,6 @@ def f(a, b): ...@@ -3,6 +3,6 @@ def f(a, b):
break # error break # error
continue # error continue # error
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_while.pyx:3:1: break statement not inside loop 3:1: break statement not inside loop
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_while.pyx:4:1: continue statement not inside loop 4:1: continue statement not inside loop
""" """
...@@ -4,5 +4,5 @@ cdef class B: ...@@ -4,5 +4,5 @@ cdef class B:
pass pass
_ERRORS = u""" _ERRORS = u"""
:3:10: C method has no self argument 3:10: C method has no self argument
""" """
...@@ -78,9 +78,9 @@ cdef void t(C c) nogil: ...@@ -78,9 +78,9 @@ cdef void t(C c) nogil:
_ERRORS = u""" _ERRORS = u"""
1: 5: Function with Python return type cannot be declared nogil 1: 5: Function with Python return type cannot be declared nogil
6: 6: Assignment of Python object not allowed without gil 6: 6: Assignment of Python object not allowed without gil
4: 5: Function declared nogil has Python locals or temporaries 4: 5: Function declared nogil has Python locals or temporaries
11: 5: Function with Python return type cannot be declared nogil 11: 5: Function with Python return type cannot be declared nogil
15: 5: Calling gil-requiring function not allowed without gil 15: 5: Calling gil-requiring function not allowed without gil
24: 9: Calling gil-requiring function not allowed without gil 24: 9: Calling gil-requiring function not allowed without gil
......
...@@ -3,6 +3,6 @@ cdef class C: ...@@ -3,6 +3,6 @@ cdef class C:
pass pass
_ERRORS = u""" _ERRORS = u"""
nogilcmeth.pyx:2:9: Signature not compatible with previous declaration 2:9: Signature not compatible with previous declaration
nogilcmeth.pxd:2:15: Previous declaration is here 2:15: Previous declaration is here
""" """
...@@ -2,5 +2,5 @@ def f(): ...@@ -2,5 +2,5 @@ def f():
a = b # space space a = b # space space
c = d # space tab c = d # space tab
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/se_badindent.pyx:3:0: Mixed use of tabs and spaces 3:0: Mixed use of tabs and spaces
""" """
...@@ -2,6 +2,6 @@ def f(): ...@@ -2,6 +2,6 @@ def f():
a = b a = b
c = d c = d
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/se_badindent2.pyx:3:0: Possible inconsistent indentation 3:0: Possible inconsistent indentation
/Local/Projects/D/Pyrex/Source/Tests/Errors1/se_badindent2.pyx:3:0: Expected an identifier or literal 3:0: Expected an identifier or literal
""" """
...@@ -2,5 +2,5 @@ if x: ...@@ -2,5 +2,5 @@ if x:
def h(): def h():
pass pass
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/se_conddef.pyx:2:1: def statement not allowed here 2:1: def statement not allowed here
""" """
...@@ -2,5 +2,5 @@ def f(): ...@@ -2,5 +2,5 @@ def f():
a = b # space space a = b # space space
c = d # tab c = d # tab
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/se_mixtabspace.pyx:3:0: Mixed use of tabs and spaces 3:0: Mixed use of tabs and spaces
""" """
...@@ -2,5 +2,5 @@ def f(): ...@@ -2,5 +2,5 @@ def f():
def g(): def g():
pass pass
_ERRORS = u""" _ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors1/se_nestdef.pyx:2:1: def statement not allowed here 2:1: def statement not allowed here
""" """
__doc__ = u"""
>>> cdiv_decorator(-12, 5)
-2
>>> pydiv_decorator(-12, 5)
-3
"""
cimport cython
@cython.cdivision(True)
cpdef cdiv_decorator(int a, int b):
return a / b
@cython.cdivision(False)
cpdef pydiv_decorator(int a, int b):
return a / b
...@@ -26,6 +26,28 @@ True ...@@ -26,6 +26,28 @@ True
>>> [test_cdiv_cmod(a, b) for a, b in v] >>> [test_cdiv_cmod(a, b) for a, b in v]
[(1, 7), (-1, -7), (1, -7), (-1, 7)] [(1, 7), (-1, -7), (1, -7), (-1, 7)]
>>> all([mod_int_py(a,b) == a % b for a in range(-10, 10) for b in range(-10, 10) if b != 0])
True
>>> all([div_int_py(a,b) == a // b for a in range(-10, 10) for b in range(-10, 10) if b != 0])
True
>>> def simple_warn(msg, *args): print msg
>>> import warnings
>>> warnings.showwarning = simple_warn
>>> mod_int_c_warn(-17, 10)
division with oppositely signed operands, C and Python semantics differ
-7
>>> div_int_c_warn(-17, 10)
division with oppositely signed operands, C and Python semantics differ
-1
>>> complex_expression(-150, 20, 20, -7)
verbose_call(-150)
division with oppositely signed operands, C and Python semantics differ
verbose_call(20)
division with oppositely signed operands, C and Python semantics differ
-2
""" """
cimport cython cimport cython
...@@ -73,3 +95,22 @@ def test_cdiv_cmod(short a, short b): ...@@ -73,3 +95,22 @@ def test_cdiv_cmod(short a, short b):
cdef short q = cython.cdiv(a, b) cdef short q = cython.cdiv(a, b)
cdef short r = cython.cmod(a, b) cdef short r = cython.cmod(a, b)
return q, r return q, r
@cython.cdivision(True)
@cython.cdivision_warnings(True)
def mod_int_c_warn(int a, int b):
return a % b
@cython.cdivision(True)
@cython.cdivision_warnings(True)
def div_int_c_warn(int a, int b):
return a // b
@cython.cdivision(False)
@cython.cdivision_warnings(True)
def complex_expression(int a, int b, int c, int d):
return (verbose_call(a) // b) % (verbose_call(c) // d)
cdef int verbose_call(int x):
print "verbose_call(%s)" % x
return x
__doc__ = u"""
>>> floor_div_float(2, 1.5)
1.0
>>> floor_div_float(2, -1.5)
-2.0
>>> floor_div_float(-2.3, 1.5)
-2.0
>>> floor_div_float(1e10, 1e-10)
1e+20
"""
def floor_div_float(double a, double b):
return a // b
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment