Commit 6c2a2b3b authored by Stefan Behnel's avatar Stefan Behnel

merged in latest cython-devel

parents 4856376e 19209090
...@@ -11,7 +11,8 @@ import Symtab ...@@ -11,7 +11,8 @@ import Symtab
class AutoTestDictTransform(ScopeTrackingTransform): class AutoTestDictTransform(ScopeTrackingTransform):
# Handles autotestdict directive # Handles autotestdict directive
blacklist = ['__cinit__', '__dealloc__', '__richcmp__', '__nonzero__'] blacklist = ['__cinit__', '__dealloc__', '__richcmp__', '__nonzero__',
'__len__', '__contains__']
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
if node.is_pxd: if node.is_pxd:
......
...@@ -44,8 +44,9 @@ class AnnotationCCodeWriter(CCodeWriter): ...@@ -44,8 +44,9 @@ class AnnotationCCodeWriter(CCodeWriter):
if pos is not None: if pos is not None:
CCodeWriter.mark_pos(self, pos) CCodeWriter.mark_pos(self, pos)
if self.last_pos: if self.last_pos:
code = self.code.get(self.last_pos[1], "") pos_code = self.code.setdefault(self.last_pos[0].get_description(),{})
self.code[self.last_pos[1]] = code + self.annotation_buffer.getvalue() code = pos_code.get(self.last_pos[1], "")
pos_code[self.last_pos[1]] = code + self.annotation_buffer.getvalue()
self.annotation_buffer = StringIO() self.annotation_buffer = StringIO()
self.last_pos = pos self.last_pos = pos
...@@ -63,15 +64,16 @@ class AnnotationCCodeWriter(CCodeWriter): ...@@ -63,15 +64,16 @@ class AnnotationCCodeWriter(CCodeWriter):
lines[k] = line lines[k] = line
f.close() f.close()
all = [] all = []
for pos, item in self.annotations: if False:
if pos[0] == source_filename: for pos, item in self.annotations:
start = item.start() if pos[0].filename == source_filename:
size, end = item.end() start = item.start()
if size: size, end = item.end()
all.append((pos, start)) if size:
all.append(((source_filename, pos[1], pos[2]+size), end)) all.append((pos, start))
else: all.append(((source_filename, pos[1], pos[2]+size), end))
all.append((pos, start+end)) else:
all.append((pos, start+end))
all.sort() all.sort()
all.reverse() all.reverse()
...@@ -136,11 +138,12 @@ function toggleDiv(id) { ...@@ -136,11 +138,12 @@ function toggleDiv(id) {
error_goto = re.compile(ur'((; *if .*)? \{__pyx_filename = .*goto __pyx_L\w+;\})') error_goto = re.compile(ur'((; *if .*)? \{__pyx_filename = .*goto __pyx_L\w+;\})')
refnanny = re.compile(u'(__Pyx_X?(GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)') refnanny = re.compile(u'(__Pyx_X?(GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)')
code_source_file = self.code[source_filename]
for line in lines: for line in lines:
k += 1 k += 1
try: try:
code = self.code[k] code = code_source_file[k]
except KeyError: except KeyError:
code = '' code = ''
......
...@@ -413,16 +413,19 @@ def init_builtins(): ...@@ -413,16 +413,19 @@ def init_builtins():
init_builtin_funcs() init_builtin_funcs()
init_builtin_types() init_builtin_types()
init_builtin_structs() init_builtin_structs()
global list_type, tuple_type, dict_type, set_type, type_type global list_type, tuple_type, dict_type, set_type, frozenset_type
global bytes_type, str_type, unicode_type, float_type global bytes_type, str_type, unicode_type
global float_type, bool_type, type_type
type_type = builtin_scope.lookup('type').type type_type = builtin_scope.lookup('type').type
list_type = builtin_scope.lookup('list').type list_type = builtin_scope.lookup('list').type
tuple_type = builtin_scope.lookup('tuple').type tuple_type = builtin_scope.lookup('tuple').type
dict_type = builtin_scope.lookup('dict').type dict_type = builtin_scope.lookup('dict').type
set_type = builtin_scope.lookup('set').type set_type = builtin_scope.lookup('set').type
frozenset_type = builtin_scope.lookup('frozenset').type
bytes_type = builtin_scope.lookup('bytes').type bytes_type = builtin_scope.lookup('bytes').type
str_type = builtin_scope.lookup('str').type str_type = builtin_scope.lookup('str').type
unicode_type = builtin_scope.lookup('unicode').type unicode_type = builtin_scope.lookup('unicode').type
float_type = builtin_scope.lookup('float').type float_type = builtin_scope.lookup('float').type
bool_type = builtin_scope.lookup('bool').type
init_builtins() init_builtins()
...@@ -10,7 +10,7 @@ debug_temp_code_comments = 0 ...@@ -10,7 +10,7 @@ debug_temp_code_comments = 0
debug_trace_code_generation = 0 debug_trace_code_generation = 0
# Do not replace exceptions with user-friendly error messages # Do not replace exceptions with user-friendly error messages
debug_no_exception_intercept = 0 debug_no_exception_intercept = 1
# Print a message each time a new stage in the pipeline is entered # Print a message each time a new stage in the pipeline is entered
debug_verbose_pipeline = 0 debug_verbose_pipeline = 0
...@@ -274,6 +274,10 @@ class ExprNode(Node): ...@@ -274,6 +274,10 @@ class ExprNode(Node):
# ConstantFolding transform will do this. # ConstantFolding transform will do this.
pass pass
def has_constant_result(self):
return self.constant_result is not constant_value_not_set and \
self.constant_result is not not_a_constant
def compile_time_value(self, denv): def compile_time_value(self, denv):
# Return value of compile-time expression, or report error. # Return value of compile-time expression, or report error.
error(self.pos, "Invalid compile-time expression") error(self.pos, "Invalid compile-time expression")
...@@ -594,11 +598,18 @@ class ExprNode(Node): ...@@ -594,11 +598,18 @@ class ExprNode(Node):
def coerce_to_boolean(self, env): def coerce_to_boolean(self, env):
# Coerce result to something acceptable as # Coerce result to something acceptable as
# a boolean value. # a boolean value.
# if it's constant, calculate the result now
if self.has_constant_result():
bool_value = bool(self.constant_result)
return BoolNode(self.pos, value=bool_value,
constant_result=bool_value)
type = self.type type = self.type
if type.is_pyobject or type.is_ptr or type.is_float: if type.is_pyobject or type.is_ptr or type.is_float:
return CoerceToBooleanNode(self, env) return CoerceToBooleanNode(self, env)
else: else:
if not type.is_int and not type.is_error: if not (type.is_int or type.is_enum or type.is_error):
error(self.pos, error(self.pos,
"Type '%s' not acceptable as a boolean" % type) "Type '%s' not acceptable as a boolean" % type)
return self return self
...@@ -630,10 +641,22 @@ class ExprNode(Node): ...@@ -630,10 +641,22 @@ class ExprNode(Node):
# a constant, local var, C global var, struct member # a constant, local var, C global var, struct member
# reference, or temporary. # reference, or temporary.
return self.result_in_temp() return self.result_in_temp()
def may_be_none(self):
return self.type.is_pyobject
def as_cython_attribute(self): def as_cython_attribute(self):
return None return None
def as_none_safe_node(self, message, error="PyExc_TypeError"):
# Wraps the node in a NoneCheckNode if it is not known to be
# not-None (e.g. because it is a Python literal).
if self.may_be_none():
return NoneCheckNode(self, error, message)
else:
return self
class AtomicExprNode(ExprNode): class AtomicExprNode(ExprNode):
# Abstract base class for expression nodes which have # Abstract base class for expression nodes which have
# no sub-expressions. # no sub-expressions.
...@@ -654,7 +677,10 @@ class PyConstNode(AtomicExprNode): ...@@ -654,7 +677,10 @@ class PyConstNode(AtomicExprNode):
def is_simple(self): def is_simple(self):
return 1 return 1
def may_be_none(self):
return False
def analyse_types(self, env): def analyse_types(self, env):
pass pass
...@@ -676,7 +702,11 @@ class NoneNode(PyConstNode): ...@@ -676,7 +702,11 @@ class NoneNode(PyConstNode):
def compile_time_value(self, denv): def compile_time_value(self, denv):
return None return None
def may_be_none(self):
return True
class EllipsisNode(PyConstNode): class EllipsisNode(PyConstNode):
# '...' in a subscript list. # '...' in a subscript list.
...@@ -698,7 +728,10 @@ class ConstNode(AtomicExprNode): ...@@ -698,7 +728,10 @@ class ConstNode(AtomicExprNode):
def is_simple(self): def is_simple(self):
return 1 return 1
def may_be_none(self):
return False
def analyse_types(self, env): def analyse_types(self, env):
pass # Types are held in class variables pass # Types are held in class variables
...@@ -853,10 +886,18 @@ class BytesNode(ConstNode): ...@@ -853,10 +886,18 @@ class BytesNode(ConstNode):
def can_coerce_to_char_literal(self): def can_coerce_to_char_literal(self):
return len(self.value) == 1 return len(self.value) == 1
def coerce_to_boolean(self, env):
# This is special because we start off as a C char*. Testing
# that for truth directly would yield the wrong result.
return BoolNode(self.pos, value=bool(self.value))
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
if dst_type.is_int: if dst_type.is_int:
if not self.can_coerce_to_char_literal(): if not self.can_coerce_to_char_literal():
error(self.pos, "Only single-character strings can be coerced into ints.") error(self.pos, "Only single-character string literals can be coerced into ints.")
return self
if dst_type is PyrexTypes.c_py_unicode_type:
error(self.pos, "Bytes literals cannot coerce to Py_UNICODE, use a unicode literal instead.")
return self return self
return CharNode(self.pos, value=self.value) return CharNode(self.pos, value=self.value)
...@@ -911,13 +952,22 @@ class UnicodeNode(PyConstNode): ...@@ -911,13 +952,22 @@ class UnicodeNode(PyConstNode):
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
if dst_type is self.type: if dst_type is self.type:
pass pass
elif dst_type is PyrexTypes.c_py_unicode_type:
if not self.can_coerce_to_char_literal():
error(self.pos, "Only single-character Unicode string literals can be coerced into Py_UNICODE.")
return self
int_value = ord(self.value)
return IntNode(self.pos, value=int_value, constant_result=int_value)
elif not dst_type.is_pyobject: elif not dst_type.is_pyobject:
error(self.pos, "Unicode objects do not support coercion to C types.") error(self.pos, "Unicode literals do not support coercion to C types other than Py_UNICODE.")
elif dst_type is not py_object_type: elif dst_type is not py_object_type:
if not self.check_for_coercion_error(dst_type): if not self.check_for_coercion_error(dst_type):
self.fail_assignment(dst_type) self.fail_assignment(dst_type)
return self return self
def can_coerce_to_char_literal(self):
return len(self.value) == 1
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
self.result_code = code.get_py_string_const(self.value) self.result_code = code.get_py_string_const(self.value)
...@@ -996,6 +1046,9 @@ class LongNode(AtomicExprNode): ...@@ -996,6 +1046,9 @@ class LongNode(AtomicExprNode):
def analyse_types(self, env): def analyse_types(self, env):
self.is_temp = 1 self.is_temp = 1
def may_be_none(self):
return False
gil_message = "Constructing Python long int" gil_message = "Constructing Python long int"
def generate_result_code(self, code): def generate_result_code(self, code):
...@@ -1023,6 +1076,9 @@ class ImagNode(AtomicExprNode): ...@@ -1023,6 +1076,9 @@ class ImagNode(AtomicExprNode):
def analyse_types(self, env): def analyse_types(self, env):
self.type.create_declaration_utility_code(env) self.type.create_declaration_utility_code(env)
def may_be_none(self):
return False
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
if self.type is dst_type: if self.type is dst_type:
return self return self
...@@ -1082,7 +1138,10 @@ class NewExprNode(AtomicExprNode): ...@@ -1082,7 +1138,10 @@ class NewExprNode(AtomicExprNode):
def analyse_types(self, env): def analyse_types(self, env):
if self.type is None: if self.type is None:
self.infer_type(env) self.infer_type(env)
def may_be_none(self):
return False
def generate_result_code(self, code): def generate_result_code(self, code):
pass pass
...@@ -2259,14 +2318,14 @@ class SliceIndexNode(ExprNode): ...@@ -2259,14 +2318,14 @@ class SliceIndexNode(ExprNode):
if self.base.type.is_string: if self.base.type.is_string:
if self.stop is None: if self.stop is None:
code.putln( code.putln(
"%s = __Pyx_PyBytes_FromString(%s + %s); %s" % ( "%s = PyBytes_FromString(%s + %s); %s" % (
self.result(), self.result(),
self.base.result(), self.base.result(),
self.start_code(), self.start_code(),
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
else: else:
code.putln( code.putln(
"%s = __Pyx_PyBytes_FromStringAndSize(%s + %s, %s - %s); %s" % ( "%s = PyBytes_FromStringAndSize(%s + %s, %s - %s); %s" % (
self.result(), self.result(),
self.base.result(), self.base.result(),
self.start_code(), self.start_code(),
...@@ -2943,6 +3002,9 @@ class AsTupleNode(ExprNode): ...@@ -2943,6 +3002,9 @@ class AsTupleNode(ExprNode):
self.type = tuple_type self.type = tuple_type
self.is_temp = 1 self.is_temp = 1
def may_be_none(self):
return False
nogil_check = Node.gil_error nogil_check = Node.gil_error
gil_message = "Constructing Python tuple" gil_message = "Constructing Python tuple"
...@@ -3419,6 +3481,9 @@ class SequenceNode(ExprNode): ...@@ -3419,6 +3481,9 @@ class SequenceNode(ExprNode):
self.type = py_object_type self.type = py_object_type
self.is_temp = 1 self.is_temp = 1
def may_be_none(self):
return False
def analyse_target_types(self, env): def analyse_target_types(self, env):
self.iterator = PyTempNode(self.pos, env) self.iterator = PyTempNode(self.pos, env)
self.unpacked_items = [] self.unpacked_items = []
...@@ -3802,6 +3867,9 @@ class ComprehensionNode(ExprNode): ...@@ -3802,6 +3867,9 @@ class ComprehensionNode(ExprNode):
self.type = self.target.type self.type = self.target.type
self.loop.analyse_expressions(env) self.loop.analyse_expressions(env)
def may_be_none(self):
return False
def calculate_result_code(self): def calculate_result_code(self):
return self.target.result() return self.target.result()
...@@ -3882,6 +3950,9 @@ class SetNode(ExprNode): ...@@ -3882,6 +3950,9 @@ class SetNode(ExprNode):
self.type = set_type self.type = set_type
self.is_temp = 1 self.is_temp = 1
def may_be_none(self):
return False
def calculate_constant_result(self): def calculate_constant_result(self):
self.constant_result = set([ self.constant_result = set([
arg.constant_result for arg in self.args]) arg.constant_result for arg in self.args])
...@@ -3949,6 +4020,9 @@ class DictNode(ExprNode): ...@@ -3949,6 +4020,9 @@ class DictNode(ExprNode):
item.analyse_types(env) item.analyse_types(env)
self.obj_conversion_errors = held_errors() self.obj_conversion_errors = held_errors()
release_errors(ignore=True) release_errors(ignore=True)
def may_be_none(self):
return False
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
if dst_type.is_pyobject: if dst_type.is_pyobject:
...@@ -4079,6 +4153,9 @@ class ClassNode(ExprNode): ...@@ -4079,6 +4153,9 @@ class ClassNode(ExprNode):
self.is_temp = 1 self.is_temp = 1
env.use_utility_code(create_class_utility_code); env.use_utility_code(create_class_utility_code);
def may_be_none(self):
return False
gil_message = "Constructing Python class" gil_message = "Constructing Python class"
def generate_result_code(self, code): def generate_result_code(self, code):
...@@ -4140,6 +4217,9 @@ class UnboundMethodNode(ExprNode): ...@@ -4140,6 +4217,9 @@ class UnboundMethodNode(ExprNode):
def analyse_types(self, env): def analyse_types(self, env):
self.function.analyse_types(env) self.function.analyse_types(env)
def may_be_none(self):
return False
gil_message = "Constructing an unbound method" gil_message = "Constructing an unbound method"
def generate_result_code(self, code): def generate_result_code(self, code):
...@@ -4172,6 +4252,9 @@ class PyCFunctionNode(ExprNode): ...@@ -4172,6 +4252,9 @@ class PyCFunctionNode(ExprNode):
def analyse_types(self, env): def analyse_types(self, env):
if self.binding: if self.binding:
env.use_utility_code(binding_cfunc_utility_code) env.use_utility_code(binding_cfunc_utility_code)
def may_be_none(self):
return False
gil_message = "Constructing Python function" gil_message = "Constructing Python function"
...@@ -4761,7 +4844,10 @@ class TypeofNode(ExprNode): ...@@ -4761,7 +4844,10 @@ class TypeofNode(ExprNode):
self.pos, value=StringEncoding.EncodedString(str(self.operand.type))) self.pos, value=StringEncoding.EncodedString(str(self.operand.type)))
self.literal.analyse_types(env) self.literal.analyse_types(env)
self.literal = self.literal.coerce_to_pyobject(env) self.literal = self.literal.coerce_to_pyobject(env)
def may_be_none(self):
return False
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
self.literal.generate_evaluation_code(code) self.literal.generate_evaluation_code(code)
...@@ -5123,7 +5209,7 @@ class DivNode(NumBinopNode): ...@@ -5123,7 +5209,7 @@ class DivNode(NumBinopNode):
if not self.type.is_pyobject: if not self.type.is_pyobject:
self.zerodivision_check = ( self.zerodivision_check = (
self.cdivision is None and not env.directives['cdivision'] self.cdivision is None and not env.directives['cdivision']
and (self.operand2.constant_result is not_a_constant or and (not self.operand2.has_constant_result() or
self.operand2.constant_result == 0)) self.operand2.constant_result == 0))
if self.zerodivision_check or env.directives['cdivision_warnings']: if self.zerodivision_check or env.directives['cdivision_warnings']:
# Need to check ahead of time to warn or raise zero division error # Need to check ahead of time to warn or raise zero division error
...@@ -5524,10 +5610,10 @@ class CmpNode(object): ...@@ -5524,10 +5610,10 @@ class CmpNode(object):
type1_can_be_int = False type1_can_be_int = False
type2_can_be_int = False type2_can_be_int = False
if isinstance(operand1, (StringNode, BytesNode)) \ if isinstance(operand1, (StringNode, BytesNode, UnicodeNode)) \
and operand1.can_coerce_to_char_literal(): and operand1.can_coerce_to_char_literal():
type1_can_be_int = True type1_can_be_int = True
if isinstance(operand2, (StringNode, BytesNode)) \ if isinstance(operand2, (StringNode, BytesNode, UnicodeNode)) \
and operand2.can_coerce_to_char_literal(): and operand2.can_coerce_to_char_literal():
type2_can_be_int = True type2_can_be_int = True
...@@ -5621,9 +5707,10 @@ class CmpNode(object): ...@@ -5621,9 +5707,10 @@ class CmpNode(object):
(op, operand1.type, operand2.type)) (op, operand1.type, operand2.type))
def is_python_comparison(self): def is_python_comparison(self):
return (self.has_python_operands() return not self.is_c_string_contains() and (
or (self.cascade and self.cascade.is_python_comparison()) self.has_python_operands()
or self.operator in ('in', 'not_in')) or (self.cascade and self.cascade.is_python_comparison())
or self.operator in ('in', 'not_in'))
def coerce_operands_to(self, dst_type, env): def coerce_operands_to(self, dst_type, env):
operand2 = self.operand2 operand2 = self.operand2
...@@ -5634,12 +5721,22 @@ class CmpNode(object): ...@@ -5634,12 +5721,22 @@ class CmpNode(object):
def is_python_result(self): def is_python_result(self):
return ((self.has_python_operands() and return ((self.has_python_operands() and
self.operator not in ('is', 'is_not', 'in', 'not_in')) self.operator not in ('is', 'is_not', 'in', 'not_in') and
not self.is_c_string_contains())
or (self.cascade and self.cascade.is_python_result())) or (self.cascade and self.cascade.is_python_result()))
def is_c_string_contains(self):
return self.operator in ('in', 'not_in') and \
((self.operand1.type in (PyrexTypes.c_char_type, PyrexTypes.c_uchar_type)
and self.operand2.type in (PyrexTypes.c_char_ptr_type,
PyrexTypes.c_uchar_ptr_type,
bytes_type)) or
(self.operand1.type is PyrexTypes.c_py_unicode_type
and self.operand2.type is unicode_type))
def generate_operation_code(self, code, result_code, def generate_operation_code(self, code, result_code,
operand1, op , operand2): operand1, op , operand2):
if self.type is PyrexTypes.py_object_type: if self.type.is_pyobject:
coerce_result = "__Pyx_PyBool_FromLong" coerce_result = "__Pyx_PyBool_FromLong"
else: else:
coerce_result = "" coerce_result = ""
...@@ -5648,8 +5745,8 @@ class CmpNode(object): ...@@ -5648,8 +5745,8 @@ class CmpNode(object):
else: else:
negation = "" negation = ""
if op == 'in' or op == 'not_in': if op == 'in' or op == 'not_in':
code.globalstate.use_utility_code(contians_utility_code) code.globalstate.use_utility_code(contains_utility_code)
if self.type is PyrexTypes.py_object_type: if self.type.is_pyobject:
coerce_result = "__Pyx_PyBoolOrNull_FromLong" coerce_result = "__Pyx_PyBoolOrNull_FromLong"
if op == 'not_in': if op == 'not_in':
negation = "__Pyx_NegateNonNeg" negation = "__Pyx_NegateNonNeg"
...@@ -5663,7 +5760,7 @@ class CmpNode(object): ...@@ -5663,7 +5760,7 @@ class CmpNode(object):
method = "PyDict_Contains" method = "PyDict_Contains"
else: else:
method = "PySequence_Contains" method = "PySequence_Contains"
if self.type is PyrexTypes.py_object_type: if self.type.is_pyobject:
error_clause = code.error_goto_if_null error_clause = code.error_goto_if_null
got_ref = "__Pyx_XGOTREF(%s); " % result_code got_ref = "__Pyx_XGOTREF(%s); " % result_code
else: else:
...@@ -5730,7 +5827,7 @@ class CmpNode(object): ...@@ -5730,7 +5827,7 @@ class CmpNode(object):
else: else:
return op return op
contians_utility_code = UtilityCode( contains_utility_code = UtilityCode(
proto=""" proto="""
static CYTHON_INLINE long __Pyx_NegateNonNeg(long b) { return unlikely(b < 0) ? b : !b; } static CYTHON_INLINE long __Pyx_NegateNonNeg(long b) { return unlikely(b < 0) ? b : !b; }
static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) { static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) {
...@@ -5738,6 +5835,38 @@ static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) { ...@@ -5738,6 +5835,38 @@ static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) {
} }
""") """)
char_in_bytes_utility_code = UtilityCode(
proto="""
static CYTHON_INLINE int __Pyx_BytesContains(PyObject* bytes, char character); /*proto*/
""",
impl="""
static CYTHON_INLINE int __Pyx_BytesContains(PyObject* bytes, char character) {
const Py_ssize_t length = PyBytes_GET_SIZE(bytes);
char* char_start = PyBytes_AS_STRING(bytes);
char* pos;
for (pos=char_start; pos < char_start+length; pos++) {
if (character == pos[0]) return 1;
}
return 0;
}
""")
pyunicode_in_unicode_utility_code = UtilityCode(
proto="""
static CYTHON_INLINE int __Pyx_UnicodeContains(PyObject* unicode, Py_UNICODE character); /*proto*/
""",
impl="""
static CYTHON_INLINE int __Pyx_UnicodeContains(PyObject* unicode, Py_UNICODE character) {
const Py_ssize_t length = PyUnicode_GET_SIZE(unicode);
Py_UNICODE* char_start = PyUnicode_AS_UNICODE(unicode);
Py_UNICODE* pos;
for (pos=char_start; pos < char_start+length; pos++) {
if (character == pos[0]) return 1;
}
return 0;
}
""")
class PrimaryCmpNode(ExprNode, CmpNode): class PrimaryCmpNode(ExprNode, CmpNode):
# Non-cascaded comparison or first comparison of # Non-cascaded comparison or first comparison of
...@@ -5784,13 +5913,30 @@ class PrimaryCmpNode(ExprNode, CmpNode): ...@@ -5784,13 +5913,30 @@ class PrimaryCmpNode(ExprNode, CmpNode):
self.cascade.analyse_types(env) self.cascade.analyse_types(env)
if self.operator in ('in', 'not_in'): if self.operator in ('in', 'not_in'):
common_type = py_object_type if self.is_c_string_contains():
self.is_pycmp = True self.is_pycmp = False
common_type = None
if self.cascade:
error(self.pos, "Cascading comparison not yet supported for 'int_val in string'.")
return
if self.operand2.type is unicode_type:
env.use_utility_code(pyunicode_in_unicode_utility_code)
else:
if self.operand1.type is PyrexTypes.c_uchar_type:
self.operand1 = self.operand1.coerce_to(PyrexTypes.c_char_type, env)
if self.operand2.type is not bytes_type:
self.operand2 = self.operand2.coerce_to(bytes_type, env)
env.use_utility_code(char_in_bytes_utility_code)
self.operand2 = self.operand2.as_none_safe_node(
"argument of type 'NoneType' is not iterable")
else:
common_type = py_object_type
self.is_pycmp = True
else: else:
common_type = self.find_common_type(env, self.operator, self.operand1) common_type = self.find_common_type(env, self.operator, self.operand1)
self.is_pycmp = common_type.is_pyobject self.is_pycmp = common_type.is_pyobject
if not common_type.is_error: if common_type is not None and not common_type.is_error:
if self.operand1.type != common_type: if self.operand1.type != common_type:
self.operand1 = self.operand1.coerce_to(common_type, env) self.operand1 = self.operand1.coerce_to(common_type, env)
self.coerce_operands_to(common_type, env) self.coerce_operands_to(common_type, env)
...@@ -5851,6 +5997,20 @@ class PrimaryCmpNode(ExprNode, CmpNode): ...@@ -5851,6 +5997,20 @@ class PrimaryCmpNode(ExprNode, CmpNode):
self.operand1.type.binary_op('=='), self.operand1.type.binary_op('=='),
self.operand1.result(), self.operand1.result(),
self.operand2.result()) self.operand2.result())
elif self.is_c_string_contains():
if self.operand2.type is bytes_type:
method = "__Pyx_BytesContains"
else:
method = "__Pyx_UnicodeContains"
if self.operator == "not_in":
negation = "!"
else:
negation = ""
return "(%s%s(%s, %s))" % (
negation,
method,
self.operand2.result(),
self.operand1.result())
else: else:
return "(%s %s %s)" % ( return "(%s %s %s)" % (
self.operand1.result(), self.operand1.result(),
...@@ -6097,6 +6257,9 @@ class NoneCheckNode(CoercionNode): ...@@ -6097,6 +6257,9 @@ class NoneCheckNode(CoercionNode):
def analyse_types(self, env): def analyse_types(self, env):
pass pass
def may_be_none(self):
return False
def result_in_temp(self): def result_in_temp(self):
return self.arg.result_in_temp() return self.arg.result_in_temp()
...@@ -6139,6 +6302,10 @@ class CoerceToPyTypeNode(CoercionNode): ...@@ -6139,6 +6302,10 @@ class CoerceToPyTypeNode(CoercionNode):
gil_message = "Converting to Python object" gil_message = "Converting to Python object"
def may_be_none(self):
# FIXME: is this always safe?
return False
def coerce_to_boolean(self, env): def coerce_to_boolean(self, env):
return self.arg.coerce_to_boolean(env).coerce_to_temp(env) return self.arg.coerce_to_boolean(env).coerce_to_temp(env)
...@@ -6201,7 +6368,14 @@ class CoerceToBooleanNode(CoercionNode): ...@@ -6201,7 +6368,14 @@ class CoerceToBooleanNode(CoercionNode):
# in a boolean context. # in a boolean context.
type = PyrexTypes.c_bint_type type = PyrexTypes.c_bint_type
_special_builtins = {
Builtin.list_type : 'PyList_GET_SIZE',
Builtin.tuple_type : 'PyTuple_GET_SIZE',
Builtin.bytes_type : 'PyBytes_GET_SIZE',
Builtin.unicode_type : 'PyUnicode_GET_SIZE',
}
def __init__(self, arg, env): def __init__(self, arg, env):
CoercionNode.__init__(self, arg) CoercionNode.__init__(self, arg)
if arg.type.is_pyobject: if arg.type.is_pyobject:
...@@ -6223,7 +6397,16 @@ class CoerceToBooleanNode(CoercionNode): ...@@ -6223,7 +6397,16 @@ class CoerceToBooleanNode(CoercionNode):
return "(%s != 0)" % self.arg.result() return "(%s != 0)" % self.arg.result()
def generate_result_code(self, code): def generate_result_code(self, code):
if self.arg.type.is_pyobject: if not self.is_temp:
return
test_func = self._special_builtins.get(self.arg.type)
if test_func is not None:
code.putln("%s = (%s != Py_None) && (%s(%s) != 0);" % (
self.result(),
self.arg.py_result(),
test_func,
self.arg.py_result()))
else:
code.putln( code.putln(
"%s = __Pyx_PyObject_IsTrue(%s); %s" % ( "%s = __Pyx_PyObject_IsTrue(%s); %s" % (
self.result(), self.result(),
...@@ -6345,6 +6528,9 @@ class ModuleRefNode(ExprNode): ...@@ -6345,6 +6528,9 @@ class ModuleRefNode(ExprNode):
def analyse_types(self, env): def analyse_types(self, env):
pass pass
def may_be_none(self):
return False
def calculate_result_code(self): def calculate_result_code(self):
return Naming.module_cname return Naming.module_cname
...@@ -6401,14 +6587,14 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/ ...@@ -6401,14 +6587,14 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
""", """,
impl = """ impl = """
static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) { static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
PyObject *__import__ = 0; PyObject *py_import = 0;
PyObject *empty_list = 0; PyObject *empty_list = 0;
PyObject *module = 0; PyObject *module = 0;
PyObject *global_dict = 0; PyObject *global_dict = 0;
PyObject *empty_dict = 0; PyObject *empty_dict = 0;
PyObject *list; PyObject *list;
__import__ = __Pyx_GetAttrString(%(BUILTINS)s, "__import__"); py_import = __Pyx_GetAttrString(%(BUILTINS)s, "__import__");
if (!__import__) if (!py_import)
goto bad; goto bad;
if (from_list) if (from_list)
list = from_list; list = from_list;
...@@ -6424,11 +6610,11 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) { ...@@ -6424,11 +6610,11 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
empty_dict = PyDict_New(); empty_dict = PyDict_New();
if (!empty_dict) if (!empty_dict)
goto bad; goto bad;
module = PyObject_CallFunctionObjArgs(__import__, module = PyObject_CallFunctionObjArgs(py_import,
name, global_dict, empty_dict, list, NULL); name, global_dict, empty_dict, list, NULL);
bad: bad:
Py_XDECREF(empty_list); Py_XDECREF(empty_list);
Py_XDECREF(__import__); Py_XDECREF(py_import);
Py_XDECREF(empty_dict); Py_XDECREF(empty_dict);
return module; return module;
} }
...@@ -6635,11 +6821,11 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j ...@@ -6635,11 +6821,11 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j
""" + ''.join([ """ + ''.join([
""" """
#define __Pyx_GetItemInt_%(type)s(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \\ #define __Pyx_GetItemInt_%(type)s(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \\
__Pyx_GetItemInt_%(type)s_Fast(o, i, size <= sizeof(long)) : \\ __Pyx_GetItemInt_%(type)s_Fast(o, i) : \\
__Pyx_GetItemInt_Generic(o, to_py_func(i))) __Pyx_GetItemInt_Generic(o, to_py_func(i)))
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_%(type)s_Fast(PyObject *o, Py_ssize_t i, int fits_long) { static CYTHON_INLINE PyObject *__Pyx_GetItemInt_%(type)s_Fast(PyObject *o, Py_ssize_t i) {
if (likely(o != Py_None)) { if (likely(o != Py_None)) {
if (likely((0 <= i) & (i < Py%(type)s_GET_SIZE(o)))) { if (likely((0 <= i) & (i < Py%(type)s_GET_SIZE(o)))) {
PyObject *r = Py%(type)s_GET_ITEM(o, i); PyObject *r = Py%(type)s_GET_ITEM(o, i);
...@@ -6652,16 +6838,16 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_%(type)s_Fast(PyObject *o, Py_ss ...@@ -6652,16 +6838,16 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_%(type)s_Fast(PyObject *o, Py_ss
return r; return r;
} }
} }
return __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i)); return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
} }
""" % {'type' : type_name} for type_name in ('List', 'Tuple') """ % {'type' : type_name} for type_name in ('List', 'Tuple')
]) + """ ]) + """
#define __Pyx_GetItemInt(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \\ #define __Pyx_GetItemInt(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \\
__Pyx_GetItemInt_Fast(o, i, size <= sizeof(long)) : \\ __Pyx_GetItemInt_Fast(o, i) : \\
__Pyx_GetItemInt_Generic(o, to_py_func(i))) __Pyx_GetItemInt_Generic(o, to_py_func(i)))
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int fits_long) { static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i) {
PyObject *r; PyObject *r;
if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) { if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) {
r = PyList_GET_ITEM(o, i); r = PyList_GET_ITEM(o, i);
...@@ -6675,7 +6861,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, ...@@ -6675,7 +6861,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
r = PySequence_GetItem(o, i); r = PySequence_GetItem(o, i);
} }
else { else {
r = __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i)); r = __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
} }
return r; return r;
} }
...@@ -6689,8 +6875,8 @@ impl = """ ...@@ -6689,8 +6875,8 @@ impl = """
setitem_int_utility_code = UtilityCode( setitem_int_utility_code = UtilityCode(
proto = """ proto = """
#define __Pyx_SetItemInt(o, i, v, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \\ #define __Pyx_SetItemInt(o, i, v, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \\
__Pyx_SetItemInt_Fast(o, i, v, size <= sizeof(long)) : \\ __Pyx_SetItemInt_Fast(o, i, v) : \\
__Pyx_SetItemInt_Generic(o, to_py_func(i), v)) __Pyx_SetItemInt_Generic(o, to_py_func(i), v))
static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) { static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) {
...@@ -6701,7 +6887,7 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyOb ...@@ -6701,7 +6887,7 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyOb
return r; return r;
} }
static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int fits_long) { static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v) {
if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) { if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) {
Py_INCREF(v); Py_INCREF(v);
Py_DECREF(PyList_GET_ITEM(o, i)); Py_DECREF(PyList_GET_ITEM(o, i));
...@@ -6711,7 +6897,7 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje ...@@ -6711,7 +6897,7 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && (likely(i >= 0))) else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && (likely(i >= 0)))
return PySequence_SetItem(o, i, v); return PySequence_SetItem(o, i, v);
else { else {
PyObject *j = fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i); PyObject *j = PyInt_FromSsize_t(i);
return __Pyx_SetItemInt_Generic(o, j, v); return __Pyx_SetItemInt_Generic(o, j, v);
} }
} }
...@@ -6723,8 +6909,8 @@ impl = """ ...@@ -6723,8 +6909,8 @@ impl = """
delitem_int_utility_code = UtilityCode( delitem_int_utility_code = UtilityCode(
proto = """ proto = """
#define __Pyx_DelItemInt(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \\ #define __Pyx_DelItemInt(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \\
__Pyx_DelItemInt_Fast(o, i, size <= sizeof(long)) : \\ __Pyx_DelItemInt_Fast(o, i) : \\
__Pyx_DelItem_Generic(o, to_py_func(i))) __Pyx_DelItem_Generic(o, to_py_func(i)))
static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) { static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) {
...@@ -6735,11 +6921,11 @@ static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) { ...@@ -6735,11 +6921,11 @@ static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) {
return r; return r;
} }
static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i, int fits_long) { static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i) {
if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && likely(i >= 0)) if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && likely(i >= 0))
return PySequence_DelItem(o, i); return PySequence_DelItem(o, i);
else { else {
PyObject *j = fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i); PyObject *j = PyInt_FromSsize_t(i);
return __Pyx_DelItem_Generic(o, j); return __Pyx_DelItem_Generic(o, j);
} }
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Cython Top Level # Cython Top Level
# #
import os, sys, re, codecs import os, sys, re
if sys.version_info[:2] < (2, 3): if sys.version_info[:2] < (2, 3):
sys.stderr.write("Sorry, Cython requires Python 2.3 or later\n") sys.stderr.write("Sorry, Cython requires Python 2.3 or later\n")
sys.exit(1) sys.exit(1)
...@@ -78,8 +78,8 @@ class Context(object): ...@@ -78,8 +78,8 @@ class Context(object):
self.pxds = {} # full name -> node tree self.pxds = {} # full name -> node tree
standard_include_path = os.path.abspath( standard_include_path = os.path.abspath(os.path.normpath(
os.path.join(os.path.dirname(__file__), '..', 'Includes')) os.path.join(os.path.dirname(__file__), os.path.pardir, 'Includes')))
self.include_directories = include_directories + [standard_include_path] self.include_directories = include_directories + [standard_include_path]
def create_pipeline(self, pxd, py=False): def create_pipeline(self, pxd, py=False):
...@@ -358,17 +358,17 @@ class Context(object): ...@@ -358,17 +358,17 @@ class Context(object):
for dir in dirs: for dir in dirs:
path = os.path.join(dir, dotted_filename) path = os.path.join(dir, dotted_filename)
if os.path.exists(path): if Utils.path_exists(path):
return path return path
if not include: if not include:
package_dir = self.check_package_dir(dir, package_names) package_dir = self.check_package_dir(dir, package_names)
if package_dir is not None: if package_dir is not None:
path = os.path.join(package_dir, module_filename) path = os.path.join(package_dir, module_filename)
if os.path.exists(path): if Utils.path_exists(path):
return path return path
path = os.path.join(dir, package_dir, module_name, path = os.path.join(dir, package_dir, module_name,
package_filename) package_filename)
if os.path.exists(path): if Utils.path_exists(path):
return path return path
return None return None
...@@ -381,20 +381,12 @@ class Context(object): ...@@ -381,20 +381,12 @@ class Context(object):
dir = parent dir = parent
return dir return dir
def is_package_dir(self, dir):
package_init = os.path.join(dir, "__init__.py")
return os.path.exists(package_init) or \
os.path.exists(package_init + "x") # same with .pyx
def check_package_dir(self, dir, package_names): def check_package_dir(self, dir, package_names):
package_dir = os.path.join(dir, *package_names)
if not os.path.exists(package_dir):
return None
for dirname in package_names: for dirname in package_names:
dir = os.path.join(dir, dirname) dir = os.path.join(dir, dirname)
if not self.is_package_dir(dir): if not self.is_package_dir(dir):
return None return None
return package_dir return dir
def c_file_out_of_date(self, source_path): def c_file_out_of_date(self, source_path):
c_path = Utils.replace_suffix(source_path, ".c") c_path = Utils.replace_suffix(source_path, ".c")
...@@ -424,9 +416,11 @@ class Context(object): ...@@ -424,9 +416,11 @@ class Context(object):
def is_package_dir(self, dir_path): def is_package_dir(self, dir_path):
# Return true if the given directory is a package directory. # Return true if the given directory is a package directory.
for filename in ("__init__.py", "__init__.pyx"): for filename in ("__init__.py",
"__init__.pyx",
"__init__.pxd"):
path = os.path.join(dir_path, filename) path = os.path.join(dir_path, filename)
if os.path.exists(path): if Utils.path_exists(path):
return 1 return 1
def read_dependency_file(self, source_path): def read_dependency_file(self, source_path):
......
...@@ -411,7 +411,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -411,7 +411,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for module in modules: for module in modules:
defined_here = module is env defined_here = module is env
modulecode.putln("/* Module declarations from %s */" % modulecode.putln("/* Module declarations from %s */" %
module.qualified_name.encode("ASCII", "ignore")) module.qualified_name)
self.generate_global_declarations(module, modulecode, defined_here) self.generate_global_declarations(module, modulecode, defined_here)
self.generate_cfunction_predeclarations(module, modulecode, defined_here) self.generate_cfunction_predeclarations(module, modulecode, defined_here)
...@@ -525,11 +525,29 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -525,11 +525,29 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
#define PyBaseString_Type PyUnicode_Type #define PyBaseString_Type PyUnicode_Type
#define PyStringObject PyUnicodeObject
#define PyString_Type PyUnicode_Type #define PyString_Type PyUnicode_Type
#define PyString_Check PyUnicode_Check
#define PyString_CheckExact PyUnicode_CheckExact #define PyString_CheckExact PyUnicode_CheckExact
#else #endif
#if PY_VERSION_HEX < 0x02060000
#define PyBytesObject PyStringObject
#define PyBytes_Type PyString_Type #define PyBytes_Type PyString_Type
#define PyBytes_Check PyString_Check
#define PyBytes_CheckExact PyString_CheckExact #define PyBytes_CheckExact PyString_CheckExact
#define PyBytes_FromString PyString_FromString
#define PyBytes_FromStringAndSize PyString_FromStringAndSize
#define PyBytes_FromFormat PyString_FromFormat
#define PyBytes_DecodeEscape PyString_DecodeEscape
#define PyBytes_AsString PyString_AsString
#define PyBytes_AsStringAndSize PyString_AsStringAndSize
#define PyBytes_Size PyString_Size
#define PyBytes_AS_STRING PyString_AS_STRING
#define PyBytes_GET_SIZE PyString_GET_SIZE
#define PyBytes_Repr PyString_Repr
#define PyBytes_Concat PyString_Concat
#define PyBytes_ConcatAndDel PyString_ConcatAndDel
#endif #endif
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
...@@ -634,11 +652,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -634,11 +652,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_includes(self, env, cimported_modules, code): def generate_includes(self, env, cimported_modules, code):
includes = [] includes = []
for filename in env.include_files: for filename in env.include_files:
# fake decoding of filenames to their original byte sequence byte_decoded_filenname = str(filename)
if filename[0] == '<' and filename[-1] == '>': if byte_decoded_filenname[0] == '<' and byte_decoded_filenname[-1] == '>':
code.putln('#include %s' % filename) code.putln('#include %s' % byte_decoded_filenname)
else: else:
code.putln('#include "%s"' % filename) code.putln('#include "%s"' % byte_decoded_filenname)
def generate_filename_table(self, code): def generate_filename_table(self, code):
code.putln("") code.putln("")
...@@ -1537,7 +1555,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1537,7 +1555,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_method_table(self, env, code): def generate_method_table(self, env, code):
code.putln("") code.putln("")
code.putln( code.putln(
"static struct PyMethodDef %s[] = {" % "static PyMethodDef %s[] = {" %
env.method_table_cname) env.method_table_cname)
for entry in env.pyfunc_entries: for entry in env.pyfunc_entries:
code.put_pymethoddef(entry, ",") code.put_pymethoddef(entry, ",")
...@@ -1659,8 +1677,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1659,8 +1677,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#endif") code.putln("#endif")
code.putln("%s = PyTuple_New(0); %s" % (Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos))); code.putln("%s = PyTuple_New(0); %s" % (Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos)));
code.putln("%s = __Pyx_PyBytes_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos))); code.putln("%s = PyBytes_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos)));
code.putln("#ifdef %s_USED" % Naming.binding_cfunc) code.putln("#ifdef %s_USED" % Naming.binding_cfunc)
code.putln("if (%s_init() < 0) %s" % (Naming.binding_cfunc, code.error_goto(self.pos))) code.putln("if (%s_init() < 0) %s" % (Naming.binding_cfunc, code.error_goto(self.pos)))
code.putln("#endif") code.putln("#endif")
...@@ -2177,7 +2195,11 @@ static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class ...@@ -2177,7 +2195,11 @@ static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class
PyOS_snprintf(warning, sizeof(warning), PyOS_snprintf(warning, sizeof(warning),
"%s.%s size changed, may indicate binary incompatibility", "%s.%s size changed, may indicate binary incompatibility",
module_name, class_name); module_name, class_name);
#if PY_VERSION_HEX < 0x02050000
PyErr_Warn(NULL, warning);
#else
PyErr_WarnEx(NULL, warning, 0); PyErr_WarnEx(NULL, warning, 0);
#endif
} }
else if (((PyTypeObject *)result)->tp_basicsize != size) { else if (((PyTypeObject *)result)->tp_basicsize != size) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
......
...@@ -630,6 +630,8 @@ class CArgDeclNode(Node): ...@@ -630,6 +630,8 @@ class CArgDeclNode(Node):
# base_type CBaseTypeNode # base_type CBaseTypeNode
# declarator CDeclaratorNode # declarator CDeclaratorNode
# not_none boolean Tagged with 'not None' # not_none boolean Tagged with 'not None'
# or_none boolean Tagged with 'or None'
# accept_none boolean Resolved boolean for not_none/or_none
# default ExprNode or None # default ExprNode or None
# default_value PyObjectConst constant for default value # default_value PyObjectConst constant for default value
# annotation ExprNode or None Py3 function arg annotation # annotation ExprNode or None Py3 function arg annotation
...@@ -1024,10 +1026,8 @@ class CppClassNode(CStructOrUnionDefNode): ...@@ -1024,10 +1026,8 @@ class CppClassNode(CStructOrUnionDefNode):
def analyse_declarations(self, env): def analyse_declarations(self, env):
scope = None scope = None
if self.attributes: if self.attributes is not None:
scope = CppClassScope(self.name, env) scope = CppClassScope(self.name, env)
else:
self.attributes = None
base_class_types = [] base_class_types = []
for base_class_name in self.base_classes: for base_class_name in self.base_classes:
base_class_entry = env.lookup(base_class_name) base_class_entry = env.lookup(base_class_name)
...@@ -1457,6 +1457,33 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1457,6 +1457,33 @@ class FuncDefNode(StatNode, BlockNode):
error(arg.pos, error(arg.pos,
"Argument type '%s' is incomplete" % arg.type) "Argument type '%s' is incomplete" % arg.type)
return env.declare_arg(arg.name, arg.type, arg.pos) return env.declare_arg(arg.name, arg.type, arg.pos)
def generate_arg_type_test(self, arg, code):
# Generate type test for one argument.
if arg.type.typeobj_is_available():
code.globalstate.use_utility_code(arg_type_test_utility_code)
typeptr_cname = arg.type.typeptr_cname
arg_code = "((PyObject *)%s)" % arg.entry.cname
code.putln(
'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
arg_code,
typeptr_cname,
arg.accept_none,
arg.name,
arg.type.is_builtin_type,
code.error_goto(arg.pos)))
else:
error(arg.pos, "Cannot test type of extern C class "
"without type object name specification")
def generate_arg_none_check(self, arg, code):
# Generate None check for one argument.
code.globalstate.use_utility_code(arg_type_test_utility_code)
code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % arg.entry.cname)
code.putln('''PyErr_Format(PyExc_TypeError, "Argument '%s' must not be None"); %s''' % (
arg.name,
code.error_goto(arg.pos)))
code.putln('}')
def generate_wrapper_functions(self, code): def generate_wrapper_functions(self, code):
pass pass
...@@ -1709,23 +1736,8 @@ class CFuncDefNode(FuncDefNode): ...@@ -1709,23 +1736,8 @@ class CFuncDefNode(FuncDefNode):
for arg in self.type.args: for arg in self.type.args:
if arg.needs_type_test: if arg.needs_type_test:
self.generate_arg_type_test(arg, code) self.generate_arg_type_test(arg, code)
elif arg.type.is_pyobject and not arg.accept_none:
def generate_arg_type_test(self, arg, code): self.generate_arg_none_check(arg, code)
# Generate type test for one argument.
if arg.type.typeobj_is_available():
typeptr_cname = arg.type.typeptr_cname
arg_code = "((PyObject *)%s)" % arg.cname
code.putln(
'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
arg_code,
typeptr_cname,
not arg.not_none,
arg.name,
type.is_builtin_type,
code.error_goto(arg.pos)))
else:
error(arg.pos, "Cannot test type of extern C class "
"without type object name specification")
def error_value(self): def error_value(self):
if self.return_type.is_pyobject: if self.return_type.is_pyobject:
...@@ -1921,6 +1933,7 @@ class DefNode(FuncDefNode): ...@@ -1921,6 +1933,7 @@ class DefNode(FuncDefNode):
def analyse_argument_types(self, env): def analyse_argument_types(self, env):
directive_locals = self.directive_locals = env.directives['locals'] directive_locals = self.directive_locals = env.directives['locals']
allow_none_for_extension_args = env.directives['allow_none_for_extension_args']
for arg in self.args: for arg in self.args:
if hasattr(arg, 'name'): if hasattr(arg, 'name'):
type = arg.type type = arg.type
...@@ -1949,12 +1962,29 @@ class DefNode(FuncDefNode): ...@@ -1949,12 +1962,29 @@ class DefNode(FuncDefNode):
arg.needs_conversion = 0 arg.needs_conversion = 0
arg.needs_type_test = 0 arg.needs_type_test = 0
arg.is_generic = 1 arg.is_generic = 1
if arg.not_none and not arg.type.is_extension_type: if arg.type.is_pyobject:
error(self.pos, if arg.or_none:
"Only extension type arguments can have 'not None'") arg.accept_none = True
elif arg.not_none:
arg.accept_none = False
elif arg.type.is_extension_type or arg.type.is_builtin_type:
if arg.default and arg.default.constant_result is None:
# special case: def func(MyType obj = None)
arg.accept_none = True
else:
# default depends on compiler directive
arg.accept_none = allow_none_for_extension_args
else:
# probably just a plain 'object'
arg.accept_none = True
else:
arg.accept_none = True # won't be used, but must be there
if arg.not_none:
error(arg.pos, "Only Python type arguments can have 'not None'")
if arg.or_none:
error(arg.pos, "Only Python type arguments can have 'or None'")
def analyse_signature(self, env): def analyse_signature(self, env):
any_type_tests_needed = 0
if self.entry.is_special: if self.entry.is_special:
self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg) self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
elif not env.directives['always_allow_keywords'] and not (self.star_arg or self.starstar_arg): elif not env.directives['always_allow_keywords'] and not (self.star_arg or self.starstar_arg):
...@@ -1999,7 +2029,6 @@ class DefNode(FuncDefNode): ...@@ -1999,7 +2029,6 @@ class DefNode(FuncDefNode):
if not arg.type.same_as(arg.hdr_type): if not arg.type.same_as(arg.hdr_type):
if arg.hdr_type.is_pyobject and arg.type.is_pyobject: if arg.hdr_type.is_pyobject and arg.type.is_pyobject:
arg.needs_type_test = 1 arg.needs_type_test = 1
any_type_tests_needed = 1
else: else:
arg.needs_conversion = 1 arg.needs_conversion = 1
if arg.needs_conversion: if arg.needs_conversion:
...@@ -2017,9 +2046,6 @@ class DefNode(FuncDefNode): ...@@ -2017,9 +2046,6 @@ class DefNode(FuncDefNode):
if arg.is_generic and \ if arg.is_generic and \
(arg.type.is_extension_type or arg.type.is_builtin_type): (arg.type.is_extension_type or arg.type.is_builtin_type):
arg.needs_type_test = 1 arg.needs_type_test = 1
any_type_tests_needed = 1
if any_type_tests_needed:
env.use_utility_code(arg_type_test_utility_code)
def bad_signature(self): def bad_signature(self):
sig = self.entry.signature sig = self.entry.signature
...@@ -2175,7 +2201,11 @@ class DefNode(FuncDefNode): ...@@ -2175,7 +2201,11 @@ class DefNode(FuncDefNode):
code.putln("%s; /*proto*/" % header) code.putln("%s; /*proto*/" % header)
if proto_only: if proto_only:
return return
if self.entry.doc and Options.docstrings: if (Options.docstrings and self.entry.doc and
(not self.entry.is_special or
self.entry.signature.method_flags()) and
not self.entry.scope.is_property_scope
):
docstr = self.entry.doc docstr = self.entry.doc
if docstr.is_unicode: if docstr.is_unicode:
docstr = docstr.utf8encode() docstr = docstr.utf8encode()
...@@ -2714,10 +2744,13 @@ class DefNode(FuncDefNode): ...@@ -2714,10 +2744,13 @@ class DefNode(FuncDefNode):
func = new_type.from_py_function func = new_type.from_py_function
# copied from CoerceFromPyTypeNode # copied from CoerceFromPyTypeNode
if func: if func:
code.putln("%s = %s(%s); %s" % ( lhs = arg.entry.cname
arg.entry.cname, rhs = "%s(%s)" % (func, arg.hdr_cname)
func, if new_type.is_enum:
arg.hdr_cname, rhs = PyrexTypes.typecast(new_type, PyrexTypes.c_long_type, rhs)
code.putln("%s = %s; %s" % (
lhs,
rhs,
code.error_goto_if(new_type.error_condition(arg.entry.cname), arg.pos))) code.error_goto_if(new_type.error_condition(arg.entry.cname), arg.pos)))
else: else:
error(arg.pos, error(arg.pos,
...@@ -2746,24 +2779,9 @@ class DefNode(FuncDefNode): ...@@ -2746,24 +2779,9 @@ class DefNode(FuncDefNode):
for arg in self.args: for arg in self.args:
if arg.needs_type_test: if arg.needs_type_test:
self.generate_arg_type_test(arg, code) self.generate_arg_type_test(arg, code)
elif not arg.accept_none and arg.type.is_pyobject:
def generate_arg_type_test(self, arg, code): self.generate_arg_none_check(arg, code)
# Generate type test for one argument.
if arg.type.typeobj_is_available():
typeptr_cname = arg.type.typeptr_cname
arg_code = "((PyObject *)%s)" % arg.entry.cname
code.putln(
'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
arg_code,
typeptr_cname,
not arg.not_none,
arg.name,
arg.type.is_builtin_type,
code.error_goto(arg.pos)))
else:
error(arg.pos, "Cannot test type of extern C class "
"without type object name specification")
def error_value(self): def error_value(self):
return self.entry.signature.error_value return self.entry.signature.error_value
......
...@@ -95,7 +95,11 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -95,7 +95,11 @@ class IterationTransform(Visitor.VisitorTransform):
return self._transform_carray_iteration(node, iterator) return self._transform_carray_iteration(node, iterator)
elif iterator.type.is_array: elif iterator.type.is_array:
return self._transform_carray_iteration(node, iterator) return self._transform_carray_iteration(node, iterator)
elif not isinstance(iterator, ExprNodes.SimpleCallNode): elif iterator.type in (Builtin.bytes_type, Builtin.unicode_type):
return self._transform_string_iteration(node, iterator)
# the rest is based on function calls
if not isinstance(iterator, ExprNodes.SimpleCallNode):
return node return node
function = iterator.function function = iterator.function
...@@ -132,6 +136,70 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -132,6 +136,70 @@ class IterationTransform(Visitor.VisitorTransform):
return node return node
PyUnicode_AS_UNICODE_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_unicode_ptr_type, [
PyrexTypes.CFuncTypeArg("s", Builtin.unicode_type, None)
])
PyUnicode_GET_SIZE_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("s", Builtin.unicode_type, None)
])
PyBytes_AS_STRING_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_char_ptr_type, [
PyrexTypes.CFuncTypeArg("s", Builtin.bytes_type, None)
])
PyBytes_GET_SIZE_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("s", Builtin.bytes_type, None)
])
def _transform_string_iteration(self, node, slice_node):
if not node.target.type.is_int:
return node
if slice_node.type is Builtin.unicode_type:
unpack_func = "PyUnicode_AS_UNICODE"
len_func = "PyUnicode_GET_SIZE"
unpack_func_type = self.PyUnicode_AS_UNICODE_func_type
len_func_type = self.PyUnicode_GET_SIZE_func_type
elif slice_node.type is Builtin.bytes_type:
unpack_func = "PyBytes_AS_STRING"
unpack_func_type = self.PyBytes_AS_STRING_func_type
len_func = "PyBytes_GET_SIZE"
len_func_type = self.PyBytes_GET_SIZE_func_type
else:
return node
unpack_temp_node = UtilNodes.LetRefNode(
slice_node.as_none_safe_node("'NoneType' is not iterable"))
slice_base_node = ExprNodes.PythonCapiCallNode(
slice_node.pos, unpack_func, unpack_func_type,
args = [unpack_temp_node],
is_temp = 0,
)
len_node = ExprNodes.PythonCapiCallNode(
slice_node.pos, len_func, len_func_type,
args = [unpack_temp_node],
is_temp = 0,
)
return UtilNodes.LetNode(
unpack_temp_node,
self._transform_carray_iteration(
node,
ExprNodes.SliceIndexNode(
slice_node.pos,
base = slice_base_node,
start = None,
step = None,
stop = len_node,
type = slice_base_node.type,
is_temp = 1,
)))
def _transform_carray_iteration(self, node, slice_node): def _transform_carray_iteration(self, node, slice_node):
if isinstance(slice_node, ExprNodes.SliceIndexNode): if isinstance(slice_node, ExprNodes.SliceIndexNode):
slice_base = slice_node.base slice_base = slice_node.base
...@@ -166,7 +234,7 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -166,7 +234,7 @@ class IterationTransform(Visitor.VisitorTransform):
stop_ptr_node = ExprNodes.AddNode( stop_ptr_node = ExprNodes.AddNode(
stop.pos, stop.pos,
operand1=carray_ptr, operand1=ExprNodes.CloneNode(carray_ptr),
operator='+', operator='+',
operand2=stop, operand2=stop,
type=ptr_type type=ptr_type
...@@ -507,7 +575,9 @@ class SwitchTransform(Visitor.VisitorTransform): ...@@ -507,7 +575,9 @@ class SwitchTransform(Visitor.VisitorTransform):
The requirement is that every clause be an (or of) var == value, where the var The requirement is that every clause be an (or of) var == value, where the var
is common among all clauses and both var and value are ints. is common among all clauses and both var and value are ints.
""" """
def extract_conditions(self, cond): NO_MATCH = (None, None, None)
def extract_conditions(self, cond, allow_not_in):
while True: while True:
if isinstance(cond, ExprNodes.CoerceToTempNode): if isinstance(cond, ExprNodes.CoerceToTempNode):
cond = cond.arg cond = cond.arg
...@@ -519,55 +589,185 @@ class SwitchTransform(Visitor.VisitorTransform): ...@@ -519,55 +589,185 @@ class SwitchTransform(Visitor.VisitorTransform):
else: else:
break break
if (isinstance(cond, ExprNodes.PrimaryCmpNode) if isinstance(cond, ExprNodes.PrimaryCmpNode):
and cond.cascade is None if cond.cascade is None and not cond.is_python_comparison():
and cond.operator == '==' if cond.operator == '==':
and not cond.is_python_comparison()): not_in = False
if is_common_value(cond.operand1, cond.operand1): elif allow_not_in and cond.operator == '!=':
if cond.operand2.is_literal: not_in = True
return cond.operand1, [cond.operand2] elif cond.is_c_string_contains() and \
elif hasattr(cond.operand2, 'entry') and cond.operand2.entry and cond.operand2.entry.is_const: isinstance(cond.operand2, (ExprNodes.UnicodeNode, ExprNodes.BytesNode)):
return cond.operand1, [cond.operand2] not_in = cond.operator == 'not_in'
if is_common_value(cond.operand2, cond.operand2): if not_in and not allow_not_in:
if cond.operand1.is_literal: return self.NO_MATCH
return cond.operand2, [cond.operand1] # this looks somewhat silly, but it does the right
elif hasattr(cond.operand1, 'entry') and cond.operand1.entry and cond.operand1.entry.is_const: # checks for NameNode and AttributeNode
return cond.operand2, [cond.operand1] if is_common_value(cond.operand1, cond.operand1):
elif (isinstance(cond, ExprNodes.BoolBinopNode) return not_in, cond.operand1, self.extract_in_string_conditions(cond.operand2)
and cond.operator == 'or'): else:
t1, c1 = self.extract_conditions(cond.operand1) return self.NO_MATCH
t2, c2 = self.extract_conditions(cond.operand2) else:
if is_common_value(t1, t2): return self.NO_MATCH
return t1, c1+c2 # this looks somewhat silly, but it does the right
return None, None # checks for NameNode and AttributeNode
if is_common_value(cond.operand1, cond.operand1):
if cond.operand2.is_literal:
return not_in, cond.operand1, [cond.operand2]
elif getattr(cond.operand2, 'entry', None) \
and cond.operand2.entry.is_const:
return not_in, cond.operand1, [cond.operand2]
if is_common_value(cond.operand2, cond.operand2):
if cond.operand1.is_literal:
return not_in, cond.operand2, [cond.operand1]
elif getattr(cond.operand1, 'entry', None) \
and cond.operand1.entry.is_const:
return not_in, cond.operand2, [cond.operand1]
elif isinstance(cond, ExprNodes.BoolBinopNode):
if cond.operator == 'or' or (allow_not_in and cond.operator == 'and'):
allow_not_in = (cond.operator == 'and')
not_in_1, t1, c1 = self.extract_conditions(cond.operand1, allow_not_in)
not_in_2, t2, c2 = self.extract_conditions(cond.operand2, allow_not_in)
if t1 is not None and not_in_1 == not_in_2 and is_common_value(t1, t2):
if (not not_in_1) or allow_not_in:
return not_in_1, t1, c1+c2
return self.NO_MATCH
def extract_in_string_conditions(self, string_literal):
if isinstance(string_literal, ExprNodes.UnicodeNode):
charvals = map(ord, set(string_literal.value))
charvals.sort()
return [ ExprNodes.IntNode(string_literal.pos, value=str(charval),
constant_result=charval)
for charval in charvals ]
else:
# this is a bit tricky as Py3's bytes type returns
# integers on iteration, whereas Py2 returns 1-char byte
# strings
characters = string_literal.value
characters = list(set([ characters[i:i+1] for i in range(len(characters)) ]))
characters.sort()
return [ ExprNodes.CharNode(string_literal.pos, value=charval,
constant_result=charval)
for charval in characters ]
def extract_common_conditions(self, common_var, condition, allow_not_in):
not_in, var, conditions = self.extract_conditions(condition, allow_not_in)
if var is None:
return self.NO_MATCH
elif common_var is not None and not is_common_value(var, common_var):
return self.NO_MATCH
elif not var.type.is_int or sum([not cond.type.is_int for cond in conditions]):
return self.NO_MATCH
return not_in, var, conditions
def has_duplicate_values(self, condition_values):
# duplicated values don't work in a switch statement
seen = set()
for value in condition_values:
if value.constant_result is not ExprNodes.not_a_constant:
if value.constant_result in seen:
return True
seen.add(value.constant_result)
else:
# this isn't completely safe as we don't know the
# final C value, but this is about the best we can do
seen.add(getattr(getattr(value, 'entry', None), 'cname'))
return False
def visit_IfStatNode(self, node): def visit_IfStatNode(self, node):
self.visitchildren(node)
common_var = None common_var = None
case_count = 0
cases = [] cases = []
for if_clause in node.if_clauses: for if_clause in node.if_clauses:
var, conditions = self.extract_conditions(if_clause.condition) _, common_var, conditions = self.extract_common_conditions(
if var is None: common_var, if_clause.condition, False)
return node if common_var is None:
elif common_var is not None and not is_common_value(var, common_var): self.visitchildren(node)
return node return node
elif not var.type.is_int or sum([not cond.type.is_int for cond in conditions]): cases.append(Nodes.SwitchCaseNode(pos = if_clause.pos,
return node conditions = conditions,
else: body = if_clause.body))
common_var = var
case_count += len(conditions) if sum([ len(case.conditions) for case in cases ]) < 2:
cases.append(Nodes.SwitchCaseNode(pos = if_clause.pos, self.visitchildren(node)
conditions = conditions, return node
body = if_clause.body)) if self.has_duplicate_values(sum([case.conditions for case in cases], [])):
if case_count < 2: self.visitchildren(node)
return node return node
common_var = unwrap_node(common_var) common_var = unwrap_node(common_var)
return Nodes.SwitchStatNode(pos = node.pos, switch_node = Nodes.SwitchStatNode(pos = node.pos,
test = common_var, test = common_var,
cases = cases, cases = cases,
else_clause = node.else_clause) else_clause = node.else_clause)
return switch_node
def visit_CondExprNode(self, node):
not_in, common_var, conditions = self.extract_common_conditions(
None, node.test, True)
if common_var is None \
or len(conditions) < 2 \
or self.has_duplicate_values(conditions):
self.visitchildren(node)
return node
return self.build_simple_switch_statement(
node, common_var, conditions, not_in,
node.true_val, node.false_val)
def visit_BoolBinopNode(self, node):
not_in, common_var, conditions = self.extract_common_conditions(
None, node, True)
if common_var is None \
or len(conditions) < 2 \
or self.has_duplicate_values(conditions):
self.visitchildren(node)
return node
return self.build_simple_switch_statement(
node, common_var, conditions, not_in,
ExprNodes.BoolNode(node.pos, value=True, constant_result=True),
ExprNodes.BoolNode(node.pos, value=False, constant_result=False))
def visit_PrimaryCmpNode(self, node):
not_in, common_var, conditions = self.extract_common_conditions(
None, node, True)
if common_var is None \
or len(conditions) < 2 \
or self.has_duplicate_values(conditions):
self.visitchildren(node)
return node
return self.build_simple_switch_statement(
node, common_var, conditions, not_in,
ExprNodes.BoolNode(node.pos, value=True, constant_result=True),
ExprNodes.BoolNode(node.pos, value=False, constant_result=False))
def build_simple_switch_statement(self, node, common_var, conditions,
not_in, true_val, false_val):
result_ref = UtilNodes.ResultRefNode(node)
true_body = Nodes.SingleAssignmentNode(
node.pos,
lhs = result_ref,
rhs = true_val,
first = True)
false_body = Nodes.SingleAssignmentNode(
node.pos,
lhs = result_ref,
rhs = false_val,
first = True)
if not_in:
true_body, false_body = false_body, true_body
cases = [Nodes.SwitchCaseNode(pos = node.pos,
conditions = conditions,
body = true_body)]
common_var = unwrap_node(common_var)
switch_node = Nodes.SwitchStatNode(pos = node.pos,
test = common_var,
cases = cases,
else_clause = false_body)
return UtilNodes.TempResultFromStatNode(result_ref, switch_node)
visit_Node = Visitor.VisitorTransform.recurse_to_children visit_Node = Visitor.VisitorTransform.recurse_to_children
...@@ -591,7 +791,9 @@ class FlattenInListTransform(Visitor.VisitorTransform, SkipDeclarations): ...@@ -591,7 +791,9 @@ class FlattenInListTransform(Visitor.VisitorTransform, SkipDeclarations):
else: else:
return node return node
if not isinstance(node.operand2, (ExprNodes.TupleNode, ExprNodes.ListNode)): if not isinstance(node.operand2, (ExprNodes.TupleNode,
ExprNodes.ListNode,
ExprNodes.SetNode)):
return node return node
args = node.operand2.args args = node.operand2.args
...@@ -778,7 +980,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): ...@@ -778,7 +980,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
def _function_is_builtin_name(self, function): def _function_is_builtin_name(self, function):
if not function.is_name: if not function.is_name:
return False return False
entry = self.env_stack[-1].lookup(function.name) entry = self.current_env().lookup(function.name)
if not entry or getattr(entry, 'scope', None) is not Builtin.builtin_scope: if not entry or getattr(entry, 'scope', None) is not Builtin.builtin_scope:
return False return False
return True return True
...@@ -907,6 +1109,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -907,6 +1109,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
arg_tuple = node.positional_args arg_tuple = node.positional_args
if not isinstance(arg_tuple, ExprNodes.TupleNode): if not isinstance(arg_tuple, ExprNodes.TupleNode):
return node return node
if node.starstar_arg:
return node
args = arg_tuple.args args = arg_tuple.args
return self._dispatch_to_handler( return self._dispatch_to_handler(
node, function, args, node.keyword_args) node, function, args, node.keyword_args)
...@@ -937,6 +1141,27 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -937,6 +1141,27 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return node return node
return node.arg return node.arg
def visit_TypecastNode(self, node):
"""
Drop redundant type casts.
"""
self.visitchildren(node)
if node.type == node.operand.type:
return node.operand
return node
def visit_CoerceToBooleanNode(self, node):
"""Drop redundant conversion nodes after tree changes.
"""
self.visitchildren(node)
arg = node.arg
if isinstance(arg, ExprNodes.PyTypeTestNode):
arg = arg.arg
if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
if arg.type in (PyrexTypes.py_object_type, Builtin.bool_type):
return arg.arg.coerce_to_boolean(self.current_env())
return node
def visit_CoerceFromPyTypeNode(self, node): def visit_CoerceFromPyTypeNode(self, node):
"""Drop redundant conversion nodes after tree changes. """Drop redundant conversion nodes after tree changes.
...@@ -951,11 +1176,20 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -951,11 +1176,20 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
if node.type == arg.type: if node.type == arg.type:
return arg return arg
else: else:
return arg.coerce_to(node.type, self.env_stack[-1]) return arg.coerce_to(node.type, self.current_env())
if not isinstance(arg, ExprNodes.SimpleCallNode): if isinstance(arg, ExprNodes.PyTypeTestNode):
return node arg = arg.arg
if not (node.type.is_int or node.type.is_float): if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
return node if arg.type is PyrexTypes.py_object_type:
if node.type.assignable_from(arg.arg.type):
# completely redundant C->Py->C coercion
return arg.arg.coerce_to(node.type, self.current_env())
if isinstance(arg, ExprNodes.SimpleCallNode):
if node.type.is_int or node.type.is_float:
return self._optimise_numeric_cast_call(node, arg)
return node
def _optimise_numeric_cast_call(self, node, arg):
function = arg.function function = arg.function
if not isinstance(function, ExprNodes.NameNode) \ if not isinstance(function, ExprNodes.NameNode) \
or not function.type.is_builtin_type \ or not function.type.is_builtin_type \
...@@ -1079,8 +1313,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1079,8 +1313,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return node return node
arg = pos_args[0] arg = pos_args[0]
if arg.type is Builtin.dict_type: if arg.type is Builtin.dict_type:
arg = ExprNodes.NoneCheckNode( arg = arg.as_none_safe_node("'NoneType' is not iterable")
arg, "PyExc_TypeError", "'NoneType' is not iterable")
return ExprNodes.PythonCapiCallNode( return ExprNodes.PythonCapiCallNode(
node.pos, "PyDict_Copy", self.PyDict_Copy_func_type, node.pos, "PyDict_Copy", self.PyDict_Copy_func_type,
args = [arg], args = [arg],
...@@ -1103,8 +1336,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1103,8 +1336,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return node return node
if not isinstance(list_arg, (ExprNodes.ComprehensionNode, if not isinstance(list_arg, (ExprNodes.ComprehensionNode,
ExprNodes.ListNode)): ExprNodes.ListNode)):
pos_args[0] = ExprNodes.NoneCheckNode( pos_args[0] = list_arg.as_none_safe_node(
list_arg, "PyExc_TypeError",
"'NoneType' object is not iterable") "'NoneType' object is not iterable")
return ExprNodes.PythonCapiCallNode( return ExprNodes.PythonCapiCallNode(
...@@ -1126,8 +1358,12 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1126,8 +1358,12 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
""" """
# Note: this requires the float() function to be typed as # Note: this requires the float() function to be typed as
# returning a C 'double' # returning a C 'double'
if len(pos_args) != 1: if len(pos_args) == 0:
self._error_wrong_arg_count('float', node, pos_args, 1) return ExprNode.FloatNode(
node, value="0.0", constant_result=0.0
).coerce_to(Builtin.float_type, self.current_env())
elif len(pos_args) != 1:
self._error_wrong_arg_count('float', node, pos_args, '0 or 1')
return node return node
func_arg = pos_args[0] func_arg = pos_args[0]
if isinstance(func_arg, ExprNodes.CoerceToPyTypeNode): if isinstance(func_arg, ExprNodes.CoerceToPyTypeNode):
...@@ -1145,6 +1381,19 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1145,6 +1381,19 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
utility_code = pyobject_as_double_utility_code, utility_code = pyobject_as_double_utility_code,
py_name = "float") py_name = "float")
def _handle_simple_function_bool(self, node, pos_args):
"""Transform bool(x) into a type coercion to a boolean.
"""
if len(pos_args) == 0:
return ExprNodes.BoolNode(
node.pos, value=False, constant_result=False
).coerce_to(Builtin.bool_type, self.current_env())
elif len(pos_args) != 1:
self._error_wrong_arg_count('bool', node, pos_args, '0 or 1')
return node
return pos_args[0].coerce_to_boolean(
self.current_env()).coerce_to_pyobject(self.current_env())
### builtin functions ### builtin functions
PyObject_GetAttr2_func_type = PyrexTypes.CFuncType( PyObject_GetAttr2_func_type = PyrexTypes.CFuncType(
...@@ -1211,8 +1460,25 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1211,8 +1460,25 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
PyrexTypes.CFuncTypeArg("bytes", PyrexTypes.c_char_ptr_type, None) PyrexTypes.CFuncTypeArg("bytes", PyrexTypes.c_char_ptr_type, None)
]) ])
PyObject_Size_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None)
])
_map_to_capi_len_function = {
Builtin.unicode_type : "PyUnicode_GET_SIZE",
Builtin.str_type : "Py_SIZE", # works in Py2 and Py3
Builtin.bytes_type : "PyBytes_GET_SIZE",
Builtin.list_type : "PyList_GET_SIZE",
Builtin.tuple_type : "PyTuple_GET_SIZE",
Builtin.dict_type : "PyDict_Size",
Builtin.set_type : "PySet_Size",
Builtin.frozenset_type : "PySet_Size",
}.get
def _handle_simple_function_len(self, node, pos_args): def _handle_simple_function_len(self, node, pos_args):
"""Replace len(char*) by the equivalent call to strlen(). """Replace len(char*) by the equivalent call to strlen() and
len(known_builtin_type) by an equivalent C-API call.
""" """
if len(pos_args) != 1: if len(pos_args) != 1:
self._error_wrong_arg_count('len', node, pos_args, 1) self._error_wrong_arg_count('len', node, pos_args, 1)
...@@ -1220,22 +1486,28 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1220,22 +1486,28 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
arg = pos_args[0] arg = pos_args[0]
if isinstance(arg, ExprNodes.CoerceToPyTypeNode): if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
arg = arg.arg arg = arg.arg
if not arg.type.is_string: if arg.type.is_string:
return node new_node = ExprNodes.PythonCapiCallNode(
if not node.type.is_numeric: node.pos, "strlen", self.Pyx_strlen_func_type,
# this optimisation only works when we already replaced args = [arg],
# len() by PyObject_Length() which returns a Py_ssize_t is_temp = node.is_temp,
# instead of a Python object, so we can return a plain utility_code = include_string_h_utility_code)
# size_t instead without caring about Python object elif arg.type.is_pyobject:
# conversion etc. cfunc_name = self._map_to_capi_len_function(arg.type)
if cfunc_name is None:
return node
if not arg.is_literal:
arg = arg.as_none_safe_node(
"object of type 'NoneType' has no len()")
new_node = ExprNodes.PythonCapiCallNode(
node.pos, cfunc_name, self.PyObject_Size_func_type,
args = [arg],
is_temp = node.is_temp)
else:
return node return node
node = ExprNodes.PythonCapiCallNode( if node.type not in (PyrexTypes.c_size_t_type, PyrexTypes.c_py_ssize_t_type):
node.pos, "strlen", self.Pyx_strlen_func_type, new_node = new_node.coerce_to(node.type, self.current_env())
args = [arg], return new_node
is_temp = node.is_temp,
utility_code = include_string_h_utility_code
)
return node
Pyx_Type_func_type = PyrexTypes.CFuncType( Pyx_Type_func_type = PyrexTypes.CFuncType(
Builtin.type_type, [ Builtin.type_type, [
...@@ -1289,8 +1561,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1289,8 +1561,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
if not type_arg.type_entry: if not type_arg.type_entry:
# arbitrary variable, needs a None check for safety # arbitrary variable, needs a None check for safety
type_arg = ExprNodes.NoneCheckNode( type_arg = type_arg.as_none_safe_node(
type_arg, "PyExc_TypeError",
"object.__new__(X): X is not a type object (NoneType)") "object.__new__(X): X is not a type object (NoneType)")
return ExprNodes.PythonCapiCallNode( return ExprNodes.PythonCapiCallNode(
...@@ -1405,8 +1676,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1405,8 +1676,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
PyrexTypes.CFuncTypeArg("dict", PyrexTypes.py_object_type, None), PyrexTypes.CFuncTypeArg("dict", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("key", PyrexTypes.py_object_type, None), PyrexTypes.CFuncTypeArg("key", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("default", PyrexTypes.py_object_type, None), PyrexTypes.CFuncTypeArg("default", PyrexTypes.py_object_type, None),
], ])
exception_value = "NULL")
def _handle_simple_method_dict_get(self, node, args, is_unbound_method): def _handle_simple_method_dict_get(self, node, args, is_unbound_method):
"""Replace dict.get() by a call to PyDict_GetItem(). """Replace dict.get() by a call to PyDict_GetItem().
...@@ -1422,19 +1692,206 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1422,19 +1692,206 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
'get', is_unbound_method, args, 'get', is_unbound_method, args,
utility_code = dict_getitem_default_utility_code) utility_code = dict_getitem_default_utility_code)
### unicode type methods
PyUnicode_Splitlines_func_type = PyrexTypes.CFuncType(
Builtin.list_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("keepends", PyrexTypes.c_bint_type, None),
])
def _handle_simple_method_unicode_splitlines(self, node, args, is_unbound_method):
"""Replace unicode.splitlines(...) by a direct call to the
corresponding C-API function.
"""
if len(args) not in (1,2):
self._error_wrong_arg_count('unicode.splitlines', node, args, "1 or 2")
return node
self._inject_bint_default_argument(node, args, 1, False)
return self._substitute_method_call(
node, "PyUnicode_Splitlines", self.PyUnicode_Splitlines_func_type,
'splitlines', is_unbound_method, args)
PyUnicode_Join_func_type = PyrexTypes.CFuncType(
Builtin.unicode_type, [
PyrexTypes.CFuncTypeArg("sep", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("iterable", PyrexTypes.py_object_type, None),
])
def _handle_simple_method_unicode_join(self, node, args, is_unbound_method):
"""Replace unicode.join(...) by a direct call to the
corresponding C-API function.
"""
if len(args) != 2:
self._error_wrong_arg_count('unicode.join', node, args, 2)
return node
return self._substitute_method_call(
node, "PyUnicode_Join", self.PyUnicode_Join_func_type,
'join', is_unbound_method, args)
PyUnicode_Split_func_type = PyrexTypes.CFuncType(
Builtin.list_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("sep", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("maxsplit", PyrexTypes.c_py_ssize_t_type, None),
]
)
def _handle_simple_method_unicode_split(self, node, args, is_unbound_method):
"""Replace unicode.split(...) by a direct call to the
corresponding C-API function.
"""
if len(args) not in (1,2,3):
self._error_wrong_arg_count('unicode.split', node, args, "1-3")
return node
if len(args) < 2:
args.append(ExprNodes.NullNode(node.pos))
self._inject_int_default_argument(
node, args, 2, PyrexTypes.c_py_ssize_t_type, "-1")
return self._substitute_method_call(
node, "PyUnicode_Split", self.PyUnicode_Split_func_type,
'split', is_unbound_method, args)
PyUnicode_Tailmatch_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_bint_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("end", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("direction", PyrexTypes.c_int_type, None),
],
exception_value = '-1')
def _handle_simple_method_unicode_endswith(self, node, args, is_unbound_method):
return self._inject_unicode_tailmatch(
node, args, is_unbound_method, 'endswith', +1)
def _handle_simple_method_unicode_startswith(self, node, args, is_unbound_method):
return self._inject_unicode_tailmatch(
node, args, is_unbound_method, 'startswith', -1)
def _inject_unicode_tailmatch(self, node, args, is_unbound_method,
method_name, direction):
"""Replace unicode.startswith(...) and unicode.endswith(...)
by a direct call to the corresponding C-API function.
"""
if len(args) not in (2,3,4):
self._error_wrong_arg_count('unicode.%s' % method_name, node, args, "2-4")
return node
self._inject_int_default_argument(
node, args, 2, PyrexTypes.c_py_ssize_t_type, "0")
self._inject_int_default_argument(
node, args, 3, PyrexTypes.c_py_ssize_t_type, "PY_SSIZE_T_MAX")
args.append(ExprNodes.IntNode(
node.pos, value=str(direction), type=PyrexTypes.c_int_type))
method_call = self._substitute_method_call(
node, "__Pyx_PyUnicode_Tailmatch", self.PyUnicode_Tailmatch_func_type,
method_name, is_unbound_method, args,
utility_code = unicode_tailmatch_utility_code)
return method_call.coerce_to(Builtin.bool_type, self.current_env())
PyUnicode_Find_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("end", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("direction", PyrexTypes.c_int_type, None),
],
exception_value = '-2')
def _handle_simple_method_unicode_find(self, node, args, is_unbound_method):
return self._inject_unicode_find(
node, args, is_unbound_method, 'find', +1)
def _handle_simple_method_unicode_rfind(self, node, args, is_unbound_method):
return self._inject_unicode_find(
node, args, is_unbound_method, 'rfind', -1)
def _inject_unicode_find(self, node, args, is_unbound_method,
method_name, direction):
"""Replace unicode.find(...) and unicode.rfind(...) by a
direct call to the corresponding C-API function.
"""
if len(args) not in (2,3,4):
self._error_wrong_arg_count('unicode.%s' % method_name, node, args, "2-4")
return node
self._inject_int_default_argument(
node, args, 2, PyrexTypes.c_py_ssize_t_type, "0")
self._inject_int_default_argument(
node, args, 3, PyrexTypes.c_py_ssize_t_type, "PY_SSIZE_T_MAX")
args.append(ExprNodes.IntNode(
node.pos, value=str(direction), type=PyrexTypes.c_int_type))
method_call = self._substitute_method_call(
node, "PyUnicode_Find", self.PyUnicode_Find_func_type,
method_name, is_unbound_method, args)
return method_call.coerce_to_pyobject(self.current_env())
PyUnicode_Count_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("end", PyrexTypes.c_py_ssize_t_type, None),
],
exception_value = '-1')
def _handle_simple_method_unicode_count(self, node, args, is_unbound_method):
"""Replace unicode.count(...) by a direct call to the
corresponding C-API function.
"""
if len(args) not in (2,3,4):
self._error_wrong_arg_count('unicode.count', node, args, "2-4")
return node
self._inject_int_default_argument(
node, args, 2, PyrexTypes.c_py_ssize_t_type, "0")
self._inject_int_default_argument(
node, args, 3, PyrexTypes.c_py_ssize_t_type, "PY_SSIZE_T_MAX")
method_call = self._substitute_method_call(
node, "PyUnicode_Count", self.PyUnicode_Count_func_type,
'count', is_unbound_method, args)
return method_call.coerce_to_pyobject(self.current_env())
PyUnicode_Replace_func_type = PyrexTypes.CFuncType(
Builtin.unicode_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("replstr", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("maxcount", PyrexTypes.c_py_ssize_t_type, None),
])
def _handle_simple_method_unicode_replace(self, node, args, is_unbound_method):
"""Replace unicode.replace(...) by a direct call to the
corresponding C-API function.
"""
if len(args) not in (3,4):
self._error_wrong_arg_count('unicode.replace', node, args, "3-4")
return node
self._inject_int_default_argument(
node, args, 3, PyrexTypes.c_py_ssize_t_type, "-1")
return self._substitute_method_call(
node, "PyUnicode_Replace", self.PyUnicode_Replace_func_type,
'replace', is_unbound_method, args)
PyUnicode_AsEncodedString_func_type = PyrexTypes.CFuncType( PyUnicode_AsEncodedString_func_type = PyrexTypes.CFuncType(
Builtin.bytes_type, [ Builtin.bytes_type, [
PyrexTypes.CFuncTypeArg("obj", Builtin.unicode_type, None), PyrexTypes.CFuncTypeArg("obj", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_char_ptr_type, None), PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_char_ptr_type, None),
PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None), PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None),
], ])
exception_value = "NULL")
PyUnicode_AsXyzString_func_type = PyrexTypes.CFuncType( PyUnicode_AsXyzString_func_type = PyrexTypes.CFuncType(
Builtin.bytes_type, [ Builtin.bytes_type, [
PyrexTypes.CFuncTypeArg("obj", Builtin.unicode_type, None), PyrexTypes.CFuncTypeArg("obj", Builtin.unicode_type, None),
], ])
exception_value = "NULL")
_special_encodings = ['UTF8', 'UTF16', 'Latin1', 'ASCII', _special_encodings = ['UTF8', 'UTF16', 'Latin1', 'ASCII',
'unicode_escape', 'raw_unicode_escape'] 'unicode_escape', 'raw_unicode_escape']
...@@ -1498,8 +1955,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1498,8 +1955,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
PyrexTypes.CFuncTypeArg("string", PyrexTypes.c_char_ptr_type, None), PyrexTypes.CFuncTypeArg("string", PyrexTypes.c_char_ptr_type, None),
PyrexTypes.CFuncTypeArg("size", PyrexTypes.c_py_ssize_t_type, None), PyrexTypes.CFuncTypeArg("size", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None), PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None),
], ])
exception_value = "NULL")
PyUnicode_Decode_func_type = PyrexTypes.CFuncType( PyUnicode_Decode_func_type = PyrexTypes.CFuncType(
Builtin.unicode_type, [ Builtin.unicode_type, [
...@@ -1507,8 +1963,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1507,8 +1963,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
PyrexTypes.CFuncTypeArg("size", PyrexTypes.c_py_ssize_t_type, None), PyrexTypes.CFuncTypeArg("size", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_char_ptr_type, None), PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_char_ptr_type, None),
PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None), PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None),
], ])
exception_value = "NULL")
def _handle_simple_method_bytes_decode(self, node, args, is_unbound_method): def _handle_simple_method_bytes_decode(self, node, args, is_unbound_method):
"""Replace char*.decode() by a direct C-API call to the """Replace char*.decode() by a direct C-API call to the
...@@ -1529,7 +1984,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1529,7 +1984,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
start = None start = None
else: else:
if start.type.is_pyobject: if start.type.is_pyobject:
start = start.coerce_to(PyrexTypes.c_py_ssize_t_type, self.env_stack[-1]) start = start.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
if stop: if stop:
start = UtilNodes.LetRefNode(start) start = UtilNodes.LetRefNode(start)
temps.append(start) temps.append(start)
...@@ -1541,7 +1996,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1541,7 +1996,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
type=string_node.type type=string_node.type
) )
if stop and stop.type.is_pyobject: if stop and stop.type.is_pyobject:
stop = stop.coerce_to(PyrexTypes.c_py_ssize_t_type, self.env_stack[-1]) stop = stop.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
elif isinstance(args[0], ExprNodes.CoerceToPyTypeNode) \ elif isinstance(args[0], ExprNodes.CoerceToPyTypeNode) \
and args[0].arg.type.is_string: and args[0].arg.type.is_string:
# use strlen() to find the string length, just as CPython would # use strlen() to find the string length, just as CPython would
...@@ -1560,7 +2015,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1560,7 +2015,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
args = [string_node], args = [string_node],
is_temp = False, is_temp = False,
utility_code = include_string_h_utility_code, utility_code = include_string_h_utility_code,
).coerce_to(PyrexTypes.c_py_ssize_t_type, self.env_stack[-1]) ).coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
elif start: elif start:
stop = ExprNodes.SubNode( stop = ExprNodes.SubNode(
pos = stop.pos, pos = stop.pos,
...@@ -1614,20 +2069,25 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1614,20 +2069,25 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return None return None
def _unpack_encoding_and_error_mode(self, pos, args): def _unpack_encoding_and_error_mode(self, pos, args):
encoding_node = args[1] null_node = ExprNodes.NullNode(pos)
if isinstance(encoding_node, ExprNodes.CoerceToPyTypeNode):
encoding_node = encoding_node.arg if len(args) >= 2:
if isinstance(encoding_node, (ExprNodes.UnicodeNode, ExprNodes.StringNode, encoding_node = args[1]
ExprNodes.BytesNode)): if isinstance(encoding_node, ExprNodes.CoerceToPyTypeNode):
encoding = encoding_node.value encoding_node = encoding_node.arg
encoding_node = ExprNodes.BytesNode(encoding_node.pos, value=encoding, if isinstance(encoding_node, (ExprNodes.UnicodeNode, ExprNodes.StringNode,
type=PyrexTypes.c_char_ptr_type) ExprNodes.BytesNode)):
elif encoding_node.type.is_string: encoding = encoding_node.value
encoding = None encoding_node = ExprNodes.BytesNode(encoding_node.pos, value=encoding,
type=PyrexTypes.c_char_ptr_type)
elif encoding_node.type.is_string:
encoding = None
else:
return None
else: else:
return None encoding = None
encoding_node = null_node
null_node = ExprNodes.NullNode(pos)
if len(args) == 3: if len(args) == 3:
error_handling_node = args[2] error_handling_node = args[2]
if isinstance(error_handling_node, ExprNodes.CoerceToPyTypeNode): if isinstance(error_handling_node, ExprNodes.CoerceToPyTypeNode):
...@@ -1652,21 +2112,23 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1652,21 +2112,23 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return (encoding, encoding_node, error_handling, error_handling_node) return (encoding, encoding_node, error_handling, error_handling_node)
### helpers
def _substitute_method_call(self, node, name, func_type, def _substitute_method_call(self, node, name, func_type,
attr_name, is_unbound_method, args=(), attr_name, is_unbound_method, args=(),
utility_code=None): utility_code=None):
args = list(args) args = list(args)
if args: if args and not args[0].is_literal:
self_arg = args[0] self_arg = args[0]
if is_unbound_method: if is_unbound_method:
self_arg = ExprNodes.NoneCheckNode( self_arg = self_arg.as_none_safe_node(
self_arg, "PyExc_TypeError",
"descriptor '%s' requires a '%s' object but received a 'NoneType'" % ( "descriptor '%s' requires a '%s' object but received a 'NoneType'" % (
attr_name, node.function.obj.name)) attr_name, node.function.obj.name))
else: else:
self_arg = ExprNodes.NoneCheckNode( self_arg = self_arg.as_none_safe_node(
self_arg, "PyExc_AttributeError", "'NoneType' object has no attribute '%s'" % attr_name,
"'NoneType' object has no attribute '%s'" % attr_name) error = "PyExc_AttributeError")
args[0] = self_arg args[0] = self_arg
return ExprNodes.PythonCapiCallNode( return ExprNodes.PythonCapiCallNode(
node.pos, name, func_type, node.pos, name, func_type,
...@@ -1675,6 +2137,48 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1675,6 +2137,48 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
utility_code = utility_code utility_code = utility_code
) )
def _inject_int_default_argument(self, node, args, arg_index, type, default_value):
assert len(args) >= arg_index
if len(args) == arg_index:
args.append(ExprNodes.IntNode(node.pos, value=str(default_value), type=type))
else:
args[arg_index] = args[arg_index].coerce_to(type, self.current_env())
def _inject_bint_default_argument(self, node, args, arg_index, default_value):
assert len(args) >= arg_index
if len(args) == arg_index:
args.append(ExprNodes.BoolNode(node.pos, value=bool(default_value)))
else:
args[arg_index] = args[arg_index].coerce_to_boolean(self.current_env())
unicode_tailmatch_utility_code = UtilityCode(
# Python's unicode.startswith() and unicode.endswith() support a
# tuple of prefixes/suffixes, whereas it's much more common to
# test for a single unicode string.
proto = '''
static int __Pyx_PyUnicode_Tailmatch(PyObject* s, PyObject* substr, \
Py_ssize_t start, Py_ssize_t end, int direction);
''',
impl = '''
static int __Pyx_PyUnicode_Tailmatch(PyObject* s, PyObject* substr,
Py_ssize_t start, Py_ssize_t end, int direction) {
if (unlikely(PyTuple_Check(substr))) {
int result;
Py_ssize_t i;
for (i = 0; i < PyTuple_GET_SIZE(substr); i++) {
result = PyUnicode_Tailmatch(s, PyTuple_GET_ITEM(substr, i),
start, end, direction);
if (result) {
return result;
}
}
return 0;
}
return PyUnicode_Tailmatch(s, substr, start, end, direction);
}
''',
)
dict_getitem_default_utility_code = UtilityCode( dict_getitem_default_utility_code = UtilityCode(
proto = ''' proto = '''
...@@ -1736,6 +2240,7 @@ impl = "" ...@@ -1736,6 +2240,7 @@ impl = ""
pop_utility_code = UtilityCode( pop_utility_code = UtilityCode(
proto = """ proto = """
static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) { static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) {
PyObject *r, *m;
#if PY_VERSION_HEX >= 0x02040000 #if PY_VERSION_HEX >= 0x02040000
if (likely(PyList_CheckExact(L)) if (likely(PyList_CheckExact(L))
/* Check that both the size is positive and no reallocation shrinking needs to be done. */ /* Check that both the size is positive and no reallocation shrinking needs to be done. */
...@@ -1744,7 +2249,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) { ...@@ -1744,7 +2249,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) {
return PyList_GET_ITEM(L, PyList_GET_SIZE(L)); return PyList_GET_ITEM(L, PyList_GET_SIZE(L));
} }
#endif #endif
PyObject *r, *m;
m = __Pyx_GetAttrString(L, "pop"); m = __Pyx_GetAttrString(L, "pop");
if (!m) return NULL; if (!m) return NULL;
r = PyObject_CallObject(m, NULL); r = PyObject_CallObject(m, NULL);
......
...@@ -58,6 +58,7 @@ directive_defaults = { ...@@ -58,6 +58,7 @@ directive_defaults = {
'cdivision': False, # was True before 0.12 'cdivision': False, # was True before 0.12
'cdivision_warnings': False, 'cdivision_warnings': False,
'always_allow_keywords': False, 'always_allow_keywords': False,
'allow_none_for_extension_args': True,
'wraparound' : True, 'wraparound' : True,
'ccomplex' : False, # use C99/C++ for complex types and arith 'ccomplex' : False, # use C99/C++ for complex types and arith
'callspec' : "", 'callspec' : "",
......
...@@ -1310,8 +1310,8 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -1310,8 +1310,8 @@ class TransformBuiltinMethods(EnvTransform):
node = BoolNode(node.pos, value=True) node = BoolNode(node.pos, value=True)
elif attribute == u'NULL': elif attribute == u'NULL':
node = NullNode(node.pos) node = NullNode(node.pos)
elif attribute == u'set': elif attribute in (u'set', u'frozenset'):
node = NameNode(node.pos, name=EncodedString('set')) node = NameNode(node.pos, name=EncodedString(attribute))
elif not PyrexTypes.parse_basic_type(attribute): elif not PyrexTypes.parse_basic_type(attribute):
error(node.pos, u"'%s' not a valid cython attribute or is being used incorrectly" % attribute) error(node.pos, u"'%s' not a valid cython attribute or is being used incorrectly" % attribute)
return node return node
......
...@@ -45,7 +45,7 @@ cpdef p_atom(PyrexScanner s) ...@@ -45,7 +45,7 @@ cpdef p_atom(PyrexScanner s)
cpdef p_name(PyrexScanner s, name) cpdef p_name(PyrexScanner s, name)
cpdef p_cat_string_literal(PyrexScanner s) cpdef p_cat_string_literal(PyrexScanner s)
cpdef p_opt_string_literal(PyrexScanner s) cpdef p_opt_string_literal(PyrexScanner s)
cpdef p_string_literal(PyrexScanner s) cpdef p_string_literal(PyrexScanner s, kind_override=*)
cpdef p_list_maker(PyrexScanner s) cpdef p_list_maker(PyrexScanner s)
cpdef p_comp_iter(PyrexScanner s, body) cpdef p_comp_iter(PyrexScanner s, body)
cpdef p_comp_for(PyrexScanner s, body) cpdef p_comp_for(PyrexScanner s, body)
......
...@@ -11,14 +11,6 @@ import os ...@@ -11,14 +11,6 @@ import os
import re import re
import sys import sys
try:
from __builtin__ import set
except (ImportError, AttributeError):
try:
from builtins import set
except (ImportError, AttributeError):
from sets import Set as set
from Cython.Compiler.Scanning import PyrexScanner, FileSourceDescriptor from Cython.Compiler.Scanning import PyrexScanner, FileSourceDescriptor
import Nodes import Nodes
import ExprNodes import ExprNodes
...@@ -678,7 +670,7 @@ def p_opt_string_literal(s): ...@@ -678,7 +670,7 @@ def p_opt_string_literal(s):
else: else:
return None return None
def p_string_literal(s): def p_string_literal(s, kind_override=None):
# A single string or char literal. # A single string or char literal.
# Returns (kind, value) where kind in ('b', 'c', 'u') # Returns (kind, value) where kind in ('b', 'c', 'u')
# s.sy == 'BEGIN_STRING' # s.sy == 'BEGIN_STRING'
...@@ -695,6 +687,8 @@ def p_string_literal(s): ...@@ -695,6 +687,8 @@ def p_string_literal(s):
if Future.unicode_literals in s.context.future_directives: if Future.unicode_literals in s.context.future_directives:
if kind == '': if kind == '':
kind = 'u' kind = 'u'
if kind_override is not None and kind_override in 'ub':
kind = kind_override
if kind == 'u': if kind == 'u':
chars = StringEncoding.UnicodeLiteralBuilder() chars = StringEncoding.UnicodeLiteralBuilder()
else: else:
...@@ -1907,7 +1901,9 @@ basic_c_type_names = ("void", "char", "int", "float", "double", "bint") ...@@ -1907,7 +1901,9 @@ basic_c_type_names = ("void", "char", "int", "float", "double", "bint")
special_basic_c_types = { special_basic_c_types = {
# name : (signed, longness) # name : (signed, longness)
"Py_UNICODE" : (0, 0),
"Py_ssize_t" : (2, 0), "Py_ssize_t" : (2, 0),
"ssize_t" : (2, 0),
"size_t" : (0, 0), "size_t" : (0, 0),
} }
...@@ -2000,7 +1996,7 @@ def p_c_func_declarator(s, pos, ctx, base, cmethod_flag): ...@@ -2000,7 +1996,7 @@ def p_c_func_declarator(s, pos, ctx, base, cmethod_flag):
exception_value = exc_val, exception_check = exc_check, exception_value = exc_val, exception_check = exc_check,
nogil = nogil or ctx.nogil or with_gil, with_gil = with_gil) nogil = nogil or ctx.nogil or with_gil, with_gil = with_gil)
supported_overloaded_operators = set([ supported_overloaded_operators = cython.set([
'+', '-', '*', '/', '%', '+', '-', '*', '/', '%',
'++', '--', '~', '|', '&', '^', '<<', '>>', '++', '--', '~', '|', '&', '^', '<<', '>>',
'==', '!=', '>=', '>', '<=', '<', '==', '!=', '>=', '>', '<=', '<',
...@@ -2139,7 +2135,7 @@ def p_optional_ellipsis(s): ...@@ -2139,7 +2135,7 @@ def p_optional_ellipsis(s):
def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0, def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0,
kw_only = 0, annotated = 1): kw_only = 0, annotated = 1):
pos = s.position() pos = s.position()
not_none = 0 not_none = or_none = 0
default = None default = None
annotation = None annotation = None
if s.in_python_file: if s.in_python_file:
...@@ -2152,15 +2148,17 @@ def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0, ...@@ -2152,15 +2148,17 @@ def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0,
else: else:
base_type = p_c_base_type(s, cmethod_flag, nonempty = nonempty) base_type = p_c_base_type(s, cmethod_flag, nonempty = nonempty)
declarator = p_c_declarator(s, ctx, nonempty = nonempty) declarator = p_c_declarator(s, ctx, nonempty = nonempty)
if s.sy == 'not' and not s.in_python_file: if s.sy in ('not', 'or') and not s.in_python_file:
kind = s.sy
s.next() s.next()
if s.sy == 'IDENT' and s.systring == 'None': if s.sy == 'IDENT' and s.systring == 'None':
s.next() s.next()
else: else:
s.error("Expected 'None'") s.error("Expected 'None'")
if not in_pyfunc: if not in_pyfunc:
error(pos, "'not None' only allowed in Python functions") error(pos, "'%s None' only allowed in Python functions" % kind)
not_none = 1 or_none = kind == 'or'
not_none = kind == 'not'
if annotated and s.sy == ':': if annotated and s.sy == ':':
s.next() s.next()
annotation = p_simple_expr(s) annotation = p_simple_expr(s)
...@@ -2177,6 +2175,7 @@ def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0, ...@@ -2177,6 +2175,7 @@ def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0,
base_type = base_type, base_type = base_type,
declarator = declarator, declarator = declarator,
not_none = not_none, not_none = not_none,
or_none = or_none,
default = default, default = default,
annotation = annotation, annotation = annotation,
kw_only = kw_only) kw_only = kw_only)
...@@ -2243,10 +2242,10 @@ def p_cdef_extern_block(s, pos, ctx): ...@@ -2243,10 +2242,10 @@ def p_cdef_extern_block(s, pos, ctx):
s.next() s.next()
else: else:
_, include_file = p_string_literal(s) _, include_file = p_string_literal(s)
ctx = ctx(cdef_flag = 1, visibility = 'extern')
if s.systring == "namespace": if s.systring == "namespace":
s.next() s.next()
ctx.namespace = p_string_literal(s)[1] ctx.namespace = p_string_literal(s, kind_override='u')[1]
ctx = ctx(cdef_flag = 1, visibility = 'extern')
if p_nogil(s): if p_nogil(s):
ctx.nogil = 1 ctx.nogil = 1
body = p_suite(s, ctx) body = p_suite(s, ctx)
...@@ -2720,6 +2719,7 @@ def p_cpp_class_definition(s, pos, ctx): ...@@ -2720,6 +2719,7 @@ def p_cpp_class_definition(s, pos, ctx):
s.expect_newline("Expected a newline") s.expect_newline("Expected a newline")
s.expect_dedent() s.expect_dedent()
else: else:
attributes = None
s.expect_newline("Syntax error in C++ class definition") s.expect_newline("Syntax error in C++ class definition")
return Nodes.CppClassNode(pos, return Nodes.CppClassNode(pos,
name = class_name, name = class_name,
......
# #
# Pyrex - Types # Pyrex - Types
# #
...@@ -162,6 +160,12 @@ class PyrexType(BaseType): ...@@ -162,6 +160,12 @@ class PyrexType(BaseType):
return 1 return 1
def public_decl(base_code, dll_linkage):
if dll_linkage:
return "%s(%s)" % (dll_linkage, base_code)
else:
return base_code
def create_typedef_type(name, base_type, cname, is_external=0): def create_typedef_type(name, base_type, cname, is_external=0):
if base_type.is_complex: if base_type.is_complex:
if is_external: if is_external:
...@@ -170,6 +174,7 @@ def create_typedef_type(name, base_type, cname, is_external=0): ...@@ -170,6 +174,7 @@ def create_typedef_type(name, base_type, cname, is_external=0):
else: else:
return CTypedefType(name, base_type, cname, is_external) return CTypedefType(name, base_type, cname, is_external)
class CTypedefType(BaseType): class CTypedefType(BaseType):
# #
# Pseudo-type defined with a ctypedef statement in a # Pseudo-type defined with a ctypedef statement in a
...@@ -286,6 +291,7 @@ class CTypedefType(BaseType): ...@@ -286,6 +291,7 @@ class CTypedefType(BaseType):
def __getattr__(self, name): def __getattr__(self, name):
return getattr(self.typedef_base_type, name) return getattr(self.typedef_base_type, name)
class BufferType(BaseType): class BufferType(BaseType):
# #
# Delegates most attribute # Delegates most attribute
...@@ -320,12 +326,7 @@ class BufferType(BaseType): ...@@ -320,12 +326,7 @@ class BufferType(BaseType):
def __repr__(self): def __repr__(self):
return "<BufferType %r>" % self.base return "<BufferType %r>" % self.base
def public_decl(base, dll_linkage):
if dll_linkage:
return "%s(%s)" % (dll_linkage, base)
else:
return base
class PyObjectType(PyrexType): class PyObjectType(PyrexType):
# #
# Base class for all Python object types (reference-counted). # Base class for all Python object types (reference-counted).
...@@ -355,9 +356,11 @@ class PyObjectType(PyrexType): ...@@ -355,9 +356,11 @@ class PyObjectType(PyrexType):
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display: if pyrex or for_display:
return self.base_declaration_code("object", entity_code) base_code = "object"
else: else:
return "%s *%s" % (public_decl("PyObject", dll_linkage), entity_code) base_code = public_decl("PyObject", dll_linkage)
entity_code = "*%s" % entity_code
return self.base_declaration_code(base_code, entity_code)
def as_pyobject(self, cname): def as_pyobject(self, cname):
if (not self.is_complete()) or self.is_extension_type: if (not self.is_complete()) or self.is_extension_type:
...@@ -436,9 +439,11 @@ class BuiltinObjectType(PyObjectType): ...@@ -436,9 +439,11 @@ class BuiltinObjectType(PyObjectType):
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display: if pyrex or for_display:
return self.base_declaration_code(self.name, entity_code) base_code = self.name
else: else:
return "%s *%s" % (public_decl("PyObject", dll_linkage), entity_code) base_code = public_decl("PyObject", dll_linkage)
entity_code = "*%s" % entity_code
return self.base_declaration_code(base_code, entity_code)
class PyExtensionType(PyObjectType): class PyExtensionType(PyObjectType):
...@@ -514,17 +519,18 @@ class PyExtensionType(PyObjectType): ...@@ -514,17 +519,18 @@ class PyExtensionType(PyObjectType):
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0, deref = 0): for_display = 0, dll_linkage = None, pyrex = 0, deref = 0):
if pyrex or for_display: if pyrex or for_display:
return self.base_declaration_code(self.name, entity_code) base_code = self.name
else: else:
if self.typedef_flag: if self.typedef_flag:
objstruct = self.objstruct_cname objstruct = self.objstruct_cname
else: else:
objstruct = "struct %s" % self.objstruct_cname objstruct = "struct %s" % self.objstruct_cname
base = public_decl(objstruct, dll_linkage) base_code = public_decl(objstruct, dll_linkage)
if deref: if deref:
return "%s %s" % (base, entity_code) assert not entity_code
else: else:
return "%s *%s" % (base, entity_code) entity_code = "*%s" % entity_code
return self.base_declaration_code(base_code, entity_code)
def type_test_code(self, py_arg, notnone=False): def type_test_code(self, py_arg, notnone=False):
...@@ -584,6 +590,10 @@ class CType(PyrexType): ...@@ -584,6 +590,10 @@ class CType(PyrexType):
class CVoidType(CType): class CVoidType(CType):
#
# C "void" type
#
is_void = 1 is_void = 1
def __repr__(self): def __repr__(self):
...@@ -591,8 +601,11 @@ class CVoidType(CType): ...@@ -591,8 +601,11 @@ class CVoidType(CType):
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
base = public_decl("void", dll_linkage) if pyrex or for_display:
return self.base_declaration_code(base, entity_code) base_code = "void"
else:
base_code = public_decl("void", dll_linkage)
return self.base_declaration_code(base_code, entity_code)
def is_complete(self): def is_complete(self):
return 0 return 0
...@@ -625,10 +638,12 @@ class CNumericType(CType): ...@@ -625,10 +638,12 @@ class CNumericType(CType):
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
base = public_decl(self.sign_and_name(), dll_linkage) type_name = self.sign_and_name()
if for_display: if pyrex or for_display:
base = base.replace('PY_LONG_LONG', 'long long') base_code = type_name.replace('PY_LONG_LONG', 'long long')
return self.base_declaration_code(base, entity_code) else:
base_code = public_decl(type_name, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
type_conversion_predeclarations = "" type_conversion_predeclarations = ""
...@@ -775,27 +790,40 @@ class CIntType(CNumericType): ...@@ -775,27 +790,40 @@ class CIntType(CNumericType):
is_int = 1 is_int = 1
typedef_flag = 0 typedef_flag = 0
to_py_function = "PyInt_FromLong" to_py_function = None
from_py_function = "__Pyx_PyInt_AsInt" from_py_function = None
exception_value = -1 exception_value = -1
def __init__(self, rank, signed, is_returncode = 0): def __init__(self, rank, signed = 1):
CNumericType.__init__(self, rank, signed) CNumericType.__init__(self, rank, signed)
self.is_returncode = is_returncode if self.to_py_function is None:
if self.from_py_function == "__Pyx_PyInt_AsInt": self.to_py_function = self.get_to_py_type_conversion()
self.from_py_function = self.get_type_conversion() if self.from_py_function is None:
self.from_py_function = self.get_from_py_type_conversion()
def get_type_conversion(self):
ctype = self.declaration_code('') def get_to_py_type_conversion(self):
bits = ctype.split(" ", 1) if self.rank < list(rank_to_type_name).index('int'):
if len(bits) == 1: # This assumes sizeof(short) < sizeof(int)
sign_word, type_name = "", bits[0] return "PyInt_FromLong"
else: else:
sign_word, type_name = bits # Py{Int|Long}_From[Unsigned]Long[Long]
type_name = type_name.replace("PY_LONG_LONG","long long") Prefix = "Int"
SignWord = sign_word.title() SignWord = ""
TypeName = type_name.title().replace(" ", "") TypeName = "Long"
if "Long" in TypeName: if not self.signed:
Prefix = "Long"
SignWord = "Unsigned"
if self.rank >= list(rank_to_type_name).index('PY_LONG_LONG'):
Prefix = "Long"
TypeName = "LongLong"
return "Py%s_From%s%s" % (Prefix, SignWord, TypeName)
def get_from_py_type_conversion(self):
type_name = rank_to_type_name[self.rank]
type_name = type_name.replace("PY_LONG_LONG", "long long")
TypeName = type_name.title().replace(" ", "")
SignWord = self.sign_words[self.signed].strip().title()
if self.rank >= list(rank_to_type_name).index('long'):
utility_code = c_long_from_py_function utility_code = c_long_from_py_function
else: else:
utility_code = c_int_from_py_function utility_code = c_int_from_py_function
...@@ -809,16 +837,6 @@ class CIntType(CNumericType): ...@@ -809,16 +837,6 @@ class CIntType(CNumericType):
return src_type.is_int or src_type.is_enum or src_type is error_type return src_type.is_int or src_type.is_enum or src_type is error_type
class CBIntType(CIntType):
to_py_function = "__Pyx_PyBool_FromLong"
from_py_function = "__Pyx_PyObject_IsTrue"
exception_check = 0
def __repr__(self):
return "<CNumericType bint>"
class CAnonEnumType(CIntType): class CAnonEnumType(CIntType):
is_enum = 1 is_enum = 1
...@@ -827,30 +845,34 @@ class CAnonEnumType(CIntType): ...@@ -827,30 +845,34 @@ class CAnonEnumType(CIntType):
return 'int' return 'int'
class CUIntType(CIntType): class CReturnCodeType(CIntType):
to_py_function = "PyLong_FromUnsignedLong" is_returncode = 1
exception_value = -1
class CLongType(CIntType): class CBIntType(CIntType):
to_py_function = "PyInt_FromLong"
class CULongType(CUIntType):
to_py_function = "PyLong_FromUnsignedLong" to_py_function = "__Pyx_PyBool_FromLong"
from_py_function = "__Pyx_PyObject_IsTrue"
exception_check = 0
def __repr__(self):
return "<CNumericType bint>"
class CLongLongType(CIntType):
to_py_function = "PyLong_FromLongLong" class CPyUnicodeIntType(CIntType):
# Py_UNICODE
# Conversion from a unicode string to Py_UNICODE at runtime is not
# currently supported and may never be - we only convert from and
# to integers here. The maximum value for a Py_UNICODE is
# 1114111, so PyInt_FromLong() will do just fine here.
class CULongLongType(CUIntType): to_py_function = "PyInt_FromLong"
from_py_function = "__Pyx_PyInt_AsPy_UNICODE"
to_py_function = "PyLong_FromUnsignedLongLong" def sign_and_name(self):
return "Py_UNICODE"
class CPySSizeTType(CIntType): class CPySSizeTType(CIntType):
...@@ -859,16 +881,23 @@ class CPySSizeTType(CIntType): ...@@ -859,16 +881,23 @@ class CPySSizeTType(CIntType):
from_py_function = "__Pyx_PyIndex_AsSsize_t" from_py_function = "__Pyx_PyIndex_AsSsize_t"
def sign_and_name(self): def sign_and_name(self):
return rank_to_type_name[self.rank] return "Py_ssize_t"
class CSSizeTType(CIntType):
to_py_function = "PyInt_FromSsize_t"
from_py_function = "PyInt_AsSsize_t"
class CSizeTType(CUIntType): def sign_and_name(self):
return "ssize_t"
class CSizeTType(CIntType):
to_py_function = "__Pyx_PyInt_FromSize_t" to_py_function = "__Pyx_PyInt_FromSize_t"
from_py_function = "__Pyx_PyInt_AsSize_t" from_py_function = "__Pyx_PyInt_AsSize_t"
def sign_and_name(self): def sign_and_name(self):
return rank_to_type_name[self.rank] return "size_t"
class CFloatType(CNumericType): class CFloatType(CNumericType):
...@@ -937,15 +966,17 @@ class CComplexType(CNumericType): ...@@ -937,15 +966,17 @@ class CComplexType(CNumericType):
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
if for_display: if pyrex or for_display:
base = public_decl(self.real_type.sign_and_name() + " complex", dll_linkage) real_code = self.real_type.declaration_code("", for_display, dll_linkage, pyrex)
base_code = "%s complex" % real_code
else: else:
base = public_decl(self.sign_and_name(), dll_linkage) base_code = public_decl(self.sign_and_name(), dll_linkage)
return self.base_declaration_code(base, entity_code) return self.base_declaration_code(base_code, entity_code)
def sign_and_name(self): def sign_and_name(self):
real_type_name = self.real_type.specialization_name() real_type_name = self.real_type.specialization_name()
real_type_name = real_type_name.replace('long__double','long_double') real_type_name = real_type_name.replace('long__double','long_double')
real_type_name = real_type_name.replace('PY_LONG_LONG','long_long')
return Naming.type_prefix + real_type_name + "_complex" return Naming.type_prefix + real_type_name + "_complex"
def assignable_from(self, src_type): def assignable_from(self, src_type):
...@@ -1638,7 +1669,12 @@ class CFuncTypeArg(object): ...@@ -1638,7 +1669,12 @@ class CFuncTypeArg(object):
# cname string # cname string
# type PyrexType # type PyrexType
# pos source file position # pos source file position
# FIXME: is this the right setup? should None be allowed here?
not_none = False
or_none = False
accept_none = True
def __init__(self, name, type, pos, cname=None): def __init__(self, name, type, pos, cname=None):
self.name = name self.name = name
if cname is not None: if cname is not None:
...@@ -1647,7 +1683,6 @@ class CFuncTypeArg(object): ...@@ -1647,7 +1683,6 @@ class CFuncTypeArg(object):
self.cname = Naming.var_prefix + name self.cname = Naming.var_prefix + name
self.type = type self.type = type
self.pos = pos self.pos = pos
self.not_none = False
self.needs_type_test = False # TODO: should these defaults be set in analyse_types()? self.needs_type_test = False # TODO: should these defaults be set in analyse_types()?
def __repr__(self): def __repr__(self):
...@@ -1748,16 +1783,15 @@ class CStructOrUnionType(CType): ...@@ -1748,16 +1783,15 @@ class CStructOrUnionType(CType):
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex: if pyrex or for_display:
return self.base_declaration_code(self.name, entity_code) base_code = self.name
else: else:
if for_display: if self.typedef_flag:
base = self.name base_code = self.cname
elif self.typedef_flag:
base = self.cname
else: else:
base = "%s %s" % (self.kind, self.cname) base_code = "%s %s" % (self.kind, self.cname)
return self.base_declaration_code(public_decl(base, dll_linkage), entity_code) base_code = public_decl(base_code, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
def __eq__(self, other): def __eq__(self, other):
try: try:
...@@ -1847,20 +1881,24 @@ class CppClassType(CType): ...@@ -1847,20 +1881,24 @@ class CppClassType(CType):
specialized.namespace = self.namespace.specialize(values) specialized.namespace = self.namespace.specialize(values)
return specialized return specialized
def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if self.templates: if self.templates:
template_strings = [param.declaration_code('', for_display, pyrex) for param in self.templates] template_strings = [param.declaration_code('', for_display, None, pyrex)
templates = "<" + ",".join(template_strings) + ">" for param in self.templates]
templates = "<%s>" % ",".join(template_strings)
if templates[-2:] == ">>":
templates = templates[:-2] + "> >"
else: else:
templates = "" templates = ""
if for_display or pyrex: if pyrex or for_display:
name = self.name base_code = "%s%s" % (self.name, templates)
else: else:
base_code = "%s%s" % (self.cname, templates)
if self.namespace is not None: if self.namespace is not None:
name = "%s::%s" % (self.namespace.declaration_code(''), self.cname) base_code = "%s::%s" % (self.namespace.declaration_code(''), base_code)
else: base_code = public_decl(base_code, dll_linkage)
name = self.cname return self.base_declaration_code(base_code, entity_code)
return "%s%s %s" % (name, templates, entity_code)
def is_subclass(self, other_type): def is_subclass(self, other_type):
# TODO(danilo): Handle templates. # TODO(danilo): Handle templates.
...@@ -1899,7 +1937,8 @@ class TemplatePlaceholderType(CType): ...@@ -1899,7 +1937,8 @@ class TemplatePlaceholderType(CType):
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if entity_code: if entity_code:
return self.name + " " + entity_code return self.name + " " + entity_code
else: else:
...@@ -1952,14 +1991,15 @@ class CEnumType(CType): ...@@ -1952,14 +1991,15 @@ class CEnumType(CType):
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex: if pyrex or for_display:
return self.base_declaration_code(self.cname, entity_code) base_code = self.name
else: else:
if self.typedef_flag: if self.typedef_flag:
base = self.cname base_code = self.cname
else: else:
base = "enum %s" % self.cname base_code = "enum %s" % self.cname
return self.base_declaration_code(public_decl(base, dll_linkage), entity_code) base_code = public_decl(base_code, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
class CStringType(object): class CStringType(object):
...@@ -1968,8 +2008,8 @@ class CStringType(object): ...@@ -1968,8 +2008,8 @@ class CStringType(object):
is_string = 1 is_string = 1
is_unicode = 0 is_unicode = 0
to_py_function = "__Pyx_PyBytes_FromString" to_py_function = "PyBytes_FromString"
from_py_function = "__Pyx_PyBytes_AsString" from_py_function = "PyBytes_AsString"
exception_value = "NULL" exception_value = "NULL"
def literal_code(self, value): def literal_code(self, value):
...@@ -2056,61 +2096,70 @@ rank_to_type_name = ( ...@@ -2056,61 +2096,70 @@ rank_to_type_name = (
"short", # 1 "short", # 1
"int", # 2 "int", # 2
"long", # 3 "long", # 3
"Py_ssize_t", # 4 "PY_LONG_LONG", # 4
"size_t", # 5 "float", # 5
"PY_LONG_LONG", # 6 "double", # 6
"float", # 7 "long double", # 7
"double", # 8
"long double", # 9
) )
py_object_type = PyObjectType() RANK_INT = list(rank_to_type_name).index('int')
RANK_LONG = list(rank_to_type_name).index('long')
c_void_type = CVoidType() UNSIGNED = 0
c_void_ptr_type = CPtrType(c_void_type) SIGNED = 2
c_void_ptr_ptr_type = CPtrType(c_void_ptr_type)
c_uchar_type = CIntType(0, 0)
c_ushort_type = CIntType(1, 0)
c_uint_type = CUIntType(2, 0)
c_ulong_type = CULongType(3, 0)
c_ulonglong_type = CULongLongType(6, 0)
c_char_type = CIntType(0, 1)
c_short_type = CIntType(1, 1)
c_int_type = CIntType(2, 1)
c_long_type = CLongType(3, 1)
c_longlong_type = CLongLongType(6, 1)
c_bint_type = CBIntType(2, 1)
c_schar_type = CIntType(0, 2) py_object_type = PyObjectType()
c_sshort_type = CIntType(1, 2)
c_sint_type = CIntType(2, 2)
c_slong_type = CLongType(3, 2)
c_slonglong_type = CLongLongType(6, 2)
c_py_ssize_t_type = CPySSizeTType(4, 2)
c_size_t_type = CSizeTType(5, 0)
c_float_type = CFloatType(7, math_h_modifier='f')
c_double_type = CFloatType(8)
c_longdouble_type = CFloatType(9, math_h_modifier='l')
c_double_complex_type = CComplexType(c_double_type) c_void_type = CVoidType()
c_uchar_type = CIntType(0, UNSIGNED)
c_ushort_type = CIntType(1, UNSIGNED)
c_uint_type = CIntType(2, UNSIGNED)
c_ulong_type = CIntType(3, UNSIGNED)
c_ulonglong_type = CIntType(4, UNSIGNED)
c_char_type = CIntType(0)
c_short_type = CIntType(1)
c_int_type = CIntType(2)
c_long_type = CIntType(3)
c_longlong_type = CIntType(4)
c_schar_type = CIntType(0, SIGNED)
c_sshort_type = CIntType(1, SIGNED)
c_sint_type = CIntType(2, SIGNED)
c_slong_type = CIntType(3, SIGNED)
c_slonglong_type = CIntType(4, SIGNED)
c_float_type = CFloatType(5, math_h_modifier='f')
c_double_type = CFloatType(6)
c_longdouble_type = CFloatType(7, math_h_modifier='l')
c_float_complex_type = CComplexType(c_float_type)
c_double_complex_type = CComplexType(c_double_type)
c_longdouble_complex_type = CComplexType(c_longdouble_type)
c_anon_enum_type = CAnonEnumType(-1)
c_returncode_type = CReturnCodeType(RANK_INT)
c_bint_type = CBIntType(RANK_INT)
c_py_unicode_type = CPyUnicodeIntType(RANK_INT-0.5, UNSIGNED)
c_py_ssize_t_type = CPySSizeTType(RANK_LONG+0.5, SIGNED)
c_ssize_t_type = CSSizeTType(RANK_LONG+0.5, SIGNED)
c_size_t_type = CSizeTType(RANK_LONG+0.5, UNSIGNED)
c_null_ptr_type = CNullPtrType(c_void_type) c_null_ptr_type = CNullPtrType(c_void_type)
c_void_ptr_type = CPtrType(c_void_type)
c_void_ptr_ptr_type = CPtrType(c_void_ptr_type)
c_char_array_type = CCharArrayType(None) c_char_array_type = CCharArrayType(None)
c_char_ptr_type = CCharPtrType() c_char_ptr_type = CCharPtrType()
c_uchar_ptr_type = CUCharPtrType() c_uchar_ptr_type = CUCharPtrType()
c_utf8_char_array_type = CUTF8CharArrayType(None) c_utf8_char_array_type = CUTF8CharArrayType(None)
c_char_ptr_ptr_type = CPtrType(c_char_ptr_type) c_char_ptr_ptr_type = CPtrType(c_char_ptr_type)
c_int_ptr_type = CPtrType(c_int_type) c_int_ptr_type = CPtrType(c_int_type)
c_py_unicode_ptr_type = CPtrType(c_py_unicode_type)
c_py_ssize_t_ptr_type = CPtrType(c_py_ssize_t_type) c_py_ssize_t_ptr_type = CPtrType(c_py_ssize_t_type)
c_ssize_t_ptr_type = CPtrType(c_ssize_t_type)
c_size_t_ptr_type = CPtrType(c_size_t_type) c_size_t_ptr_type = CPtrType(c_size_t_type)
c_returncode_type = CIntType(2, 1, is_returncode = 1)
c_anon_enum_type = CAnonEnumType(-1, 1)
# the Py_buffer type is defined in Builtin.py # the Py_buffer type is defined in Builtin.py
c_py_buffer_type = CStructOrUnionType("Py_buffer", "struct", None, 1, "Py_buffer") c_py_buffer_type = CStructOrUnionType("Py_buffer", "struct", None, 1, "Py_buffer")
...@@ -2119,99 +2168,57 @@ c_py_buffer_ptr_type = CPtrType(c_py_buffer_type) ...@@ -2119,99 +2168,57 @@ c_py_buffer_ptr_type = CPtrType(c_py_buffer_type)
error_type = ErrorType() error_type = ErrorType()
unspecified_type = UnspecifiedType() unspecified_type = UnspecifiedType()
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, 6): c_ulonglong_type,
(1, 0): c_char_type,
(1, 1): c_short_type,
(1, 2): c_int_type,
(1, 3): c_long_type,
(1, 6): c_longlong_type,
(2, 0): c_schar_type,
(2, 1): c_sshort_type,
(2, 2): c_sint_type,
(2, 3): c_slong_type,
(2, 6): c_slonglong_type,
(0, 4): c_py_ssize_t_type,
(1, 4): c_py_ssize_t_type,
(2, 4): c_py_ssize_t_type,
(0, 5): c_size_t_type,
(1, 5): c_size_t_type,
(2, 5): c_size_t_type,
(1, 7): c_float_type,
(1, 8): c_double_type,
(1, 9): c_longdouble_type,
# In case we're mixing unsigned ints and floats...
(0, 7): c_float_type,
(0, 8): c_double_type,
(0, 9): c_longdouble_type,
}
modifiers_and_name_to_type = { modifiers_and_name_to_type = {
#(signed, longness, name) #(signed, longness, name) : type
(0, 0, "char"): c_uchar_type, (0, 0, "char"): c_uchar_type,
(1, 0, "char"): c_char_type,
(2, 0, "char"): c_schar_type,
(0, -1, "int"): c_ushort_type, (0, -1, "int"): c_ushort_type,
(0, 0, "int"): c_uint_type, (0, 0, "int"): c_uint_type,
(0, 1, "int"): c_ulong_type, (0, 1, "int"): c_ulong_type,
(0, 2, "int"): c_ulonglong_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, -1, "int"): c_short_type,
(1, 0, "int"): c_int_type, (1, 0, "int"): c_int_type,
(1, 1, "int"): c_long_type, (1, 1, "int"): c_long_type,
(1, 2, "int"): c_longlong_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,
(1, 0, "bint"): c_bint_type,
(2, 0, "char"): c_schar_type,
(2, -1, "int"): c_sshort_type, (2, -1, "int"): c_sshort_type,
(2, 0, "int"): c_sint_type, (2, 0, "int"): c_sint_type,
(2, 1, "int"): c_slong_type, (2, 1, "int"): c_slong_type,
(2, 2, "int"): c_slonglong_type, (2, 2, "int"): c_slonglong_type,
(2, 0, "Py_ssize_t"): c_py_ssize_t_type, (1, 0, "float"): c_float_type,
(0, 0, "size_t") : c_size_t_type, (1, 0, "double"): c_double_type,
(1, 1, "double"): c_longdouble_type,
(1, 0, "long"): c_long_type, (1, 0, "complex"): c_float_complex_type,
(1, 0, "short"): c_short_type, (1, 0, "floatcomplex"): c_float_complex_type,
(1, 0, "longlong"): c_longlong_type, (1, 0, "doublecomplex"): c_double_complex_type,
(1, 0, "bint"): c_bint_type, (1, 1, "doublecomplex"): c_longdouble_complex_type,
}
def is_promotion0(src_type, dst_type): #
if src_type.is_numeric and dst_type.is_numeric: (1, 0, "void"): c_void_type,
if src_type.is_int and dst_type.is_int:
if src_type.is_enum: (1, 0, "bint"): c_bint_type,
return True (0, 0, "Py_UNICODE"): c_py_unicode_type,
elif src_type.signed: (2, 0, "Py_ssize_t"): c_py_ssize_t_type,
return dst_type.signed and src_type.rank <= dst_type.rank (2, 0, "ssize_t") : c_ssize_t_type,
elif dst_type.signed: # and not src_type.signed (0, 0, "size_t") : c_size_t_type,
src_type.rank < dst_type.rank
else: (1, 0, "object"): py_object_type,
return src_type.rank <= dst_type.rank }
elif src_type.is_float and dst_type.is_float:
return src_type.rank <= dst_type.rank
else:
return False
else:
return False
def is_promotion(src_type, dst_type): def is_promotion(src_type, dst_type):
# It's hard to find a hard definition of promotion, but empirical # It's hard to find a hard definition of promotion, but empirical
# evidence suggests that the below is all that's allowed. # evidence suggests that the below is all that's allowed.
if src_type.is_numeric: if src_type.is_numeric:
if dst_type.same_as(c_int_type): if dst_type.same_as(c_int_type):
return src_type.is_enum or (src_type.is_int and (not src_type.signed) + src_type.rank < dst_type.rank) unsigned = (not src_type.signed)
return (src_type.is_enum or
(src_type.is_int and
unsigned + src_type.rank < dst_type.rank))
elif dst_type.same_as(c_double_type): elif dst_type.same_as(c_double_type):
return src_type.is_float and src_type.rank <= dst_type.rank return src_type.is_float and src_type.rank <= dst_type.rank
return False return False
...@@ -2275,8 +2282,11 @@ def best_match(args, functions, pos=None): ...@@ -2275,8 +2282,11 @@ def best_match(args, functions, pos=None):
if len(candidates) == 1: if len(candidates) == 1:
return candidates[0][0] return candidates[0][0]
elif len(candidates) == 0: elif len(candidates) == 0:
if len(errors) == 1 and pos is not None: if pos is not None:
error(pos, errors[0][1]) if len(errors) == 1:
error(pos, errors[0][1])
else:
error(pos, "no suitable method found")
return None return None
possibilities = [] possibilities = []
...@@ -2316,30 +2326,31 @@ def best_match(args, functions, pos=None): ...@@ -2316,30 +2326,31 @@ def best_match(args, functions, pos=None):
error(pos, "no suitable method found") error(pos, "no suitable method found")
return None return None
def widest_numeric_type(type1, type2): def widest_numeric_type(type1, type2):
# Given two numeric types, return the narrowest type # Given two numeric types, return the narrowest type
# encompassing both of them. # encompassing both of them.
if type1 == type2: if type1 == type2:
return type1 widest_type = type1
if type1.is_complex: elif type1.is_complex or type2.is_complex:
if type2.is_complex: def real_type(ntype):
return CComplexType(widest_numeric_type(type1.real_type, type2.real_type)) if ntype.is_complex:
else: return ntype.real_type
return CComplexType(widest_numeric_type(type1.real_type, type2)) return ntype
elif type2.is_complex: widest_type = CComplexType(
return CComplexType(widest_numeric_type(type1, type2.real_type)) widest_numeric_type(
if type1.is_enum and type2.is_enum: real_type(type1),
return c_int_type real_type(type2)))
elif type1 is type2: elif type1.is_enum and type2.is_enum:
return type1 widest_type = c_int_type
elif (type1.signed and type2.signed) or (not type1.signed and not type2.signed): elif type1.rank < type2.rank:
if type2.rank > type1.rank: widest_type = type2
return type2 elif type1.rank > type2.rank:
else: widest_type = type1
return type1 elif type1.signed < type2.signed:
widest_type = type1
else: else:
return sign_and_rank_to_type[min(type1.signed, type2.signed), max(type1.rank, type2.rank)] widest_type = type2
return widest_type
def spanning_type(type1, type2): def spanning_type(type1, type2):
# Return a type assignable from both type1 and type2. # Return a type assignable from both type1 and type2.
...@@ -2394,10 +2405,39 @@ def parse_basic_type(name): ...@@ -2394,10 +2405,39 @@ def parse_basic_type(name):
base = parse_basic_type(name[:-1]) base = parse_basic_type(name[:-1])
if base: if base:
return CPtrType(base) return CPtrType(base)
elif name.startswith('u'): #
return simple_c_type(0, 0, name[1:]) basic_type = simple_c_type(1, 0, name)
if basic_type:
return basic_type
#
signed = 1
longness = 0
if name == 'Py_UNICODE':
signed = 0
elif name == 'Py_ssize_t':
signed = 2
elif name == 'ssize_t':
signed = 2
elif name == 'size_t':
signed = 0
else: else:
return simple_c_type(1, 0, name) if name.startswith('u'):
name = name[1:]
signed = 0
elif (name.startswith('s') and
not name.startswith('short')):
name = name[1:]
signed = 2
longness = 0
while name.startswith('short'):
name = name.replace('short', '', 1).strip()
longness -= 1
while name.startswith('long'):
name = name.replace('long', '', 1).strip()
longness += 1
if longness != 0 and not name:
name = 'int'
return simple_c_type(signed, longness, name)
def c_array_type(base_type, size): def c_array_type(base_type, size):
# Construct a C array type. # Construct a C array type.
...@@ -2425,19 +2465,6 @@ def c_ref_type(base_type): ...@@ -2425,19 +2465,6 @@ def c_ref_type(base_type):
return error_type return error_type
else: else:
return CReferenceType(base_type) return CReferenceType(base_type)
def Node_to_type(node, env):
from ExprNodes import NameNode, AttributeNode, StringNode, error
if isinstance(node, StringNode):
node = NameNode(node.pos, name=node.value)
if isinstance(node, NameNode) and node.name in rank_to_type_name:
return simple_c_type(1, 0, node.name)
elif isinstance(node, (AttributeNode, NameNode)):
node.analyze_types(env)
if not node.entry.is_type:
pass
else:
error(node.pos, "Bad type")
def same_type(type1, type2): def same_type(type1, type2):
return type1.same_as(type2) return type1.same_as(type2)
...@@ -2460,23 +2487,17 @@ def typecast(to_type, from_type, expr_code): ...@@ -2460,23 +2487,17 @@ def typecast(to_type, from_type, expr_code):
type_conversion_predeclarations = """ type_conversion_predeclarations = """
/* Type Conversion Predeclarations */ /* Type Conversion Predeclarations */
#if PY_MAJOR_VERSION < 3 #define __Pyx_PyBytes_FromUString(s) PyBytes_FromString((char*)s)
#define __Pyx_PyBytes_FromString PyString_FromString #define __Pyx_PyBytes_AsUString(s) ((unsigned char*) PyBytes_AsString(s))
#define __Pyx_PyBytes_FromStringAndSize PyString_FromStringAndSize
#define __Pyx_PyBytes_AsString PyString_AsString
#else
#define __Pyx_PyBytes_FromString PyBytes_FromString
#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize
#define __Pyx_PyBytes_AsString PyBytes_AsString
#endif
#define __Pyx_PyBytes_FromUString(s) __Pyx_PyBytes_FromString((char*)s)
#define __Pyx_PyBytes_AsUString(s) ((unsigned char*) __Pyx_PyBytes_AsString(s))
#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False)) #define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x); static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x);
#ifdef Py_USING_UNICODE
static CYTHON_INLINE Py_UNICODE __Pyx_PyInt_AsPy_UNICODE(PyObject*);
#endif
static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject*); static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject*);
...@@ -2541,6 +2562,26 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) { ...@@ -2541,6 +2562,26 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) {
return res; return res;
} }
#ifdef Py_USING_UNICODE
static CYTHON_INLINE Py_UNICODE __Pyx_PyInt_AsPy_UNICODE(PyObject* x) {
long ival = __Pyx_PyInt_AsLong(x);
static long maxval = 0;
if (unlikely(!maxval))
maxval = (long)PyUnicode_GetMax();
if (unlikely(ival < 0)) {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_OverflowError,
"can't convert negative value to Py_UNICODE");
return (Py_UNICODE)-1;
} else if (unlikely(ival > maxval)) {
PyErr_SetString(PyExc_OverflowError,
"value too large to convert to Py_UNICODE");
return (Py_UNICODE)-1;
}
return (Py_UNICODE)ival;
}
#endif
static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
Py_ssize_t ival; Py_ssize_t ival;
PyObject* x = PyNumber_Index(b); PyObject* x = PyNumber_Index(b);
...@@ -2578,4 +2619,3 @@ static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject* x) { ...@@ -2578,4 +2619,3 @@ static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject* x) {
""" + type_conversion_functions """ + type_conversion_functions
...@@ -2,12 +2,9 @@ ...@@ -2,12 +2,9 @@
# Cython Scanner # Cython Scanner
# #
import sys
import os import os
import platform import platform
import stat
import sys
import codecs
from time import time
import cython import cython
cython.declare(EncodedString=object, string_prefixes=object, raw_prefixes=object, IDENT=object, cython.declare(EncodedString=object, string_prefixes=object, raw_prefixes=object, IDENT=object,
......
...@@ -210,6 +210,8 @@ class Scope(object): ...@@ -210,6 +210,8 @@ class Scope(object):
# is_py_class_scope boolean Is a Python class scope # is_py_class_scope boolean Is a Python class scope
# is_c_class_scope boolean Is an extension type scope # is_c_class_scope boolean Is an extension type scope
# is_closure_scope boolean # is_closure_scope boolean
# is_cpp_class_scope boolean Is a C++ class scope
# is_property_scope boolean Is a extension type property scope
# scope_prefix string Disambiguator for C names # scope_prefix string Disambiguator for C names
# in_cinclude boolean Suppress C declaration code # in_cinclude boolean Suppress C declaration code
# qualified_name string "modname" or "modname.classname" # qualified_name string "modname" or "modname.classname"
...@@ -225,6 +227,7 @@ class Scope(object): ...@@ -225,6 +227,7 @@ class Scope(object):
is_c_class_scope = 0 is_c_class_scope = 0
is_closure_scope = 0 is_closure_scope = 0
is_cpp_class_scope = 0 is_cpp_class_scope = 0
is_property_scope = 0
is_module_scope = 0 is_module_scope = 0
is_internal = 0 is_internal = 0
scope_prefix = "" scope_prefix = ""
...@@ -415,7 +418,7 @@ class Scope(object): ...@@ -415,7 +418,7 @@ class Scope(object):
error(pos, "C++ classes may only be extern") error(pos, "C++ classes may only be extern")
if cname is None: if cname is None:
cname = name cname = name
entry = self.lookup(name) entry = self.lookup_here(name)
if not entry: if not entry:
type = PyrexTypes.CppClassType( type = PyrexTypes.CppClassType(
name, scope, cname, base_classes, templates = templates) name, scope, cname, base_classes, templates = templates)
...@@ -439,7 +442,8 @@ class Scope(object): ...@@ -439,7 +442,8 @@ class Scope(object):
for base_class in base_classes: for base_class in base_classes:
declare_inherited_attributes(entry, base_class.base_classes) declare_inherited_attributes(entry, base_class.base_classes)
entry.type.scope.declare_inherited_cpp_attributes(base_class.scope) entry.type.scope.declare_inherited_cpp_attributes(base_class.scope)
declare_inherited_attributes(entry, base_classes) if entry.type.scope:
declare_inherited_attributes(entry, base_classes)
if self.is_cpp_class_scope: if self.is_cpp_class_scope:
entry.type.namespace = self.outer_scope.lookup(self.name).type entry.type.namespace = self.outer_scope.lookup(self.name).type
return entry return entry
...@@ -1664,6 +1668,8 @@ class PropertyScope(Scope): ...@@ -1664,6 +1668,8 @@ class PropertyScope(Scope):
# a property of an extension type. # a property of an extension type.
# #
# parent_type PyExtensionType The type to which the property belongs # parent_type PyExtensionType The type to which the property belongs
is_property_scope = 1
def declare_pyfunction(self, name, pos): def declare_pyfunction(self, name, pos):
# Add an entry for a method. # Add an entry for a method.
......
...@@ -117,6 +117,7 @@ class ResultRefNode(AtomicExprNode): ...@@ -117,6 +117,7 @@ class ResultRefNode(AtomicExprNode):
# must be set externally (usually a temp name). # must be set externally (usually a temp name).
subexprs = [] subexprs = []
lhs_of_first_assignment = False
def __init__(self, expression): def __init__(self, expression):
self.pos = expression.pos self.pos = expression.pos
...@@ -148,7 +149,8 @@ class ResultRefNode(AtomicExprNode): ...@@ -148,7 +149,8 @@ class ResultRefNode(AtomicExprNode):
def generate_assignment_code(self, rhs, code): def generate_assignment_code(self, rhs, code):
if self.type.is_pyobject: if self.type.is_pyobject:
rhs.make_owned_reference(code) rhs.make_owned_reference(code)
code.put_decref(self.result(), self.ctype()) if not self.lhs_of_first_assignment:
code.put_decref(self.result(), self.ctype())
code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype()))) code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
rhs.generate_post_assignment_code(code) rhs.generate_post_assignment_code(code)
rhs.free_temps(code) rhs.free_temps(code)
...@@ -250,3 +252,26 @@ class LetNode(Nodes.StatNode, LetNodeMixin): ...@@ -250,3 +252,26 @@ class LetNode(Nodes.StatNode, LetNodeMixin):
self.setup_temp_expr(code) self.setup_temp_expr(code)
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
self.teardown_temp_expr(code) self.teardown_temp_expr(code)
class TempResultFromStatNode(ExprNodes.ExprNode):
# An ExprNode wrapper around a StatNode that executes the StatNode
# body. Requires a ResultRefNode that it sets up to refer to its
# own temp result. The StatNode must assign a value to the result
# node, which then becomes the result of this node.
#
# This can only be used in/after type analysis.
#
subexprs = []
child_attrs = ['body']
def __init__(self, result_ref, body):
self.result_ref = result_ref
self.pos = body.pos
self.body = body
self.type = result_ref.type
self.is_temp = 1
def generate_result_code(self, code):
self.result_ref.result_code = self.result()
self.body.generate_execution_code(code)
...@@ -325,7 +325,10 @@ class EnvTransform(CythonTransform): ...@@ -325,7 +325,10 @@ class EnvTransform(CythonTransform):
def __call__(self, root): def __call__(self, root):
self.env_stack = [root.scope] self.env_stack = [root.scope]
return super(EnvTransform, self).__call__(root) return super(EnvTransform, self).__call__(root)
def current_env(self):
return self.env_stack[-1]
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
self.env_stack.append(node.local_scope) self.env_stack.append(node.local_scope)
self.visitchildren(node) self.visitchildren(node)
......
from cpython.unicode cimport Py_UNICODE
cdef extern from "Python.h": cdef extern from "Python.h":
ctypedef long long PY_LONG_LONG ctypedef long long PY_LONG_LONG
......
cdef extern from *: cdef extern from *:
ctypedef unsigned int Py_UNICODE
# Return true if the object o is a Unicode object or an instance # Return true if the object o is a Unicode object or an instance
# of a Unicode subtype. Changed in version 2.2: Allowed subtypes # of a Unicode subtype. Changed in version 2.2: Allowed subtypes
# to be accepted. # to be accepted.
...@@ -91,6 +89,13 @@ cdef extern from *: ...@@ -91,6 +89,13 @@ cdef extern from *:
# when u is NULL. # when u is NULL.
object PyUnicode_FromUnicode(Py_UNICODE *u, Py_ssize_t size) object PyUnicode_FromUnicode(Py_UNICODE *u, Py_ssize_t size)
# Create a Unicode Object from the given Unicode code point ordinal.
#
# The ordinal must be in range(0x10000) on narrow Python builds
# (UCS2), and range(0x110000) on wide builds (UCS4). A ValueError
# is raised in case it is not.
object PyUnicode_FromOrdinal(int ordinal)
# Return a read-only pointer to the Unicode object's internal # Return a read-only pointer to the Unicode object's internal
# Py_UNICODE buffer, NULL if unicode is not a Unicode object. # Py_UNICODE buffer, NULL if unicode is not a Unicode object.
Py_UNICODE* PyUnicode_AsUnicode(object o) except NULL Py_UNICODE* PyUnicode_AsUnicode(object o) except NULL
......
...@@ -3,39 +3,44 @@ from pair cimport pair ...@@ -3,39 +3,44 @@ from pair cimport pair
cdef extern from "<deque>" namespace "std": cdef extern from "<deque>" namespace "std":
cdef cppclass deque[T]: cdef cppclass deque[T]:
cppclass iterator: cppclass iterator:
T operator*() T& operator*()
iterator operator++() iterator operator++()
iterator operator--()
bint operator==(iterator) bint operator==(iterator)
bint operator!=(iterator) bint operator!=(iterator)
cppclass const_iterator(iterator): cppclass reverse_iterator:
pass T& operator*()
cppclass reverse_iterator(iterator): iterator operator++()
pass iterator operator--()
cppclass const_reverse_iterator(iterator): bint operator==(iterator)
pass bint operator!=(iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
# pass
deque() deque()
deque(deque&) deque(deque&)
deque(size_t, T& val = T()) deque(size_t)
#deque(input_iterator, input_iterator) deque(size_t, T&)
TYPE& operator[]( size_type index ) #deque[input_iterator](input_iterator, input_iterator)
const TYPE& operator[]( size_type index ) const T& operator[](size_t)
#deque& operator=(deque&) #deque& operator=(deque&)
bool operator==(deque&, deque&) bint operator==(deque&, deque&)
bool operator!=(deque&, deque&) bint operator!=(deque&, deque&)
bool operator<(deque&, deque&) bint operator<(deque&, deque&)
bool operator>(deque&, deque&) bint operator>(deque&, deque&)
bool operator<=(deque&, deque&) bint operator<=(deque&, deque&)
bool operator>=(deque&, deque&) bint operator>=(deque&, deque&)
void assign(size_t, TYPE&) void assign(size_t, T&)
void assign(input_iterator, input_iterator) void assign(input_iterator, input_iterator)
T& at(size_t) T& at(size_t)
T& back() T& back()
iterator begin() iterator begin()
const_iterator begin() #const_iterator begin()
void clear() void clear()
bool empty() bint empty()
iterator end() iterator end()
const_iterator end() #const_iterator end()
iterator erase(iterator) iterator erase(iterator)
iterator erase(iterator, iterator) iterator erase(iterator, iterator)
T& front() T& front()
...@@ -48,9 +53,10 @@ cdef extern from "<deque>" namespace "std": ...@@ -48,9 +53,10 @@ cdef extern from "<deque>" namespace "std":
void push_back(T&) void push_back(T&)
void push_front(T&) void push_front(T&)
reverse_iterator rbegin() reverse_iterator rbegin()
const_reverse_iterator rbegin() #const_reverse_iterator rbegin()
reverse_iterator rend() reverse_iterator rend()
const_reverse_iterator rend() #const_reverse_iterator rend()
void resize(size_t, T val = T()) void resize(size_t)
void resize(size_t, T&)
size_t size() size_t size()
void swap(deque&) void swap(deque&)
cdef extern from "<list>" namespace "std":
cdef cppclass list[T]:
cppclass iterator:
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
cppclass reverse_iterator:
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
# pass
list()
list(list&)
list(size_t, T&)
#list operator=(list&)
bint operator==(list&, list&)
bint operator!=(list&, list&)
bint operator<(list&, list&)
bint operator>(list&, list&)
bint operator<=(list&, list&)
bint operator>=(list&, list&)
void assign(size_t, T&)
T& back()
iterator begin()
#const_iterator begin()
bint empty()
iterator end()
#const_iterator end()
iterator erase(iterator)
iterator erase(iterator, iterator)
T& front()
iterator insert(iterator, T&)
void insert(iterator, size_t, T&)
size_t max_size()
void merge(list&)
#void merge(list&, BinPred)
void pop_back()
void pop_front()
void push_back(T&)
void push_front(T&)
reverse_iterator rbegin()
#const_reverse_iterator rbegin()
void remove(T&)
#void remove_if(UnPred)
reverse_iterator rend()
#const_reverse_iterator rend()
void resize(size_t, T&)
void reverse()
size_t size()
void sort()
#void sort(BinPred)
void splice(iterator, list&)
void splice(iterator, list&, iterator)
void splice(iterator, list&, iterator, iterator)
void swap(list&)
void unique()
#void unique(BinPred)
from pair cimport pair
cdef extern from "<map>" namespace "std":
cdef cppclass map[T, U]:
cppclass iterator:
pair[T,U]& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
cppclass reverse_iterator:
pair[T,U] operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
# pass
map()
map(map&)
#map(key_compare&)
U& operator[](T&)
#map& operator=(map&)
bint operator==(map&, map&)
bint operator!=(map&, map&)
bint operator<(map&, map&)
bint operator>(map&, map&)
bint operator<=(map&, map&)
bint operator>=(map&, map&)
U& at(T&)
iterator begin()
#const_iterator begin()
void clear()
size_t count(T&)
bint empty()
iterator end()
#const_iterator end()
pair[iterator, iterator] equal_range(T&)
#pair[const_iterator, const_iterator] equal_range(key_type&)
void erase(iterator)
void erase(iterator, iterator)
size_t erase(T&)
iterator find(T&)
#const_iterator find(key_type&)
pair[iterator, bint] insert(pair[T,U]) # XXX pair[T,U]&
iterator insert(iterator, pair[T,U]) # XXX pair[T,U]&
#void insert(input_iterator, input_iterator)
#key_compare key_comp()
iterator lower_bound(T&)
#const_iterator lower_bound(key_type&)
size_t max_size()
reverse_iterator rbegin()
#const_reverse_iterator rbegin()
reverse_iterator rend()
#const_reverse_iterator rend()
size_t size()
void swap(map&)
iterator upper_bound(T&)
#const_iterator upper_bound(key_type&)
#value_compare value_comp()
cdef extern from "pair.h": cdef extern from "<utility>" namespace "std":
cdef cppclass pair[T, U]: cdef cppclass pair[T, U]:
T first T first
U second U second
pair() pair()
pair(pair&)
pair(T&, U&) pair(T&, U&)
from pair cimport pair
cdef extern from "<queue>" namespace "std": cdef extern from "<queue>" namespace "std":
cdef cppclass queue[T]: cdef cppclass queue[T]:
queue() queue()
queue(queue&)
#queue(Container&) #queue(Container&)
T& back() T& back()
bool empty() bint empty()
T& front() T& front()
void pop() void pop()
void push(T&) void push(T&)
size_t size() size_t size()
cdef cppclass priority_queue[T]:
priority_queue()
priority_queue(priority_queue&)
#priority_queue(Container&)
bint empty()
void pop()
void push(T&)
size_t size()
T& top()
...@@ -5,51 +5,56 @@ cdef extern from "<set>" namespace "std": ...@@ -5,51 +5,56 @@ cdef extern from "<set>" namespace "std":
cppclass iterator: cppclass iterator:
T operator*() T operator*()
iterator operator++() iterator operator++()
iterator operator--()
bint operator==(iterator) bint operator==(iterator)
bint operator!=(iterator) bint operator!=(iterator)
cppclass const_iterator(iterator): cppclass reverse_iterator:
pass T operator*()
cppclass reverse_iterator(iterator): iterator operator++()
pass iterator operator--()
cppclass const_reverse_iterator(iterator): bint operator==(iterator)
pass bint operator!=(iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
# pass
set() set()
set(set&) set(set&)
#set set(key_compare&) #set(key_compare&)
#set& operator=(set&) #set& operator=(set&)
bool operator==(set&, set&) bint operator==(set&, set&)
bool operator!=(set&, set&) bint operator!=(set&, set&)
bool operator<(set&, set&) bint operator<(set&, set&)
bool operator>(set&, set&) bint operator>(set&, set&)
bool operator<=(set&, set&) bint operator<=(set&, set&)
bool operator>=(set&, set&) bint operator>=(set&, set&)
iterator begin() iterator begin()
const_iterator begin() #const_iterator begin()
void clear() void clear()
#size_t count(key_type&) size_t count(T&)
bool empty() bint empty()
iterator end() iterator end()
const_iterator end() #const_iterator end()
#pair[iterator, iterator] equal_range(key_type&) pair[iterator, iterator] equal_range(T&)
#pair[const_iterator, const_iterator] equal_range(key_type&) #pair[const_iterator, const_iterator] equal_range(T&)
void erase(iterator) void erase(iterator)
void erase(iterator, iterator) void erase(iterator, iterator)
#size_t erase(key_type&) size_t erase(T&)
#iterator find(key_type&) iterator find(T&)
#const_iterator find(key_type&) #const_iterator find(T&)
#pair[iterator, bool] insert(T&) pair[iterator, bint] insert(T&)
iterator insert(iterator, T&) iterator insert(iterator, T&)
#void insert(input_iterator, input_iterator) #void insert(input_iterator, input_iterator)
#key_compare key_comp() #key_compare key_comp()
#iterator lower_bound(key_type&) iterator lower_bound(T&)
#const_iterator lower_bound(key_type&) #const_iterator lower_bound(T&)
size_t max_size() size_t max_size()
reverse_iterator rbegin() reverse_iterator rbegin()
const_reverse_iterator rbegin() #const_reverse_iterator rbegin()
reverse_iterator rend() reverse_iterator rend()
const_reverse_iterator rend() #const_reverse_iterator rend()
size_t size() size_t size()
void swap(set&) void swap(set&)
#iterator upper_bound(key_type&) iterator upper_bound(T&)
#const_iterator upper_bound(key_type&) #const_iterator upper_bound(T&)
#value_compare value_comp() #value_compare value_comp()
from pair cimport pair cdef extern from "<stack>" namespace "std":
cdef cppclass stack[T]:
cdef extern from "<list>" namespace "std": stack()
cdef cppclass list[T]: stack(stack&)
cppclass iterator: #stack(Container&)
T operator*() bint empty()
iterator operator++() void pop()
bint operator==(iterator) void push(T&)
bint operator!=(iterator)
cppclass const_iterator(iterator):
pass
cppclass reverse_iterator(iterator):
pass
cppclass const_reverse_iterator(iterator):
pass
list()
list(list&)
list(size_t, T&)
#list operator=(list&)
bool operator==(list&, list&)
bool operator!=(list&, list&)
bool operator<(list&, list&)
bool operator>(list&, list&)
bool operator<=(list&, list&)
bool operator>=(list&, list&)
void assign(size_t, T&)
T& back()
iterator begin()
const_iterator begin()
bool empty()
iterator end()
const_iterator end()
iterator erase(iterator)
iterator erase(iterator, iterator)
T& front()
iterator insert(iterator, T&)
void insert(iterator, size_t, T&)
size_t max_size()
void merge(list&)
#voide merge(list&, BinPred)
void pop_back()
void pop_front()
void push_back(T&)
void push_front(T&)
reverse_iterator rbegin()
const_reverse_iterator rbegin()
void remove(T&)
#void remove_if(UnPred)
reverse_iterator rend()
const_reverse_iterator rend()
void resize(size_t, T&)
void reverse()
size_t size() size_t size()
void sort() T& top()
#void sort(BinPred)
void splice(iterator, list&)
void splice(iterator, list&, iterator)
void splice(iterator, list&, iterator, iterator)
void swap(list&)
void unique()
#void unique(BinPred)
from pair cimport pair
cdef extern from "<vector>" namespace "std": cdef extern from "<vector>" namespace "std":
cdef cppclass vector[T]: cdef cppclass vector[T]:
cppclass iterator: cppclass iterator:
T operator*() T& operator*()
iterator operator++() iterator operator++()
iterator operator--()
bint operator==(iterator) bint operator==(iterator)
bint operator!=(iterator) bint operator!=(iterator)
cppclass const_iterator(iterator): cppclass reverse_iterator:
pass T& operator*()
cppclass reverse_iterator(iterator): iterator operator++()
pass iterator operator--()
cppclass const_reverse_iterator(iterator): bint operator==(iterator)
pass bint operator!=(iterator)
#cppclass input_iterator(iterator): #cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
# pass # pass
vector() vector()
#vector(vector&) vector(vector&)
#vector(size_t, T&) vector(size_t)
vector(size_t, T&)
#vector[input_iterator](input_iterator, input_iterator) #vector[input_iterator](input_iterator, input_iterator)
T& operator[](size_t) T& operator[](size_t)
#vector& operator=(vector&) #vector& operator=(vector&)
bool operator==(vector&, vector&) bint operator==(vector&, vector&)
bool operator!=(vector&, vector&) bint operator!=(vector&, vector&)
bool operator<(vector&, vector&) bint operator<(vector&, vector&)
bool operator>(vector&, vector&) bint operator>(vector&, vector&)
bool operator<=(vector&, vector&) bint operator<=(vector&, vector&)
bool operator>=(vector&, vector&) bint operator>=(vector&, vector&)
void assign(size_t, T&) void assign(size_t, T&)
#void assign(input_iterator, input_iterator) #void assign[input_iterator](input_iterator, input_iterator)
T& at(size_t) T& at(size_t)
T& back() T& back()
iterator begin() iterator begin()
const_iterator begin() #const_iterator begin()
size_t capacity() size_t capacity()
void clear() void clear()
bool empty() bint empty()
iterator end() iterator end()
const_iterator end() #const_iterator end()
iterator erase(iterator) iterator erase(iterator)
iterator erase(iterator, iterator) iterator erase(iterator, iterator)
T& front() T& front()
...@@ -48,10 +50,11 @@ cdef extern from "<vector>" namespace "std": ...@@ -48,10 +50,11 @@ cdef extern from "<vector>" namespace "std":
void pop_back() void pop_back()
void push_back(T&) void push_back(T&)
reverse_iterator rbegin() reverse_iterator rbegin()
const_reverse_iterator rbegin() #const_reverse_iterator rbegin()
reverse_iterator rend() reverse_iterator rend()
const_reverse_iterator rend() #const_reverse_iterator rend()
void reserve(size_t) void reserve(size_t)
void resize(size_t, T) void resize(size_t)
void resize(size_t, T&)
size_t size() size_t size()
void swap(vector&) void swap(vector&)
...@@ -481,8 +481,8 @@ cdef extern from "numpy/arrayobject.h": ...@@ -481,8 +481,8 @@ cdef extern from "numpy/arrayobject.h":
bint PyArray_FROM_OT(object m, int type) bint PyArray_FROM_OT(object m, int type)
bint PyArray_FROM_OTF(object m, int type, int flags) bint PyArray_FROM_OTF(object m, int type, int flags)
object PyArray_FROMANY(object m, int type, int min, int max, int flags) object PyArray_FROMANY(object m, int type, int min, int max, int flags)
bint PyArray_ZEROS(ndarray m, dims, int type, int fortran) bint PyArray_ZEROS(ndarray m, npy_intp* dims, int type, int fortran)
object PyArray_EMPTY(object m, dims, int type, int fortran) object PyArray_EMPTY(object m, npy_intp* dims, int type, int fortran)
void PyArray_FILLWBYTE(object, int val) void PyArray_FILLWBYTE(object, int val)
npy_intp PyArray_REFCOUNT(object) npy_intp PyArray_REFCOUNT(object)
object PyArray_ContiguousFromAny(op, int, int min_depth, int max_depth) object PyArray_ContiguousFromAny(op, int, int min_depth, int max_depth)
......
...@@ -153,40 +153,50 @@ class typedef(CythonType): ...@@ -153,40 +153,50 @@ class typedef(CythonType):
py_float = float
py_int = int py_int = int
try: try:
py_long = long py_long = long
except NameError: # Py3 except NameError: # Py3
py_long = int py_long = int
py_float = float
py_complex = complex
try: try:
# Python 3 # Python 3
from builtins import set from builtins import set, frozenset
except ImportError: except ImportError:
try: try:
# Python 2.4+ # Python 2.4+
from __builtin__ import set from __builtin__ import set, frozenset
except ImportError: except ImportError:
# Py 2.3 # Py 2.3
from sets import Set as set from sets import Set as set, ImmutableSet as frozenset
# Predefined types # Predefined types
int_types = ['char', 'short', 'int', 'long', 'longlong', 'Py_ssize_t'] int_types = ['char', 'short', 'Py_UNICODE', 'int', 'long', 'longlong', 'Py_ssize_t', 'size_t']
float_types = ['double', 'float'] float_types = ['longdouble', 'double', 'float']
complex_types = ['longdoublecomplex', 'doublecomplex', 'floatcomplex', 'complex']
other_types = ['bint', 'void'] other_types = ['bint', 'void']
gs = globals() gs = globals()
for name in int_types: for name in int_types:
gs[name] = typedef(py_int) gs[name] = typedef(py_int)
gs['u'+name] = typedef(py_int) if name != 'Py_UNICODE' and not name.endswith('size_t'):
gs['u'+name] = typedef(py_int)
gs['s'+name] = typedef(py_int)
double = float = typedef(py_float) for name in float_types:
gs[name] = typedef(py_float)
for name in complex_types:
gs[name] = typedef(py_complex)
bint = typedef(bool) bint = typedef(bool)
void = typedef(int) void = typedef(int)
for t in int_types + float_types + other_types: for t in int_types + float_types + complex_types + other_types:
for i in range(1, 4): for i in range(1, 4):
gs["%s_%s" % ('p'*i, t)] = globals()[t]._pointer(i) gs["%s_%s" % ('p'*i, t)] = globals()[t]._pointer(i)
......
...@@ -45,6 +45,27 @@ def file_newer_than(path, time): ...@@ -45,6 +45,27 @@ def file_newer_than(path, time):
ftime = modification_time(path) ftime = modification_time(path)
return ftime > time return ftime > time
def path_exists(path):
# try on the filesystem first
if os.path.exists(path):
return True
# figure out if a PEP 302 loader is around
try:
loader = __loader__
# XXX the code below assumes as 'zipimport.zipimporter' instance
# XXX should be easy to generalize, but too lazy right now to write it
if path.startswith(loader.archive):
nrmpath = os.path.normpath(path)
arcname = nrmpath[len(loader.archive)+1:]
try:
loader.get_data(arcname)
return True
except IOError:
return False
except NameError:
pass
return False
# support for source file encoding detection # support for source file encoding detection
def encode_filename(filename): def encode_filename(filename):
...@@ -109,18 +130,31 @@ class NormalisedNewlineStream(object): ...@@ -109,18 +130,31 @@ class NormalisedNewlineStream(object):
data = self._read(0x1000) data = self._read(0x1000)
return u''.join(content).split(u'\n') return u''.join(content).split(u'\n')
try: io = None
from io import open as io_open if sys.version_info >= (2,6):
except ImportError: try:
io_open = None import io
except ImportError:
pass
def open_source_file(source_filename, mode="r", def open_source_file(source_filename, mode="r",
encoding=None, error_handling=None, encoding=None, error_handling=None,
require_normalised_newlines=True): require_normalised_newlines=True):
if encoding is None: if encoding is None:
encoding = detect_file_encoding(source_filename) encoding = detect_file_encoding(source_filename)
if io_open is not None: #
return io_open(source_filename, mode=mode, try:
loader = __loader__
if source_filename.startswith(loader.archive):
return open_source_from_loader(
loader, source_filename,
encoding, error_handling,
require_normalised_newlines)
except (NameError, AttributeError):
pass
#
if io is not None:
return io.open(source_filename, mode=mode,
encoding=encoding, errors=error_handling) encoding=encoding, errors=error_handling)
else: else:
# codecs module doesn't have universal newline support # codecs module doesn't have universal newline support
...@@ -130,6 +164,28 @@ def open_source_file(source_filename, mode="r", ...@@ -130,6 +164,28 @@ def open_source_file(source_filename, mode="r",
stream = NormalisedNewlineStream(stream) stream = NormalisedNewlineStream(stream)
return stream return stream
def open_source_from_loader(loader,
source_filename,
encoding=None, error_handling=None,
require_normalised_newlines=True):
nrmpath = os.path.normpath(source_filename)
arcname = nrmpath[len(loader.archive)+1:]
data = loader.get_data(arcname)
if io is not None:
return io.TextIOWrapper(io.BytesIO(data),
encoding=encoding,
errors=error_handling)
else:
try:
import cStringIO as StringIO
except ImportError:
import StringIO
reader = codecs.getreader(encoding)
stream = reader(StringIO.StringIO(data))
if require_normalised_newlines:
stream = NormalisedNewlineStream(stream)
return stream
def str_to_number(value): def str_to_number(value):
# note: this expects a string as input that was accepted by the # note: this expects a string as input that was accepted by the
# parser already # parser already
......
...@@ -178,7 +178,10 @@ class TestBuilder(object): ...@@ -178,7 +178,10 @@ class TestBuilder(object):
def build_tests(self, test_class, path, workdir, module, expect_errors): def build_tests(self, test_class, path, workdir, module, expect_errors):
if expect_errors: if expect_errors:
languages = self.languages[:1] if 'cpp' in module and 'cpp' in self.languages:
languages = ['cpp']
else:
languages = self.languages[:1]
else: else:
languages = self.languages languages = self.languages
if 'cpp' in module and 'c' in languages: if 'cpp' in module and 'c' in languages:
...@@ -752,6 +755,9 @@ if __name__ == '__main__': ...@@ -752,6 +755,9 @@ if __name__ == '__main__':
parser.add_option("-C", "--coverage", dest="coverage", parser.add_option("-C", "--coverage", dest="coverage",
action="store_true", default=False, action="store_true", default=False,
help="collect source coverage data for the Compiler") help="collect source coverage data for the Compiler")
parser.add_option("--coverage-xml", dest="coverage_xml",
action="store_true", default=False,
help="collect source coverage data for the Compiler in XML format")
parser.add_option("-A", "--annotate", dest="annotate_source", parser.add_option("-A", "--annotate", dest="annotate_source",
action="store_true", default=True, action="store_true", default=True,
help="generate annotated HTML versions of the test source files") help="generate annotated HTML versions of the test source files")
...@@ -799,11 +805,12 @@ if __name__ == '__main__': ...@@ -799,11 +805,12 @@ if __name__ == '__main__':
WITH_CYTHON = options.with_cython WITH_CYTHON = options.with_cython
if options.coverage: if options.coverage or options.coverage_xml:
if not WITH_CYTHON: if not WITH_CYTHON:
options.coverage = False options.coverage = options.coverage_xml = False
else: else:
import coverage from coverage import coverage as _coverage
coverage = _coverage(branch=True)
coverage.erase() coverage.erase()
coverage.start() coverage.start()
...@@ -924,14 +931,17 @@ if __name__ == '__main__': ...@@ -924,14 +931,17 @@ if __name__ == '__main__':
result = test_runner.run(test_suite) result = test_runner.run(test_suite)
if options.coverage: if options.coverage or options.coverage_xml:
coverage.stop() coverage.stop()
ignored_modules = ('Options', 'Version', 'DebugFlags', 'CmdLine') ignored_modules = ('Options', 'Version', 'DebugFlags', 'CmdLine')
modules = [ module for name, module in sys.modules.items() modules = [ module for name, module in sys.modules.items()
if module is not None and if module is not None and
name.startswith('Cython.Compiler.') and name.startswith('Cython.Compiler.') and
name[len('Cython.Compiler.'):] not in ignored_modules ] name[len('Cython.Compiler.'):] not in ignored_modules ]
coverage.report(modules, show_missing=0) if options.coverage:
coverage.report(modules, show_missing=0)
if options.coverage_xml:
coverage.xml_report(modules, outfile="coverage-report.xml")
if missing_dep_excluder.tests_missing_deps: if missing_dep_excluder.tests_missing_deps:
sys.stderr.write("Following tests excluded because of missing dependencies on your system:\n") sys.stderr.write("Following tests excluded because of missing dependencies on your system:\n")
......
...@@ -85,7 +85,7 @@ else: ...@@ -85,7 +85,7 @@ else:
else: else:
scripts = ["cython.py"] scripts = ["cython.py"]
def compile_cython_modules(): def compile_cython_modules(profile=False):
source_root = os.path.abspath(os.path.dirname(__file__)) source_root = os.path.abspath(os.path.dirname(__file__))
compiled_modules = ["Cython.Plex.Scanners", compiled_modules = ["Cython.Plex.Scanners",
"Cython.Compiler.Scanning", "Cython.Compiler.Scanning",
...@@ -116,6 +116,10 @@ def compile_cython_modules(): ...@@ -116,6 +116,10 @@ def compile_cython_modules():
del sys.modules[module] del sys.modules[module]
sys.path.insert(0, os.path.join(source_root, self.build_lib)) sys.path.insert(0, os.path.join(source_root, self.build_lib))
if profile:
from Cython.Compiler.Options import directive_defaults
directive_defaults['profile'] = True
print("Enabled profiling for the Cython binary modules")
build_ext_orig.build_extensions(self) build_ext_orig.build_extensions(self)
setup_args['ext_modules'] = extensions setup_args['ext_modules'] = extensions
...@@ -132,6 +136,10 @@ def compile_cython_modules(): ...@@ -132,6 +136,10 @@ def compile_cython_modules():
print("Compilation of '%s' failed" % ext.sources[0]) print("Compilation of '%s' failed" % ext.sources[0])
from Cython.Compiler.Main import compile from Cython.Compiler.Main import compile
from Cython import Utils from Cython import Utils
if profile:
from Cython.Compiler.Options import directive_defaults
directive_defaults['profile'] = True
print("Enabled profiling for the Cython binary modules")
source_root = os.path.dirname(__file__) source_root = os.path.dirname(__file__)
for module in compiled_modules: for module in compiled_modules:
source_file = os.path.join(source_root, *module.split('.')) source_file = os.path.join(source_root, *module.split('.'))
...@@ -159,10 +167,14 @@ def compile_cython_modules(): ...@@ -159,10 +167,14 @@ def compile_cython_modules():
print("ERROR: %s" % sys.exc_info()[1]) print("ERROR: %s" % sys.exc_info()[1])
print("Extension module compilation failed, using plain Python implementation") print("Extension module compilation failed, using plain Python implementation")
cython_profile = '--cython-profile' in sys.argv
if cython_profile:
sys.argv.remove('--cython-profile')
try: try:
sys.argv.remove("--no-cython-compile") sys.argv.remove("--no-cython-compile")
except ValueError: except ValueError:
compile_cython_modules() compile_cython_modules(cython_profile)
setup_args.update(setuptools_extra_args) setup_args.update(setuptools_extra_args)
......
#ifdef __cplusplus
extern "C" {
#endif
extern DL_EXPORT(int) f1(void);
extern DL_EXPORT(int) __cdecl f2(void);
extern DL_EXPORT(int) __stdcall f3(void);
extern DL_EXPORT(int) __fastcall f4(void);
#ifdef __cplusplus
}
#endif
int f1(void) {return 0;}
int __cdecl f2(void) {return 0;}
int __stdcall f3(void) {return 0;}
int __fastcall f4(void) {return 0;}
#ifdef __cplusplus
extern "C" {
#endif
extern int (*p1)(void);
extern int (__cdecl *p2)(void);
extern int (__stdcall *p3)(void);
extern int (__fastcall *p4)(void);
#ifdef __cplusplus
}
#endif
int (*p1)(void);
int (__cdecl *p2)(void);
int (__stdcall *p3)(void);
int (__fastcall *p4)(void);
cdef extern from "callingconvention.h":
pass
cdef extern int f1() cdef extern int f1()
cdef extern int __cdecl f2() cdef extern int __cdecl f2()
......
#ifdef __cplusplus
extern "C" {
#endif
extern char *cp;
extern char *cpa[5];
extern int (*ifnpa[5])(void);
extern char *(*cpfnpa[5])(void);
extern int (*ifnp)(void);
extern int (*iap)[5];
#ifdef __cplusplus
}
#endif
char *cp;
char *cpa[5];
int (*ifnpa[5])(void);
char *(*cpfnpa[5])(void);
int (*ifnp)(void);
int (*iap)[5];
#ifdef __cplusplus
extern "C" {
#endif
extern DL_EXPORT(int) ifn(void);
extern DL_EXPORT(char *) cpfn(void);
extern DL_EXPORT(int) fnargfn(int (void));
extern DL_EXPORT(int) (*iapfn(void))[5];
extern DL_EXPORT(char *)(*cpapfn(void))[5];
#ifdef __cplusplus
}
#endif
int ifn(void) {return 0;}
char *cpfn(void) {return 0;}
int fnargfn(int f(void)) {return 0;}
#ifdef __cplusplus
extern "C" {
#endif
extern int ia[];
extern int iaa[][3];
extern DL_EXPORT(int) a(int[][3], int[][3][5]);
#ifdef __cplusplus
}
#endif
int ia[1];
int iaa[1][3];
int a(int a[][3], int b[][3][5]) {return 0;}
cdef extern from "declarations.h":
pass
cdef extern char *cp cdef extern char *cp
cdef extern char *cpa[5] cdef extern char *cpa[5]
cdef extern int (*ifnpa[5])() cdef extern int (*ifnpa[5])()
......
#ifdef __cplusplus
extern "C" {
#endif
extern DL_EXPORT(int) spam(void);
extern DL_EXPORT(void) grail(void);
extern DL_EXPORT(char *)tomato(void);
#ifdef __cplusplus
}
#endif
int spam(void) {return 0;}
void grail(void) {return;}
char *tomato(void) {return 0;}
cdef extern from "excvalcheck.h":
pass
cdef extern int spam() except -1 cdef extern int spam() except -1
cdef extern void grail() except * cdef extern void grail() except *
cdef extern char *tomato() except? NULL cdef extern char *tomato() except? NULL
......
cimport libc
cimport libc.stdio
cimport libc.errno
cimport libc.float
cimport libc.limits
cimport libc.locale
cimport libc.signal
cimport libc.stddef
cimport libc.stdint
cimport libc.stdio
cimport libc.stdlib
cimport libc.string
from libc cimport errno
from libc cimport float
from libc cimport limits
from libc cimport locale
from libc cimport signal
from libc cimport stddef
from libc cimport stdint
from libc cimport stdio
from libc cimport stdlib
from libc cimport string
from libc.errno cimport * from libc.errno cimport *
from libc.float cimport * from libc.float cimport *
from libc.limits cimport * from libc.limits cimport *
...@@ -8,3 +33,7 @@ from libc.stdint cimport * ...@@ -8,3 +33,7 @@ from libc.stdint cimport *
from libc.stdio cimport * from libc.stdio cimport *
from libc.stdlib cimport * from libc.stdlib cimport *
from libc.string cimport * from libc.string cimport *
libc.stdio.printf("hello %s\n", b"world")
stdio.printf("hello %s\n", b"world")
printf("hello %s\n", b"world")
cimport libcpp
cimport libcpp.deque
cimport libcpp.list
cimport libcpp.map
cimport libcpp.pair
cimport libcpp.queue
cimport libcpp.set
cimport libcpp.stack
cimport libcpp.vector
from libcpp.deque cimport *
from libcpp.list cimport *
from libcpp.map cimport *
from libcpp.pair cimport *
from libcpp.queue cimport *
from libcpp.set cimport *
from libcpp.stack cimport *
from libcpp.vector cimport *
cdef libcpp.deque.deque[int] d1 = deque[int]()
cdef libcpp.list.list[int] l1 = list[int]()
cdef libcpp.map.map[int,int] m1 = map[int,int]()
cdef libcpp.pair.pair[int,int] p1 = pair[int,int](1,2)
cdef libcpp.queue.queue[int] q1 = queue[int]()
cdef libcpp.set.set[int] s1 = set[int]()
cdef libcpp.stack.stack[int] t1 = stack[int]()
cdef libcpp.vector.vector[int] v1 = vector[int]()
cdef deque[int].iterator id1 = d1.begin()
cdef deque[int].iterator id2 = d1.end()
cdef deque[int].reverse_iterator rid1 = d1.rbegin()
cdef deque[int].reverse_iterator rid2 = d1.rend()
cdef list[int].iterator il1 = l1.begin()
cdef list[int].iterator il2 = l1.end()
cdef list[int].reverse_iterator ril1 = l1.rbegin()
cdef list[int].reverse_iterator ril2 = l1.rend()
cdef map[int,int].iterator im1 = m1.begin()
cdef map[int,int].iterator im2 = m1.end()
cdef map[int,int].reverse_iterator rim1 = m1.rbegin()
cdef map[int,int].reverse_iterator rim2 = m1.rend()
cdef pair[map[int,int].iterator, bint] pimb = m1.insert(p1)
cdef set[int].iterator is1 = s1.begin()
cdef set[int].iterator is2 = s1.end()
cdef set[int].reverse_iterator ris1 = s1.rbegin()
cdef set[int].reverse_iterator ris2 = s1.rend()
cdef pair[set[int].iterator, bint] pisb = s1.insert(4)
cdef vector[int].iterator iv1 = v1.begin()
cdef vector[int].iterator iv2 = v1.end()
cdef vector[int].reverse_iterator riv1 = v1.rbegin()
cdef vector[int].reverse_iterator riv2 = v1.rend()
void e1(void); #ifdef __cplusplus
void *e2(void); extern "C" {
#endif
extern DL_EXPORT(void) e1(void);
extern DL_EXPORT(void *) e2(void);
#ifdef __cplusplus
}
#endif
void e1(void) {return;}
void *e2(void) {return 0;}
#ifdef __cplusplus
extern "C" {
#endif
extern DL_EXPORT(PyObject *) g(PyObject*);
extern DL_EXPORT(void) g2(PyObject*);
#ifdef __cplusplus
}
#endif
PyObject *g(PyObject* o) {return 0;}
void g2(PyObject* o) {return;}
cdef class C: cdef class C:
def __cinit__(self):
"This is an unusable docstring."
def __init__(self): def __init__(self):
"This is an unusable docstring." "This is an unusable docstring."
def __dealloc__(self):
"This is an unusable docstring."
def __richcmp__(self, other, int op):
"This is an unusable docstring."
def __nonzero__(self):
"This is an unusable docstring."
return False
def __contains__(self, other):
"This is an unusable docstring."
property foo: property foo:
def __get__(self): def __get__(self):
"So is this." "So is this."
def __set__(self, x): def __set__(self, x):
"And here is another one." "And here is another one."
def __add__(self, other):
"usable docstring"
def __iter__(self):
"usable docstring"
return False
def __next__(self):
"usable docstring"
return False
cdef extern from *:
cdef cppclass Foo:
Foo()
Foo(int)
new Foo(1, 2)
_ERRORS = u"""
6:7: no suitable method found
"""
def eggs(int x not None, y not None): def eggs(int x not None, char* y not None):
pass pass
_ERRORS = u""" _ERRORS = u"""
1:0: Only extension type arguments can have 'not None' 1: 9: Only Python type arguments can have 'not None'
1:0: Only extension type arguments can have 'not None' 1:25: Only Python type arguments can have 'not None'
""" """
...@@ -4,12 +4,14 @@ cdef int cx = "test" # fails ...@@ -4,12 +4,14 @@ cdef int cx = "test" # fails
cdef int x1 = "\xFF" # works cdef int x1 = "\xFF" # works
cdef int x2 = "\u0FFF" # fails cdef int x2 = "\u0FFF" # fails
cdef int x3 = u"\xFF" # fails
cdef Py_UNICODE u1 = u"\xFF" # works
cdef int u3 = u"\xFF" # fails
_ERRORS = u"""
2:14: Only single-character strings can be coerced into ints. _ERRORS = """
3:14: Only single-character strings can be coerced into ints. 2:14: Only single-character string literals can be coerced into ints.
6:15: Only single-character strings can be coerced into ints. 3:14: Only single-character string literals can be coerced into ints.
7:14: Unicode objects do not support coercion to C types. 6:15: Only single-character string literals can be coerced into ints.
9:14: Unicode literals do not support coercion to C types other than Py_UNICODE.
""" """
# -*- coding: iso-8859-1 -*-
cdef Py_UNICODE char_ASCII = u'A'
cdef Py_UNICODE char_KLINGON = u'\uF8D2'
def char_too_long_ASCII():
cdef Py_UNICODE c = u'AB'
def char_too_long_Unicode():
cdef Py_UNICODE c = u'A\uF8D2'
def char_too_long_bytes():
cdef Py_UNICODE c = b'AB'
def char_too_long_latin1():
cdef Py_UNICODE char_bytes_latin1 = b'\xf6'
_ERRORS = """
7:24: Only single-character Unicode string literals can be coerced into Py_UNICODE.
10:24: Only single-character Unicode string literals can be coerced into Py_UNICODE.
13:24: Only single-character string literals can be coerced into ints.
16:40: Bytes literals cannot coerce to Py_UNICODE, use a unicode literal instead.
"""
...@@ -50,7 +50,7 @@ cdef list l_f2 = b1 ...@@ -50,7 +50,7 @@ cdef list l_f2 = b1
cdef list l_f3 = u1 cdef list l_f3 = u1
_ERRORS = u""" _ERRORS = u"""
25:20: Unicode objects do not support coercion to C types. 25:20: Unicode literals do not support coercion to C types other than Py_UNICODE.
26:22: Unicode objects do not support coercion to C types. 26:22: Unicode objects do not support coercion to C types.
27:22: 'str' objects do not support coercion to C types (use 'bytes'?). 27:22: 'str' objects do not support coercion to C types (use 'bytes'?).
......
...@@ -110,4 +110,20 @@ cdef class MyCdefClass: ...@@ -110,4 +110,20 @@ cdef class MyCdefClass:
False False
""" """
def __len__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
def __contains__(self, value):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
cdeffunc() cdeffunc()
def bool_list(list obj):
"""
>>> bool_list( [] )
False
>>> bool_list( [1] )
True
>>> bool_list(None)
False
"""
return bool(obj)
def if_list(list obj):
"""
>>> if_list( [] )
False
>>> if_list( [1] )
True
>>> if_list(None)
False
"""
if obj:
return True
else:
return False
def if_list_literal(t):
"""
>>> if_list_literal(True)
True
>>> if_list_literal(False)
False
"""
if t:
if [1,2,3]:
return True
else:
return False
else:
if []:
return True
else:
return False
def bool_tuple(tuple obj):
"""
>>> bool_tuple( () )
False
>>> bool_tuple( (1,) )
True
>>> bool_tuple(None)
False
"""
return bool(obj)
def if_tuple(tuple obj):
"""
>>> if_tuple( () )
False
>>> if_tuple( (1,) )
True
>>> if_tuple(None)
False
"""
if obj:
return True
else:
return False
def if_tuple_literal(t):
"""
>>> if_tuple_literal(True)
True
>>> if_tuple_literal(False)
False
"""
if t:
if (1,2,3):
return True
else:
return False
else:
if ():
return True
else:
return False
b0 = b''
b1 = b'abc'
def bool_bytes(bytes obj):
"""
>>> bool_bytes(b0)
False
>>> bool_bytes(b1)
True
>>> bool_bytes(None)
False
"""
return bool(obj)
def if_bytes(bytes obj):
"""
>>> if_bytes(b0)
False
>>> if_bytes(b1)
True
>>> if_bytes(None)
False
"""
if obj:
return True
else:
return False
def if_bytes_literal(t):
"""
>>> if_bytes_literal(True)
True
>>> if_bytes_literal(False)
False
"""
if t:
if b'abc':
return True
else:
return False
else:
if b'':
return True
else:
return False
u0 = u''
u1 = u'abc'
def bool_unicode(unicode obj):
"""
>>> bool_unicode(u0)
False
>>> bool_unicode(u1)
True
>>> bool_unicode(None)
False
"""
return bool(obj)
def if_unicode(unicode obj):
"""
>>> if_unicode(u0)
False
>>> if_unicode(u1)
True
>>> if_unicode(None)
False
"""
if obj:
return True
else:
return False
def if_unicode_literal(t):
"""
>>> if_unicode_literal(True)
True
>>> if_unicode_literal(False)
False
"""
if t:
if u'abc':
return True
else:
return False
else:
if u'':
return True
else:
return False
...@@ -17,6 +17,19 @@ def slice_charptr_decode(): ...@@ -17,6 +17,19 @@ def slice_charptr_decode():
cstring[:3].decode('UTF-8'), cstring[:3].decode('UTF-8'),
cstring[:9].decode('UTF-8')) cstring[:9].decode('UTF-8'))
@cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode")
def slice_charptr_decode_platform_encoding():
"""
>>> print(str(slice_charptr_decode()).replace("u'", "'"))
('a', 'abc', 'abcABCqtp')
"""
cdef bytes s = u'abcABCqtp'.encode()
cdef char* cstr = s
return (cstr[:1].decode(),
cstr[:3].decode(),
cstr[:9].decode())
@cython.test_assert_path_exists("//PythonCapiCallNode") @cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode") @cython.test_fail_if_path_exists("//AttributeNode")
def slice_charptr_decode_unknown_encoding(): def slice_charptr_decode_unknown_encoding():
......
...@@ -69,15 +69,9 @@ def lentest_uchar_c(): ...@@ -69,15 +69,9 @@ def lentest_uchar_c():
return l return l
@cython.test_assert_path_exists(
"//SimpleCallNode",
)
def lentest_py(): def lentest_py():
return len(pystr) return len(pystr)
@cython.test_assert_path_exists(
"//SimpleCallNode",
)
def lentest_py_c(): def lentest_py_c():
cdef Py_ssize_t l = len(pystr) cdef Py_ssize_t l = len(pystr)
return l return l
...@@ -43,4 +43,18 @@ def test_conjugate(long complex z): ...@@ -43,4 +43,18 @@ def test_conjugate(long complex z):
>>> test_conjugate(2+3j) >>> test_conjugate(2+3j)
(2-3j) (2-3j)
""" """
return z.conjugate() return z.conjugate()
\ No newline at end of file
def test_conjugate2(short complex z):
"""
>>> test_conjugate2(2+3j)
(2-3j)
"""
return z.conjugate()
def test_conjugate3(long long complex z):
"""
>>> test_conjugate3(2+3j)
(2-3j)
"""
return z.conjugate()
...@@ -26,3 +26,20 @@ def test_wrap_pair(int i, double x): ...@@ -26,3 +26,20 @@ def test_wrap_pair(int i, double x):
return wrap.get().first(), wrap.get().second(), deref(wrap) == deref(wrap) return wrap.get().first(), wrap.get().second(), deref(wrap) == deref(wrap)
finally: finally:
del wrap del wrap
def test_wrap_pair_pair(int i, int j, double x):
"""
>>> test_wrap_pair_pair(1, 3, 1.5)
(1, 3, 1.5, True)
>>> test_wrap_pair_pair(2, 5, 2.25)
(2, 5, 2.25, True)
"""
try:
wrap = new Wrap[Pair[int, Pair[int, double]]](
Pair[int, Pair[int, double]](i,Pair[int, double](j, x)))
return (wrap.get().first(),
wrap.get().second().first(),
wrap.get().second().second(),
deref(wrap) == deref(wrap))
finally:
del wrap
...@@ -13,6 +13,7 @@ class Pair { ...@@ -13,6 +13,7 @@ class Pair {
T1 _first; T1 _first;
T2 _second; T2 _second;
public: public:
Pair() { }
Pair(T1 u, T2 v) { _first = u; _second = v; } Pair(T1 u, T2 v) { _first = u; _second = v; }
T1 first(void) { return _first; } T1 first(void) { return _first; }
T2 second(void) { return _second; } T2 second(void) { return _second; }
......
...@@ -78,7 +78,7 @@ def test_attr_int(TestExtInt e): ...@@ -78,7 +78,7 @@ def test_attr_int(TestExtInt e):
return False return False
ctypedef union _aux: ctypedef union _aux:
int i size_t i
void *p void *p
cdef class TestExtPtr: cdef class TestExtPtr:
......
cimport cython
@cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode")
def get(dict d, key): def get(dict d, key):
""" """
>>> d = { 1: 10 } >>> d = { 1: 10 }
...@@ -38,6 +43,9 @@ def get(dict d, key): ...@@ -38,6 +43,9 @@ def get(dict d, key):
""" """
return d.get(key) return d.get(key)
@cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode")
def get_default(dict d, key, default): def get_default(dict d, key, default):
""" """
>>> d = { 1: 10 } >>> d = { 1: 10 }
...@@ -69,3 +77,14 @@ def get_default(dict d, key, default): ...@@ -69,3 +77,14 @@ def get_default(dict d, key, default):
ValueError ValueError
""" """
return d.get(key, default) return d.get(key, default)
@cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode")
def get_in_condition(dict d, key, expected_result):
"""
>>> d = dict(a=1, b=2)
>>> get_in_condition(d, 'a', 1)
True
"""
return d.get(key) is expected_result
...@@ -32,3 +32,12 @@ def test(dict d, index): ...@@ -32,3 +32,12 @@ def test(dict d, index):
cdef class Subscriptable: cdef class Subscriptable:
def __getitem__(self, key): def __getitem__(self, key):
return key return key
def getitem_in_condition(dict d, key, expected_result):
"""
>>> d = dict(a=1, b=2)
>>> getitem_in_condition(d, 'a', 1)
True
"""
return d[key] is expected_result
cimport cython
import sys
IS_PY3 = sys.version_info[0] >= 3
def _bool():
"""
>>> _bool() == bool()
True
"""
return bool()
def _int():
"""
>>> _int() == int()
True
"""
return int()
def _long():
"""
>>> IS_PY3 or _long() == long()
True
"""
return long()
def _float():
"""
>>> _float() == float()
True
"""
return float()
def _complex():
"""
>>> _complex() == complex()
True
"""
return complex()
def _bytes():
"""
>>> IS_PY3 and _bytes() == bytes() or _bytes() == str()
True
"""
return bytes()
def _str():
"""
>>> _str() == str()
True
"""
return str()
def _unicode():
"""
>>> IS_PY3 and _unicode() == str() or _unicode() == unicode()
True
"""
return unicode()
def _tuple():
"""
>>> _tuple() == tuple()
True
"""
return tuple()
def _list():
"""
>>> _list() == list()
True
"""
return list()
def _dict():
"""
>>> _dict() == dict()
True
"""
return dict()
py_set = cython.set
def _set():
"""
>>> _set() == py_set()
True
"""
return set()
py_frozenset = cython.frozenset
def _frozenset():
"""
>>> _frozenset() == py_frozenset()
True
"""
return frozenset()
cdef public enum Truth:
FALSE=0
TRUE=1
def enum_boolctx(Truth arg):
"""
>>> enum_boolctx(FALSE)
False
>>> enum_boolctx(TRUE)
True
"""
if arg:
return True
else:
return False
cdef extern from *:
enum: FALSE_VALUE "(0)"
enum: TRUE_VALUE "(1)"
def extern_enum_false():
"""
>>> extern_enum_false()
"""
if FALSE_VALUE:
raise ValueError
def extern_enum_true():
"""
>>> extern_enum_true()
"""
if not TRUE_VALUE:
raise ValueError
def extern_enum_false_true():
"""
>>> extern_enum_false_true()
"""
if not TRUE_VALUE or FALSE_VALUE:
raise ValueError
cimport cython
### extension types
cdef class MyExtType:
cdef object attr
def __cinit__(self):
self.attr = 123
cdef attr(MyExtType x):
return x is None and 321 or x.attr
# defaults, without 'not/or None'
def ext_default(MyExtType x): # currently behaves like 'or None'
"""
>>> ext_default(MyExtType())
123
>>> ext_default(None)
321
"""
return attr(x)
@cython.allow_none_for_extension_args(False)
def ext_default_none(MyExtType x=None): # special cased default arg
"""
>>> ext_default_none(MyExtType())
123
>>> ext_default_none(None)
321
>>> ext_default_none()
321
"""
return attr(x)
@cython.allow_none_for_extension_args(True)
def ext_default_check_off(MyExtType x):
"""
>>> ext_default_check_off(MyExtType())
123
>>> ext_default_check_off(None)
321
"""
return attr(x)
@cython.allow_none_for_extension_args(False)
def ext_default_check_on(MyExtType x):
"""
>>> ext_default_check_on(MyExtType())
123
>>> ext_default_check_on(None)
Traceback (most recent call last):
TypeError: Argument 'x' has incorrect type (expected ext_type_none_arg.MyExtType, got NoneType)
"""
return attr(x)
# with 'or/not None'
def ext_or_none(MyExtType x or None):
"""
>>> ext_or_none(MyExtType())
123
>>> ext_or_none(None)
321
"""
return attr(x)
def ext_not_none(MyExtType x not None):
"""
>>> ext_not_none(MyExtType())
123
>>> ext_not_none(None)
Traceback (most recent call last):
TypeError: Argument 'x' has incorrect type (expected ext_type_none_arg.MyExtType, got NoneType)
"""
return attr(x)
### builtin types (using list)
cdef litem(list L, int item):
return L is None and 321 or L[item]
# defaults, without 'not/or None'
def builtin_default(list L): # currently behaves like 'or None'
"""
>>> builtin_default([123])
123
>>> builtin_default(None)
321
"""
return litem(L, 0)
@cython.allow_none_for_extension_args(False)
def builtin_default_none(list L=None): # special cased default arg
"""
>>> builtin_default_none([123])
123
>>> builtin_default_none(None)
321
>>> builtin_default_none()
321
"""
return litem(L, 0)
@cython.allow_none_for_extension_args(True)
def builtin_default_check_off(list L):
"""
>>> builtin_default_check_off([123])
123
>>> builtin_default_check_off(None)
321
"""
return litem(L, 0)
@cython.allow_none_for_extension_args(False)
def builtin_default_check_on(list L):
"""
>>> builtin_default_check_on([123])
123
>>> builtin_default_check_on(None)
Traceback (most recent call last):
TypeError: Argument 'L' has incorrect type (expected list, got NoneType)
"""
return litem(L, 0)
# with 'or/not None'
def builtin_or_none(list L or None):
"""
>>> builtin_or_none([123])
123
>>> builtin_or_none(None)
321
"""
return litem(L, 0)
def builtin_not_none(list L not None):
"""
>>> builtin_not_none([123])
123
>>> builtin_not_none(None)
Traceback (most recent call last):
TypeError: Argument 'L' has incorrect type (expected list, got NoneType)
"""
return litem(L, 0)
## builtin type 'object' - isinstance(None, object) is True!
@cython.allow_none_for_extension_args(False)
def object_default(object o): # always behaves like 'or None'
"""
>>> object_default(object())
'object'
>>> object_default([])
'list'
>>> object_default(None)
'NoneType'
"""
return type(o).__name__
@cython.allow_none_for_extension_args(False)
def object_default_none(object o=None): # behaves like 'or None'
"""
>>> object_default_none(object())
'object'
>>> object_default_none([])
'list'
>>> object_default_none(None)
'NoneType'
>>> object_default_none()
'NoneType'
"""
return type(o).__name__
@cython.allow_none_for_extension_args(False)
def object_or_none(object o or None):
"""
>>> object_or_none(object())
'object'
>>> object_or_none([])
'list'
>>> object_or_none(None)
'NoneType'
"""
return type(o).__name__
@cython.allow_none_for_extension_args(False)
def object_not_none(object o not None):
"""
>>> object_not_none(object())
'object'
>>> object_not_none([])
'list'
>>> object_not_none(None)
Traceback (most recent call last):
TypeError: Argument 'o' must not be None
"""
return type(o).__name__
## untyped 'object' - isinstance(None, object) is True!
@cython.allow_none_for_extension_args(False)
def notype_default(o): # behaves like 'or None'
"""
>>> notype_default(object())
'object'
>>> notype_default([])
'list'
>>> notype_default(None)
'NoneType'
"""
return type(o).__name__
@cython.allow_none_for_extension_args(False)
def notype_default_none(o=None): # behaves like 'or None'
"""
>>> notype_default_none(object())
'object'
>>> notype_default_none([])
'list'
>>> notype_default_none(None)
'NoneType'
>>> notype_default_none()
'NoneType'
"""
return type(o).__name__
@cython.allow_none_for_extension_args(False)
def notype_or_none(o or None):
"""
>>> notype_or_none(object())
'object'
>>> notype_or_none([])
'list'
>>> notype_or_none(None)
'NoneType'
"""
return type(o).__name__
@cython.allow_none_for_extension_args(False)
def notype_not_none(o not None):
"""
>>> notype_not_none(object())
'object'
>>> notype_not_none([])
'list'
>>> notype_not_none(None)
Traceback (most recent call last):
TypeError: Argument 'o' must not be None
"""
return type(o).__name__
cimport cython
bytes_abc = b'abc'
bytes_ABC = b'ABC'
bytes_abc_null = b'a\0b\0c'
bytes_ABC_null = b'A\0B\0C'
unicode_abc = u'abc'
unicode_ABC = u'ABC'
unicode_abc_null = u'a\0b\0c'
unicode_ABC_null = u'A\0B\0C'
def for_in_bytes(bytes s):
"""
>>> for_in_bytes(bytes_abc)
'X'
>>> for_in_bytes(bytes_ABC)
'C'
>>> for_in_bytes(bytes_abc_null)
'X'
>>> for_in_bytes(bytes_ABC_null)
'C'
"""
for c in s:
# Py2/Py3
if c == b'C' or c == c'C':
return 'C'
else:
return 'X'
@cython.test_assert_path_exists("//ForFromStatNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def for_char_in_bytes(bytes s):
"""
>>> for_char_in_bytes(bytes_abc)
'X'
>>> for_char_in_bytes(bytes_ABC)
'C'
>>> for_char_in_bytes(bytes_abc_null)
'X'
>>> for_char_in_bytes(bytes_ABC_null)
'C'
"""
cdef char c
for c in s:
if c == b'C':
return 'C'
else:
return 'X'
@cython.test_assert_path_exists("//ForFromStatNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def for_char_in_enumerate_bytes(bytes s):
"""
>>> for_char_in_enumerate_bytes(bytes_abc)
'X'
>>> for_char_in_enumerate_bytes(bytes_ABC)
2
>>> for_char_in_enumerate_bytes(bytes_abc_null)
'X'
>>> for_char_in_enumerate_bytes(bytes_ABC_null)
4
"""
cdef char c
cdef Py_ssize_t i
for i, c in enumerate(s):
if c == b'C':
return i
else:
return 'X'
@cython.test_assert_path_exists("//ForFromStatNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def for_pyunicode_in_unicode(unicode s):
"""
>>> for_pyunicode_in_unicode(unicode_abc)
'X'
>>> for_pyunicode_in_unicode(unicode_ABC)
'C'
>>> for_pyunicode_in_unicode(unicode_abc_null)
'X'
>>> for_pyunicode_in_unicode(unicode_ABC_null)
'C'
"""
cdef Py_UNICODE c
for c in s:
if c == u'C':
return 'C'
else:
return 'X'
@cython.test_assert_path_exists("//ForFromStatNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def for_pyunicode_in_enumerate_unicode(unicode s):
"""
>>> for_pyunicode_in_enumerate_unicode(unicode_abc)
'X'
>>> for_pyunicode_in_enumerate_unicode(unicode_ABC)
2
>>> for_pyunicode_in_enumerate_unicode(unicode_abc_null)
'X'
>>> for_pyunicode_in_enumerate_unicode(unicode_ABC_null)
4
"""
cdef Py_UNICODE c
cdef Py_ssize_t i
for i, c in enumerate(s):
if c == u'C':
return i
else:
return 'X'
cimport cython
def f(a,b): def f(a,b):
""" """
>>> f(1,[1,2,3]) >>> f(1,[1,2,3])
...@@ -42,6 +45,7 @@ def j(b): ...@@ -42,6 +45,7 @@ def j(b):
cdef int result = 2 in b cdef int result = 2 in b
return result return result
@cython.test_fail_if_path_exists("//SwitchStatNode")
def k(a): def k(a):
""" """
>>> k(1) >>> k(1)
...@@ -52,16 +56,209 @@ def k(a): ...@@ -52,16 +56,209 @@ def k(a):
cdef int result = a in [1,2,3,4] cdef int result = a in [1,2,3,4]
return result return result
def m(int a): @cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def m_list(int a):
""" """
>>> m(2) >>> m_list(2)
1 1
>>> m(5) >>> m_list(5)
0 0
""" """
cdef int result = a in [1,2,3,4] cdef int result = a in [1,2,3,4]
return result return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def m_tuple(int a):
"""
>>> m_tuple(2)
1
>>> m_tuple(5)
0
"""
cdef int result = a in (1,2,3,4)
return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def m_set(int a):
"""
>>> m_set(2)
1
>>> m_set(5)
0
"""
cdef int result = a in {1,2,3,4}
return result
cdef bytes bytes_string = b'ab\0cde\0f\0g'
py_bytes_string = bytes_string
@cython.test_assert_path_exists("//PrimaryCmpNode")
@cython.test_fail_if_path_exists("//SwitchStatNode", "//BoolBinopNode")
def m_bytes(char a, bytes bytes_string):
"""
>>> m_bytes(ord('f'), py_bytes_string)
1
>>> m_bytes(ord('X'), py_bytes_string)
0
>>> 'f'.encode('ASCII') in None
Traceback (most recent call last):
TypeError: argument of type 'NoneType' is not iterable
>>> m_bytes(ord('f'), None)
Traceback (most recent call last):
TypeError: argument of type 'NoneType' is not iterable
"""
cdef int result = a in bytes_string
return result
@cython.test_assert_path_exists("//PrimaryCmpNode")
@cython.test_fail_if_path_exists("//SwitchStatNode", "//BoolBinopNode")
def m_bytes_unsigned(unsigned char a, bytes bytes_string):
"""
>>> m_bytes(ord('f'), py_bytes_string)
1
>>> m_bytes(ord('X'), py_bytes_string)
0
>>> 'f'.encode('ASCII') in None
Traceback (most recent call last):
TypeError: argument of type 'NoneType' is not iterable
>>> m_bytes(ord('f'), None)
Traceback (most recent call last):
TypeError: argument of type 'NoneType' is not iterable
"""
cdef int result = a in bytes_string
return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def m_bytes_literal(char a):
"""
>>> m_bytes_literal(ord('f'))
1
>>> m_bytes_literal(ord('X'))
0
"""
cdef int result = a in b'ab\0cde\0f\0g'
return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def m_bytes_literal_unsigned(unsigned char a):
"""
>>> m_bytes_literal(ord('f'))
1
>>> m_bytes_literal(ord('X'))
0
"""
cdef int result = a in b'ab\0cde\0f\0g'
return result
cdef unicode unicode_string = u'abc\0defg\u1234\uF8D2'
py_unicode_string = unicode_string
@cython.test_assert_path_exists("//PrimaryCmpNode")
@cython.test_fail_if_path_exists("//SwitchStatNode", "//BoolBinopNode")
def m_unicode(Py_UNICODE a, unicode unicode_string):
"""
>>> m_unicode(ord('f'), py_unicode_string)
1
>>> m_unicode(ord('X'), py_unicode_string)
0
>>> m_unicode(ord(py_klingon_character), py_unicode_string)
1
>>> 'f' in None
Traceback (most recent call last):
TypeError: argument of type 'NoneType' is not iterable
>>> m_unicode(ord('f'), None)
Traceback (most recent call last):
TypeError: argument of type 'NoneType' is not iterable
"""
cdef int result = a in unicode_string
return result
cdef unicode klingon_character = u'\uF8D2'
py_klingon_character = klingon_character
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def m_unicode_literal(Py_UNICODE a):
"""
>>> m_unicode_literal(ord('f'))
1
>>> m_unicode_literal(ord('X'))
0
>>> m_unicode_literal(ord(py_klingon_character))
1
"""
cdef int result = a in u'abc\0defg\u1234\uF8D2'
return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_int(int a):
"""
>>> conditional_int(1)
1
>>> conditional_int(0)
2
>>> conditional_int(5)
2
"""
return 1 if a in (1,2,3,4) else 2
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_object(int a):
"""
>>> conditional_object(1)
1
>>> conditional_object(0)
'2'
>>> conditional_object(5)
'2'
"""
return 1 if a in (1,2,3,4) else '2'
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_bytes(char a):
"""
>>> conditional_bytes(ord('a'))
1
>>> conditional_bytes(ord('X'))
'2'
>>> conditional_bytes(0)
'2'
"""
return 1 if a in b'abc' else '2'
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_unicode(Py_UNICODE a):
"""
>>> conditional_unicode(ord('a'))
1
>>> conditional_unicode(ord('X'))
'2'
>>> conditional_unicode(0)
'2'
"""
return 1 if a in u'abc' else '2'
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_none(int a):
"""
>>> conditional_none(1)
>>> conditional_none(0)
1
>>> conditional_none(5)
1
"""
return None if a in {1,2,3,4} else 1
def n(a): def n(a):
""" """
>>> n('d *') >>> n('d *')
......
cimport cython
dict_size = 4 dict_size = 4
d = dict(zip(range(10,dict_size+10), range(dict_size))) d = dict(zip(range(10,dict_size+10), range(dict_size)))
@cython.test_fail_if_path_exists(
"//WhileStatNode")
def items(dict d): def items(dict d):
""" """
>>> items(d) >>> items(d)
...@@ -12,6 +17,10 @@ def items(dict d): ...@@ -12,6 +17,10 @@ def items(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def iteritems(dict d): def iteritems(dict d):
""" """
>>> iteritems(d) >>> iteritems(d)
...@@ -23,6 +32,10 @@ def iteritems(dict d): ...@@ -23,6 +32,10 @@ def iteritems(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def iteritems_int(dict d): def iteritems_int(dict d):
""" """
>>> iteritems_int(d) >>> iteritems_int(d)
...@@ -35,6 +48,10 @@ def iteritems_int(dict d): ...@@ -35,6 +48,10 @@ def iteritems_int(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def iteritems_tuple(dict d): def iteritems_tuple(dict d):
""" """
>>> iteritems_tuple(d) >>> iteritems_tuple(d)
...@@ -46,11 +63,19 @@ def iteritems_tuple(dict d): ...@@ -46,11 +63,19 @@ def iteritems_tuple(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def iteritems_listcomp(dict d): def iteritems_listcomp(dict d):
cdef list l = [(k,v) for k,v in d.iteritems()] cdef list l = [(k,v) for k,v in d.iteritems()]
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def iterkeys(dict d): def iterkeys(dict d):
""" """
>>> iterkeys(d) >>> iterkeys(d)
...@@ -62,6 +87,10 @@ def iterkeys(dict d): ...@@ -62,6 +87,10 @@ def iterkeys(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def iterkeys_int(dict d): def iterkeys_int(dict d):
""" """
>>> iterkeys_int(d) >>> iterkeys_int(d)
...@@ -74,6 +103,10 @@ def iterkeys_int(dict d): ...@@ -74,6 +103,10 @@ def iterkeys_int(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def iterdict(dict d): def iterdict(dict d):
""" """
>>> iterdict(d) >>> iterdict(d)
...@@ -85,6 +118,10 @@ def iterdict(dict d): ...@@ -85,6 +118,10 @@ def iterdict(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def iterdict_int(dict d): def iterdict_int(dict d):
""" """
>>> iterdict_int(d) >>> iterdict_int(d)
...@@ -97,6 +134,10 @@ def iterdict_int(dict d): ...@@ -97,6 +134,10 @@ def iterdict_int(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def iterdict_reassign(dict d): def iterdict_reassign(dict d):
""" """
>>> iterdict_reassign(d) >>> iterdict_reassign(d)
...@@ -110,11 +151,23 @@ def iterdict_reassign(dict d): ...@@ -110,11 +151,23 @@ def iterdict_reassign(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def iterdict_listcomp(dict d): def iterdict_listcomp(dict d):
"""
>>> iterdict_listcomp(d)
[10, 11, 12, 13]
"""
cdef list l = [k for k in d] cdef list l = [k for k in d]
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def itervalues(dict d): def itervalues(dict d):
""" """
>>> itervalues(d) >>> itervalues(d)
...@@ -126,6 +179,10 @@ def itervalues(dict d): ...@@ -126,6 +179,10 @@ def itervalues(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def itervalues_int(dict d): def itervalues_int(dict d):
""" """
>>> itervalues_int(d) >>> itervalues_int(d)
...@@ -138,7 +195,28 @@ def itervalues_int(dict d): ...@@ -138,7 +195,28 @@ def itervalues_int(dict d):
l.sort() l.sort()
return l return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def itervalues_listcomp(dict d): def itervalues_listcomp(dict d):
"""
>>> itervalues_listcomp(d)
[0, 1, 2, 3]
"""
cdef list l = [v for v in d.itervalues()]
l.sort()
return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode/SimpleCallNode",
"//WhileStatNode/SimpleCallNode/NameNode")
def itervalues_kwargs(**d):
"""
>>> itervalues_kwargs(a=1, b=2, c=3, d=4)
[1, 2, 3, 4]
"""
cdef list l = [v for v in d.itervalues()] cdef list l = [v for v in d.itervalues()]
l.sort() l.sort()
return l return l
cimport cython
def f(a,b): def f(a,b):
""" """
>>> f(1,[1,2,3]) >>> f(1,[1,2,3])
...@@ -44,6 +47,7 @@ def j(b): ...@@ -44,6 +47,7 @@ def j(b):
result = 2 not in b result = 2 not in b
return result return result
@cython.test_fail_if_path_exists("//SwitchStatNode")
def k(a): def k(a):
""" """
>>> k(1) >>> k(1)
...@@ -54,16 +58,227 @@ def k(a): ...@@ -54,16 +58,227 @@ def k(a):
cdef int result = a not in [1,2,3,4] cdef int result = a not in [1,2,3,4]
return result return result
def m(int a): @cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//PrimaryCmpNode")
def m_list(int a):
""" """
>>> m(2) >>> m_list(2)
0 0
>>> m(5) >>> m_list(5)
1 1
""" """
cdef int result = a not in [1,2,3,4] cdef int result = a not in [1,2,3,4]
return result return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//PrimaryCmpNode")
def m_tuple(int a):
"""
>>> m_tuple(2)
0
>>> m_tuple(5)
1
"""
cdef int result = a not in (1,2,3,4)
return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def m_set(int a):
"""
>>> m_set(2)
0
>>> m_set(5)
1
"""
cdef int result = a not in {1,2,3,4}
return result
cdef bytes bytes_string = b'abcdefg'
@cython.test_assert_path_exists("//PrimaryCmpNode")
@cython.test_fail_if_path_exists("//SwitchStatNode", "//BoolBinopNode")
def m_bytes(char a):
"""
>>> m_bytes(ord('f'))
0
>>> m_bytes(ord('X'))
1
"""
cdef int result = a not in bytes_string
return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def m_bytes_literal(char a):
"""
>>> m_bytes_literal(ord('f'))
0
>>> m_bytes_literal(ord('X'))
1
"""
cdef int result = a not in b'abcdefg'
return result
cdef unicode unicode_string = u'abcdefg\u1234\uF8D2'
py_unicode_string = unicode_string
cdef unicode klingon_character = u'\uF8D2'
py_klingon_character = klingon_character
@cython.test_assert_path_exists("//PrimaryCmpNode")
@cython.test_fail_if_path_exists("//SwitchStatNode", "//BoolBinopNode")
def m_unicode(Py_UNICODE a, unicode unicode_string):
"""
>>> m_unicode(ord('f'), py_unicode_string)
0
>>> m_unicode(ord('X'), py_unicode_string)
1
>>> m_unicode(ord(py_klingon_character), py_unicode_string)
0
>>> 'f' in None
Traceback (most recent call last):
TypeError: argument of type 'NoneType' is not iterable
>>> m_unicode(ord('f'), None)
Traceback (most recent call last):
TypeError: argument of type 'NoneType' is not iterable
"""
cdef int result = a not in unicode_string
return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def m_unicode_literal(Py_UNICODE a):
"""
>>> m_unicode_literal(ord('f'))
0
>>> m_unicode_literal(ord('X'))
1
>>> m_unicode_literal(ord(py_klingon_character))
0
"""
cdef int result = a not in u'abcdefg\u1234\uF8D2'
return result
@cython.test_assert_path_exists("//SwitchStatNode", "//BoolBinopNode")
@cython.test_fail_if_path_exists("//PrimaryCmpNode")
def m_tuple_in_or_notin(int a):
"""
>>> m_tuple_in_or_notin(2)
0
>>> m_tuple_in_or_notin(3)
1
>>> m_tuple_in_or_notin(5)
1
"""
cdef int result = a not in (1,2,3,4) or a in (3,4)
return result
@cython.test_assert_path_exists("//SwitchStatNode", "//BoolBinopNode")
@cython.test_fail_if_path_exists("//PrimaryCmpNode")
def m_tuple_notin_or_notin(int a):
"""
>>> m_tuple_notin_or_notin(2)
1
>>> m_tuple_notin_or_notin(6)
1
>>> m_tuple_notin_or_notin(4)
0
"""
cdef int result = a not in (1,2,3,4) or a not in (4,5)
return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def m_tuple_notin_and_notin(int a):
"""
>>> m_tuple_notin_and_notin(2)
0
>>> m_tuple_notin_and_notin(6)
0
>>> m_tuple_notin_and_notin(5)
1
"""
cdef int result = a not in (1,2,3,4) and a not in (6,7)
return result
@cython.test_assert_path_exists("//SwitchStatNode", "//BoolBinopNode")
@cython.test_fail_if_path_exists("//PrimaryCmpNode")
def m_tuple_notin_and_notin_overlap(int a):
"""
>>> m_tuple_notin_and_notin_overlap(2)
0
>>> m_tuple_notin_and_notin_overlap(4)
0
>>> m_tuple_notin_and_notin_overlap(5)
1
"""
cdef int result = a not in (1,2,3,4) and a not in (3,4)
return result
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_int(int a):
"""
>>> conditional_int(1)
2
>>> conditional_int(0)
1
>>> conditional_int(5)
1
"""
return 1 if a not in (1,2,3,4) else 2
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_object(int a):
"""
>>> conditional_object(1)
'2'
>>> conditional_object(0)
1
>>> conditional_object(5)
1
"""
return 1 if a not in (1,2,3,4) else '2'
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_bytes(char a):
"""
>>> conditional_bytes(ord('a'))
'2'
>>> conditional_bytes(ord('X'))
1
>>> conditional_bytes(0)
1
"""
return 1 if a not in b'abc' else '2'
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_unicode(Py_UNICODE a):
"""
>>> conditional_unicode(ord('a'))
'2'
>>> conditional_unicode(ord('X'))
1
>>> conditional_unicode(0)
1
"""
return 1 if a not in u'abc' else '2'
@cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_none(int a):
"""
>>> conditional_none(1)
1
>>> conditional_none(0)
>>> conditional_none(5)
"""
return None if a not in {1,2,3,4} else 1
def n(a): def n(a):
""" """
>>> n('d *') >>> n('d *')
......
...@@ -104,3 +104,42 @@ def test_imports(): ...@@ -104,3 +104,42 @@ def test_imports():
MyStruct3 = typedef(MyStruct[3]) MyStruct3 = typedef(MyStruct[3])
MyStruct4 = my_typedef(MyStruct[4]) MyStruct4 = my_typedef(MyStruct[4])
MyStruct5 = cy.typedef(MyStruct[5]) MyStruct5 = cy.typedef(MyStruct[5])
def test_declare_c_types(n):
"""
>>> test_declare_c_types(0)
>>> test_declare_c_types(1)
>>> test_declare_c_types(2)
"""
#
b00 = cython.declare(cython.bint, 0)
b01 = cython.declare(cython.bint, 1)
b02 = cython.declare(cython.bint, 2)
#
i00 = cython.declare(cython.uchar, n)
i01 = cython.declare(cython.char, n)
i02 = cython.declare(cython.schar, n)
i03 = cython.declare(cython.ushort, n)
i04 = cython.declare(cython.short, n)
i05 = cython.declare(cython.sshort, n)
i06 = cython.declare(cython.uint, n)
i07 = cython.declare(cython.int, n)
i08 = cython.declare(cython.sint, n)
i09 = cython.declare(cython.slong, n)
i10 = cython.declare(cython.long, n)
i11 = cython.declare(cython.ulong, n)
i12 = cython.declare(cython.slonglong, n)
i13 = cython.declare(cython.longlong, n)
i14 = cython.declare(cython.ulonglong, n)
i20 = cython.declare(cython.Py_ssize_t, n)
i21 = cython.declare(cython.size_t, n)
#
f00 = cython.declare(cython.float, n)
f01 = cython.declare(cython.double, n)
f02 = cython.declare(cython.longdouble, n)
#
#z00 = cython.declare(cython.complex, n+1j)
#z01 = cython.declare(cython.floatcomplex, n+1j)
#z02 = cython.declare(cython.doublecomplex, n+1j)
#z03 = cython.declare(cython.longdoublecomplex, n+1j)
# -*- coding: iso-8859-1 -*-
cdef Py_UNICODE char_ASCII = u'A'
cdef Py_UNICODE char_KLINGON = u'\uF8D2'
def compare_ASCII():
"""
>>> compare_ASCII()
True
False
False
"""
print(char_ASCII == u'A')
print(char_ASCII == u'B')
print(char_ASCII == u'\uF8D2')
def compare_KLINGON():
"""
>>> compare_ASCII()
True
False
False
"""
print(char_KLINGON == u'\uF8D2')
print(char_KLINGON == u'A')
print(char_KLINGON == u'B')
def index_literal(int i):
"""
>>> index_literal(0) == '1'
True
>>> index_literal(-5) == '1'
True
>>> index_literal(2) == '3'
True
>>> index_literal(4) == '5'
True
"""
# runtime casts are not currently supported
#return <Py_UNICODE>(u"12345"[i])
return u"12345"[i]
def unicode_cardinal(Py_UNICODE i):
"""
>>> import sys
>>> unicode_cardinal(0)
0
>>> unicode_cardinal(1)
1
>>> unicode_cardinal(sys.maxunicode) == sys.maxunicode
True
>>> unicode_cardinal(-1) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
OverflowError: ...
>>> unicode_cardinal(sys.maxunicode+1) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
OverflowError: ...
"""
return i
__doc__ = u"""
>>> test(-2)
-2
>>> test(-1)
-1
>>> test(0)
0
>>> test(1)
1
>>> test(2)
2
>>> test(SSIZE_T_MAX) == SSIZE_T_MAX
True
>>> test(SSIZE_T_MIN) == SSIZE_T_MIN
True
>>> test(SSIZE_T_MAX+1) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
OverflowError: ...
>>> test(SSIZE_T_MIN-1) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
OverflowError: ...
>>> test(1<<128) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
OverflowError: ...
>>> test(-(1<<128)) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
OverflowError: ...
>>> a = A(1,2)
>>> a.a == 1
True
>>> a.b == 2
True
>>> a.foo(5)
5
>>> a.foo(1 << 180) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
OverflowError: ...
"""
# XXX This should generate a warning !!!
cdef extern from *:
ctypedef long ssize_t
SSIZE_T_MAX = <ssize_t>((<size_t>-1)>>1)
SSIZE_T_MIN = (-SSIZE_T_MAX-1)
def test(ssize_t i):
return i
cdef class A:
cdef public ssize_t a
cdef readonly ssize_t b
def __init__(self, ssize_t a, object b):
self.a = a
self.b = b
cpdef ssize_t foo(self, ssize_t x):
cdef object o = x
return o
# -*- coding: utf-8 -*-
cimport cython
import sys
PY_VERSION = sys.version_info
text = u'ab jd sdflk as sa sadas asdas fsdf '
sep = u' '
multiline_text = u'''\
ab jd
sdflk as sa
sadas asdas fsdf '''
def print_all(l):
for s in l:
print(s)
# unicode.split(s, [sep, [maxsplit]])
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def split(unicode s):
"""
>>> print_all( text.split() )
ab
jd
sdflk
as
sa
sadas
asdas
fsdf
>>> print_all( split(text) )
ab
jd
sdflk
as
sa
sadas
asdas
fsdf
"""
return s.split()
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def split_sep(unicode s, sep):
"""
>>> print_all( text.split(sep) )
ab jd
sdflk as sa
sadas asdas fsdf
>>> print_all( split_sep(text, sep) )
ab jd
sdflk as sa
sadas asdas fsdf
"""
return s.split(sep)
@cython.test_fail_if_path_exists(
"//CoerceToPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//CoerceFromPyTypeNode",
"//PythonCapiCallNode")
def split_sep_max(unicode s, sep, max):
"""
>>> print_all( text.split(sep, 1) )
ab jd
sdflk as sa sadas asdas fsdf
>>> print_all( split_sep_max(text, sep, 1) )
ab jd
sdflk as sa sadas asdas fsdf
"""
return s.split(sep, max)
@cython.test_fail_if_path_exists(
"//CoerceToPyTypeNode", "//CoerceFromPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def split_sep_max_int(unicode s, sep):
"""
>>> print_all( text.split(sep, 1) )
ab jd
sdflk as sa sadas asdas fsdf
>>> print_all( split_sep_max_int(text, sep) )
ab jd
sdflk as sa sadas asdas fsdf
"""
return s.split(sep, 1)
# unicode.splitlines(s, [keepends])
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def splitlines(unicode s):
"""
>>> len(multiline_text.splitlines())
3
>>> print_all( multiline_text.splitlines() )
ab jd
sdflk as sa
sadas asdas fsdf
>>> len(splitlines(multiline_text))
3
>>> print_all( splitlines(multiline_text) )
ab jd
sdflk as sa
sadas asdas fsdf
"""
return s.splitlines()
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def splitlines_keep(unicode s, keep):
"""
>>> len(multiline_text.splitlines(True))
3
>>> print_all( multiline_text.splitlines(True) )
ab jd
<BLANKLINE>
sdflk as sa
<BLANKLINE>
sadas asdas fsdf
>>> len(splitlines_keep(multiline_text, True))
3
>>> print_all( splitlines_keep(multiline_text, True) )
ab jd
<BLANKLINE>
sdflk as sa
<BLANKLINE>
sadas asdas fsdf
"""
return s.splitlines(keep)
@cython.test_fail_if_path_exists(
"//CoerceToPyTypeNode", "//CoerceFromPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def splitlines_keep_bint(unicode s):
"""
>>> len(multiline_text.splitlines(True))
3
>>> print_all( multiline_text.splitlines(True) )
ab jd
<BLANKLINE>
sdflk as sa
<BLANKLINE>
sadas asdas fsdf
>>> print_all( multiline_text.splitlines(False) )
ab jd
sdflk as sa
sadas asdas fsdf
>>> len(splitlines_keep_bint(multiline_text))
7
>>> print_all( splitlines_keep_bint(multiline_text) )
ab jd
<BLANKLINE>
sdflk as sa
<BLANKLINE>
sadas asdas fsdf
--
ab jd
sdflk as sa
sadas asdas fsdf
"""
return s.splitlines(True) + ['--'] + s.splitlines(False)
# unicode.join(s, iterable)
pipe_sep = u'|'
@cython.test_fail_if_path_exists(
"//CoerceToPyTypeNode", "//CoerceFromPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def join(unicode sep, l):
"""
>>> l = text.split()
>>> len(l)
8
>>> print( pipe_sep.join(l) )
ab|jd|sdflk|as|sa|sadas|asdas|fsdf
>>> print( join(pipe_sep, l) )
ab|jd|sdflk|as|sa|sadas|asdas|fsdf
"""
return sep.join(l)
@cython.test_fail_if_path_exists(
"//CoerceToPyTypeNode", "//CoerceFromPyTypeNode",
"//CastNode", "//TypecastNode", "//NoneCheckNode")
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def join_sep(l):
"""
>>> l = text.split()
>>> len(l)
8
>>> print( '|'.join(l) )
ab|jd|sdflk|as|sa|sadas|asdas|fsdf
>>> print( join_sep(l) )
ab|jd|sdflk|as|sa|sadas|asdas|fsdf
"""
return u'|'.join(l)
# unicode.startswith(s, prefix, [start, [end]])
@cython.test_fail_if_path_exists(
"//CoerceToPyTypeNode",
"//CoerceFromPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def startswith(unicode s, sub):
"""
>>> text.startswith('ab ')
True
>>> startswith(text, 'ab ')
'MATCH'
>>> text.startswith('ab X')
False
>>> startswith(text, 'ab X')
'NO MATCH'
>>> PY_VERSION < (2,5) or text.startswith(('ab', 'ab '))
True
>>> startswith(text, ('ab', 'ab '))
'MATCH'
>>> PY_VERSION < (2,5) or not text.startswith((' ab', 'ab X'))
True
>>> startswith(text, (' ab', 'ab X'))
'NO MATCH'
"""
if s.startswith(sub):
return 'MATCH'
else:
return 'NO MATCH'
@cython.test_fail_if_path_exists(
"//CoerceToPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//CoerceFromPyTypeNode",
"//PythonCapiCallNode")
def startswith_start_end(unicode s, sub, start, end):
"""
>>> text.startswith('b ', 1, 5)
True
>>> startswith_start_end(text, 'b ', 1, 5)
'MATCH'
>>> text.startswith('b X', 1, 5)
False
>>> startswith_start_end(text, 'b X', 1, 5)
'NO MATCH'
"""
if s.startswith(sub, start, end):
return 'MATCH'
else:
return 'NO MATCH'
# unicode.endswith(s, prefix, [start, [end]])
@cython.test_fail_if_path_exists(
"//CoerceToPyTypeNode",
"//CoerceFromPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def endswith(unicode s, sub):
"""
>>> text.endswith('fsdf ')
True
>>> endswith(text, 'fsdf ')
'MATCH'
>>> text.endswith('fsdf X')
False
>>> endswith(text, 'fsdf X')
'NO MATCH'
>>> PY_VERSION < (2,5) or text.endswith(('fsdf', 'fsdf '))
True
>>> endswith(text, ('fsdf', 'fsdf '))
'MATCH'
>>> PY_VERSION < (2,5) or not text.endswith(('fsdf', 'fsdf X'))
True
>>> endswith(text, ('fsdf', 'fsdf X'))
'NO MATCH'
"""
if s.endswith(sub):
return 'MATCH'
else:
return 'NO MATCH'
@cython.test_fail_if_path_exists(
"//CoerceToPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//CoerceFromPyTypeNode",
"//PythonCapiCallNode")
def endswith_start_end(unicode s, sub, start, end):
"""
>>> text.endswith('fsdf', 10, len(text)-1)
True
>>> endswith_start_end(text, 'fsdf', 10, len(text)-1)
'MATCH'
>>> text.endswith('fsdf ', 10, len(text)-1)
False
>>> endswith_start_end(text, 'fsdf ', 10, len(text)-1)
'NO MATCH'
>>> PY_VERSION < (2,5) or text.endswith(('fsd', 'fsdf'), 10, len(text)-1)
True
>>> endswith_start_end(text, ('fsd', 'fsdf'), 10, len(text)-1)
'MATCH'
>>> PY_VERSION < (2,5) or not text.endswith(('fsdf ', 'fsdf X'), 10, len(text)-1)
True
>>> endswith_start_end(text, ('fsdf ', 'fsdf X'), 10, len(text)-1)
'NO MATCH'
"""
if s.endswith(sub, start, end):
return 'MATCH'
else:
return 'NO MATCH'
# unicode.find(s, sub, [start, [end]])
@cython.test_fail_if_path_exists(
"//CoerceFromPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//CoerceToPyTypeNode",
"//PythonCapiCallNode")
def find(unicode s, substring):
"""
>>> text.find('sa')
16
>>> find(text, 'sa')
16
"""
cdef Py_ssize_t pos = s.find(substring)
return pos
@cython.test_fail_if_path_exists(
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//CoerceToPyTypeNode",
"//PythonCapiCallNode")
def find_start_end(unicode s, substring, start, end):
"""
>>> text.find('sa', 17, 25)
20
>>> find_start_end(text, 'sa', 17, 25)
20
"""
cdef Py_ssize_t pos = s.find(substring, start, end)
return pos
# unicode.rfind(s, sub, [start, [end]])
@cython.test_fail_if_path_exists(
"//CoerceFromPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//CoerceToPyTypeNode",
"//PythonCapiCallNode")
def rfind(unicode s, substring):
"""
>>> text.rfind('sa')
20
>>> rfind(text, 'sa')
20
"""
cdef Py_ssize_t pos = s.rfind(substring)
return pos
@cython.test_fail_if_path_exists(
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//CoerceToPyTypeNode",
"//PythonCapiCallNode")
def rfind_start_end(unicode s, substring, start, end):
"""
>>> text.rfind('sa', 14, 19)
16
>>> rfind_start_end(text, 'sa', 14, 19)
16
"""
cdef Py_ssize_t pos = s.rfind(substring, start, end)
return pos
# unicode.count(s, sub, [start, [end]])
@cython.test_fail_if_path_exists(
"//CoerceFromPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//CoerceToPyTypeNode",
"//PythonCapiCallNode")
def count(unicode s, substring):
"""
>>> text.count('sa')
2
>>> count(text, 'sa')
2
"""
cdef Py_ssize_t pos = s.count(substring)
return pos
@cython.test_fail_if_path_exists(
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//CoerceToPyTypeNode",
"//PythonCapiCallNode")
def count_start_end(unicode s, substring, start, end):
"""
>>> text.count('sa', 14, 21)
1
>>> text.count('sa', 14, 22)
2
>>> count_start_end(text, 'sa', 14, 21)
1
>>> count_start_end(text, 'sa', 14, 22)
2
"""
cdef Py_ssize_t pos = s.count(substring, start, end)
return pos
# unicode.replace(s, sub, repl, [maxcount])
@cython.test_fail_if_path_exists(
"//CoerceFromPyTypeNode",
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//PythonCapiCallNode")
def replace(unicode s, substring, repl):
"""
>>> print( text.replace('sa', 'SA') )
ab jd sdflk as SA SAdas asdas fsdf
>>> print( replace(text, 'sa', 'SA') )
ab jd sdflk as SA SAdas asdas fsdf
"""
return s.replace(substring, repl)
@cython.test_fail_if_path_exists(
"//CastNode", "//TypecastNode")
@cython.test_assert_path_exists(
"//CoerceFromPyTypeNode",
"//PythonCapiCallNode")
def replace_maxcount(unicode s, substring, repl, maxcount):
"""
>>> print( text.replace('sa', 'SA', 1) )
ab jd sdflk as SA sadas asdas fsdf
>>> print( replace_maxcount(text, 'sa', 'SA', 1) )
ab jd sdflk as SA sadas asdas fsdf
"""
return s.replace(substring, repl, maxcount)
import sys
if sys.version_info[0] >= 3:
__doc__ = u"""
>>> test_signed()
3 <class 'int'>
9 <class 'int'>
6 <class 'int'>
12 <class 'int'>
"""
else:
__doc__ = u"""
>>> test_signed()
3 <type 'int'>
9 <type 'long'>
6 <type 'long'>
12 <type 'long'>
"""
cdef int i = 1 cdef int i = 1
cdef long l = 2 cdef long l = 2
cdef unsigned int ui = 4 cdef unsigned int ui = 4
cdef unsigned long ul = 8 cdef unsigned long ul = 8
def test_signed(): def test_add():
print i + l, type(i+l) """
print i + ul, type(i+ul) >>> test_add()
print ui + l, type(ui+l) 3
print ui + ul, type(ui+ul) 9
6
12
"""
print i + l
print i + ul
print ui + l
print ui + ul
def test_add_sshort_ulong(signed short a, unsigned long b):
"""
>>> test_add_sshort_ulong(1, 1) == 2
True
>>> test_add_sshort_ulong(-1, 1) == 0
True
>>> test_add_sshort_ulong(-2, 1) == -1
False
"""
return a + b
def test_add_ushort_slonglong(unsigned short a, signed long long b):
"""
>>> test_add_ushort_slonglong(1, 1) == 2
True
>>> test_add_ushort_slonglong(1, -1) == 0
True
>>> test_add_ushort_slonglong(1, -2) == -1
True
"""
return a + b
def test_add_slong_ulong(signed long a, unsigned long b):
"""
>>> test_add_slong_ulong(1, 1) == 2
True
>>> test_add_slong_ulong(-1, 1) == 0
True
>>> test_add_slong_ulong(-2, 1) == -1
False
"""
return a + b
from __future__ import with_statement from __future__ import with_statement
import sys
if sys.version_info < (2,5):
__doc__ = __doc__.replace(u"exit <type 'type'> <type 'MyException'>",
u"exit <type 'classobj'> <type 'instance'>")
def typename(t): def typename(t):
return u"<type '%s'>" % type(t).__name__ return u"<type '%s'>" % type(t).__name__
......
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