Commit 5cc0a44b authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

merge

parents da14f38b fa55b747
...@@ -20,7 +20,7 @@ class EmbedSignature(CythonTransform): ...@@ -20,7 +20,7 @@ class EmbedSignature(CythonTransform):
try: try:
denv = self.denv # XXX denv = self.denv # XXX
ctval = default_val.compile_time_value(self.denv) ctval = default_val.compile_time_value(self.denv)
repr_val = '%r' % ctval repr_val = repr(ctval)
if isinstance(default_val, ExprNodes.UnicodeNode): if isinstance(default_val, ExprNodes.UnicodeNode):
if repr_val[:1] != 'u': if repr_val[:1] != 'u':
return u'u%s' % repr_val return u'u%s' % repr_val
...@@ -28,8 +28,8 @@ class EmbedSignature(CythonTransform): ...@@ -28,8 +28,8 @@ class EmbedSignature(CythonTransform):
if repr_val[:1] != 'b': if repr_val[:1] != 'b':
return u'b%s' % repr_val return u'b%s' % repr_val
elif isinstance(default_val, ExprNodes.StringNode): elif isinstance(default_val, ExprNodes.StringNode):
if repr_val[:1] in ('u', 'b'): if repr_val[:1] in 'ub':
repr_val[1:] return repr_val[1:]
return repr_val return repr_val
except Exception: except Exception:
try: try:
......
...@@ -137,7 +137,7 @@ def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, nee ...@@ -137,7 +137,7 @@ def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, nee
if defaults is None: if defaults is None:
defaults = buffer_defaults defaults = buffer_defaults
posargs, dictargs = Interpreter.interpret_compiletime_options(posargs, dictargs, type_env=env) posargs, dictargs = Interpreter.interpret_compiletime_options(posargs, dictargs, type_env=env, type_args = (0,'dtype'))
if len(posargs) > buffer_positional_options_count: if len(posargs) > buffer_positional_options_count:
raise CompileError(posargs[-1][1], ERR_BUF_TOO_MANY) raise CompileError(posargs[-1][1], ERR_BUF_TOO_MANY)
......
...@@ -637,6 +637,8 @@ class GlobalState(object): ...@@ -637,6 +637,8 @@ class GlobalState(object):
def put_cached_builtin_init(self, pos, name, cname): def put_cached_builtin_init(self, pos, name, cname):
w = self.parts['cached_builtins'] w = self.parts['cached_builtins']
interned_cname = self.get_interned_identifier(name).cname interned_cname = self.get_interned_identifier(name).cname
from ExprNodes import get_name_interned_utility_code
self.use_utility_code(get_name_interned_utility_code)
w.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % ( w.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
cname, cname,
Naming.builtins_cname, Naming.builtins_cname,
...@@ -667,7 +669,7 @@ class GlobalState(object): ...@@ -667,7 +669,7 @@ class GlobalState(object):
decls_writer = self.parts['decls'] decls_writer = self.parts['decls']
for _, cname, c in c_consts: for _, cname, c in c_consts:
decls_writer.putln('static char %s[] = "%s";' % ( decls_writer.putln('static char %s[] = "%s";' % (
cname, c.escaped_value)) cname, StringEncoding.split_string_literal(c.escaped_value)))
if c.py_strings is not None: if c.py_strings is not None:
for py_string in c.py_strings.itervalues(): for py_string in c.py_strings.itervalues():
py_strings.append((c.cname, len(py_string.cname), py_string)) py_strings.append((c.cname, len(py_string.cname), py_string))
......
...@@ -1041,6 +1041,44 @@ class ImagNode(AtomicExprNode): ...@@ -1041,6 +1041,44 @@ class ImagNode(AtomicExprNode):
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
class NewExprNode(AtomicExprNode):
# C++ new statement
#
# cppclass string c++ class to create
# template_parameters None or [ExprNode] temlate parameters, if any
def infer_type(self, env):
entry = env.lookup(self.cppclass)
if entry is None or not entry.is_cpp_class:
error(self.pos, "new operator can only be applied to a C++ class")
return
self.cpp_check(env)
if self.template_parameters is not None:
template_types = [v.analyse_as_type(env) for v in self.template_parameters]
type = entry.type.specialize_here(self.pos, template_types)
else:
type = entry.type
constructor = type.scope.lookup(u'<init>')
if constructor is None:
return_type = PyrexTypes.CFuncType(type, [])
return_type = PyrexTypes.CPtrType(return_type)
type.scope.declare_cfunction(u'<init>', return_type, self.pos)
constructor = type.scope.lookup(u'<init>')
self.class_type = type
self.entry = constructor
self.type = constructor.type
return self.type
def analyse_types(self, env):
self.infer_type(env)
def generate_result_code(self, code):
pass
def calculate_result_code(self):
return "new " + self.class_type.declaration_code("")
class NameNode(AtomicExprNode): class NameNode(AtomicExprNode):
# Reference to a local or global variable name. # Reference to a local or global variable name.
...@@ -1210,8 +1248,8 @@ class NameNode(AtomicExprNode): ...@@ -1210,8 +1248,8 @@ class NameNode(AtomicExprNode):
self.is_temp = 0 self.is_temp = 0
else: else:
self.is_temp = 1 self.is_temp = 1
self.is_used_as_rvalue = 1
env.use_utility_code(get_name_interned_utility_code) env.use_utility_code(get_name_interned_utility_code)
self.is_used_as_rvalue = 1
def nogil_check(self, env): def nogil_check(self, env):
if self.is_used_as_rvalue: if self.is_used_as_rvalue:
...@@ -1239,7 +1277,8 @@ class NameNode(AtomicExprNode): ...@@ -1239,7 +1277,8 @@ class NameNode(AtomicExprNode):
if entry.is_type and entry.type.is_extension_type: if entry.is_type and entry.type.is_extension_type:
self.type_entry = entry self.type_entry = entry
if not (entry.is_const or entry.is_variable if not (entry.is_const or entry.is_variable
or entry.is_builtin or entry.is_cfunction): or entry.is_builtin or entry.is_cfunction
or entry.is_cpp_class):
if self.entry.as_variable: if self.entry.as_variable:
self.entry = self.entry.as_variable self.entry = self.entry.as_variable
else: else:
...@@ -1297,6 +1336,7 @@ class NameNode(AtomicExprNode): ...@@ -1297,6 +1336,7 @@ class NameNode(AtomicExprNode):
namespace = Naming.builtins_cname namespace = Naming.builtins_cname
else: # entry.is_pyglobal else: # entry.is_pyglobal
namespace = entry.scope.namespace_cname namespace = entry.scope.namespace_cname
code.globalstate.use_utility_code(get_name_interned_utility_code)
code.putln( code.putln(
'%s = __Pyx_GetName(%s, %s); %s' % ( '%s = __Pyx_GetName(%s, %s); %s' % (
self.result(), self.result(),
...@@ -1517,6 +1557,12 @@ class IteratorNode(ExprNode): ...@@ -1517,6 +1557,12 @@ class IteratorNode(ExprNode):
def analyse_types(self, env): def analyse_types(self, env):
self.sequence.analyse_types(env) self.sequence.analyse_types(env)
if isinstance(self.sequence, SliceIndexNode) and \
(self.sequence.base.type.is_array or self.sequence.base.type.is_ptr) \
or self.sequence.type.is_array and self.sequence.type.size is not None:
# C array iteration will be transformed later on
pass
else:
self.sequence = self.sequence.coerce_to_pyobject(env) self.sequence = self.sequence.coerce_to_pyobject(env)
self.is_temp = 1 self.is_temp = 1
...@@ -1767,6 +1813,18 @@ class IndexNode(ExprNode): ...@@ -1767,6 +1813,18 @@ class IndexNode(ExprNode):
def analyse_as_type(self, env): def analyse_as_type(self, env):
base_type = self.base.analyse_as_type(env) base_type = self.base.analyse_as_type(env)
if base_type and not base_type.is_pyobject: if base_type and not base_type.is_pyobject:
if base_type.is_cpp_class:
if isinstance(self.index, TupleNode):
template_values = self.index.args
else:
template_values = [self.index]
import Nodes
type_node = Nodes.TemplatedTypeNode(
pos = self.pos,
positional_args = template_values,
keyword_args = None)
return type_node.analyse(env, base_type = base_type)
else:
return PyrexTypes.CArrayType(base_type, int(self.index.compile_time_value(env))) return PyrexTypes.CArrayType(base_type, int(self.index.compile_time_value(env)))
return None return None
...@@ -1869,11 +1927,6 @@ class IndexNode(ExprNode): ...@@ -1869,11 +1927,6 @@ class IndexNode(ExprNode):
else: else:
if self.base.type.is_ptr or self.base.type.is_array: if self.base.type.is_ptr or self.base.type.is_array:
self.type = self.base.type.base_type self.type = self.base.type.base_type
else:
error(self.pos,
"Attempting to index non-array type '%s'" %
self.base.type)
self.type = PyrexTypes.error_type
if self.index.type.is_pyobject: if self.index.type.is_pyobject:
self.index = self.index.coerce_to( self.index = self.index.coerce_to(
PyrexTypes.c_py_ssize_t_type, env) PyrexTypes.c_py_ssize_t_type, env)
...@@ -1881,6 +1934,26 @@ class IndexNode(ExprNode): ...@@ -1881,6 +1934,26 @@ class IndexNode(ExprNode):
error(self.pos, error(self.pos,
"Invalid index type '%s'" % "Invalid index type '%s'" %
self.index.type) self.index.type)
elif self.base.type.is_cpp_class:
function = env.lookup_operator("[]", [self.base, self.index])
function = self.base.type.scope.lookup("operator[]")
if function is None:
error(self.pos, "Indexing '%s' not supported for index type '%s'" % (self.base.type, self.index.type))
self.type = PyrexTypes.error_type
self.result_code = "<error>"
return
func_type = function.type
if func_type.is_ptr:
func_type = func_type.base_type
self.index = self.index.coerce_to(func_type.args[0].type, env)
self.type = func_type.return_type
if setting and not func_type.return_type.is_reference:
error(self.pos, "Can't set non-reference '%s'" % self.type)
else:
error(self.pos,
"Attempting to index non-array type '%s'" %
self.base.type)
self.type = PyrexTypes.error_type
gil_message = "Indexing Python object" gil_message = "Indexing Python object"
def nogil_check(self, env): def nogil_check(self, env):
...@@ -2380,6 +2453,15 @@ class CallNode(ExprNode): ...@@ -2380,6 +2453,15 @@ class CallNode(ExprNode):
self.analyse_types(env) self.analyse_types(env)
self.coerce_to(type, env) self.coerce_to(type, env)
return True return True
elif type and type.is_cpp_class:
for arg in self.args:
arg.analyse_types(env)
constructor = type.scope.lookup("<init>")
self.function = RawCNameExprNode(self.function.pos, constructor.type)
self.function.entry = constructor
self.function.set_cname(type.declaration_code(""))
self.analyse_c_function_call(env)
return True
def nogil_check(self, env): def nogil_check(self, env):
func_type = self.function_type() func_type = self.function_type()
...@@ -2426,6 +2508,8 @@ class SimpleCallNode(CallNode): ...@@ -2426,6 +2508,8 @@ class SimpleCallNode(CallNode):
def infer_type(self, env): def infer_type(self, env):
function = self.function function = self.function
func_type = function.infer_type(env) func_type = function.infer_type(env)
if isinstance(self.function, NewExprNode):
return PyrexTypes.CPtrType(self.function.class_type)
if func_type.is_ptr: if func_type.is_ptr:
func_type = func_type.base_type func_type = func_type.base_type
if func_type.is_cfunction: if func_type.is_cfunction:
...@@ -2515,36 +2599,26 @@ class SimpleCallNode(CallNode): ...@@ -2515,36 +2599,26 @@ class SimpleCallNode(CallNode):
return func_type return func_type
def analyse_c_function_call(self, env): def analyse_c_function_call(self, env):
func_type = self.function_type() if self.function.type.is_cpp_class:
# Check function type function = self.function.type.scope.lookup("operator()")
if not func_type.is_cfunction: if function is None:
if not func_type.is_error:
error(self.pos, "Calling non-function type '%s'" %
func_type)
self.type = PyrexTypes.error_type self.type = PyrexTypes.error_type
self.result_code = "<error>" self.result_code = "<error>"
return return
else:
function = self.function.entry
entry = PyrexTypes.best_match(self.args, function.all_alternatives(), self.pos)
if not entry:
self.type = PyrexTypes.error_type
self.result_code = "<error>"
return
self.function.entry = entry
self.function.type = entry.type
func_type = self.function_type()
# Check no. of args # Check no. of args
max_nargs = len(func_type.args) max_nargs = len(func_type.args)
expected_nargs = max_nargs - func_type.optional_arg_count expected_nargs = max_nargs - func_type.optional_arg_count
actual_nargs = len(self.args) actual_nargs = len(self.args)
if actual_nargs < expected_nargs \
or (not func_type.has_varargs and actual_nargs > max_nargs):
expected_str = str(expected_nargs)
if func_type.has_varargs:
expected_str = "at least " + expected_str
elif func_type.optional_arg_count:
if actual_nargs < max_nargs:
expected_str = "at least " + expected_str
else:
expected_str = "at most " + str(max_nargs)
error(self.pos,
"Call with wrong number of arguments (expected %s, got %s)"
% (expected_str, actual_nargs))
self.args = None
self.type = PyrexTypes.error_type
self.result_code = "<error>"
return
if func_type.optional_arg_count and expected_nargs != actual_nargs: if func_type.optional_arg_count and expected_nargs != actual_nargs:
self.has_optional_args = 1 self.has_optional_args = 1
self.is_temp = 1 self.is_temp = 1
...@@ -2557,6 +2631,9 @@ class SimpleCallNode(CallNode): ...@@ -2557,6 +2631,9 @@ class SimpleCallNode(CallNode):
error(self.args[i].pos, error(self.args[i].pos,
"Python object cannot be passed as a varargs parameter") "Python object cannot be passed as a varargs parameter")
# Calc result type and code fragment # Calc result type and code fragment
if isinstance(self.function, NewExprNode):
self.type = PyrexTypes.CPtrType(self.function.class_type)
else:
self.type = func_type.return_type self.type = func_type.return_type
if self.type.is_pyobject: if self.type.is_pyobject:
self.result_ctype = py_object_type self.result_ctype = py_object_type
...@@ -2574,7 +2651,7 @@ class SimpleCallNode(CallNode): ...@@ -2574,7 +2651,7 @@ class SimpleCallNode(CallNode):
def c_call_code(self): def c_call_code(self):
func_type = self.function_type() func_type = self.function_type()
if self.args is None or not func_type.is_cfunction: if self.type is PyrexTypes.error_type or not func_type.is_cfunction:
return "<error>" return "<error>"
formal_args = func_type.args formal_args = func_type.args
arg_list_code = [] arg_list_code = []
...@@ -2874,6 +2951,9 @@ class AttributeNode(ExprNode): ...@@ -2874,6 +2951,9 @@ class AttributeNode(ExprNode):
def as_cython_attribute(self): def as_cython_attribute(self):
if isinstance(self.obj, NameNode) and self.obj.is_cython_module: if isinstance(self.obj, NameNode) and self.obj.is_cython_module:
return self.attribute return self.attribute
cy = self.obj.as_cython_attribute()
if cy:
return "%s.%s" % (cy, self.attribute)
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
# If coercing to a generic pyobject and this is a cpdef function # If coercing to a generic pyobject and this is a cpdef function
...@@ -4012,6 +4092,7 @@ class UnboundMethodNode(ExprNode): ...@@ -4012,6 +4092,7 @@ class UnboundMethodNode(ExprNode):
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
class PyCFunctionNode(AtomicExprNode): class PyCFunctionNode(AtomicExprNode):
# Helper class used in the implementation of Python # Helper class used in the implementation of Python
# class definitions. Constructs a PyCFunction object # class definitions. Constructs a PyCFunction object
...@@ -4088,6 +4169,8 @@ class UnopNode(ExprNode): ...@@ -4088,6 +4169,8 @@ class UnopNode(ExprNode):
self.coerce_operand_to_pyobject(env) self.coerce_operand_to_pyobject(env)
self.type = py_object_type self.type = py_object_type
self.is_temp = 1 self.is_temp = 1
elif self.is_cpp_operation():
self.analyse_cpp_operation(env)
else: else:
self.analyse_c_operation(env) self.analyse_c_operation(env)
...@@ -4101,6 +4184,10 @@ class UnopNode(ExprNode): ...@@ -4101,6 +4184,10 @@ class UnopNode(ExprNode):
if self.is_py_operation(): if self.is_py_operation():
self.gil_error() self.gil_error()
def is_cpp_operation(self):
type = self.operand.type
return type.is_cpp_class or type.is_reference and type.base_type.is_cpp_class
def coerce_operand_to_pyobject(self, env): def coerce_operand_to_pyobject(self, env):
self.operand = self.operand.coerce_to_pyobject(env) self.operand = self.operand.coerce_to_pyobject(env)
...@@ -4124,6 +4211,22 @@ class UnopNode(ExprNode): ...@@ -4124,6 +4211,22 @@ class UnopNode(ExprNode):
(self.operator, self.operand.type)) (self.operator, self.operand.type))
self.type = PyrexTypes.error_type self.type = PyrexTypes.error_type
def analyse_cpp_operation(self, env):
type = self.operand.type
if type.is_ptr or type.is_reference:
type = type.base_type
entry = env.lookup(type.name)
function = entry.type.scope.lookup("operator%s" % self.operator)
if not function:
error(self.pos, "'%s' operator not defined for %s"
% (self.operator, type))
self.type_error()
return
func_type = function.type
if func_type.is_ptr:
func_type = func_type.base_type
self.type = func_type.return_type
class NotNode(ExprNode): class NotNode(ExprNode):
# 'not' operator # 'not' operator
...@@ -4170,6 +4273,9 @@ class UnaryPlusNode(UnopNode): ...@@ -4170,6 +4273,9 @@ class UnaryPlusNode(UnopNode):
return "PyNumber_Positive" return "PyNumber_Positive"
def calculate_result_code(self): def calculate_result_code(self):
if self.is_cpp_operation():
return "(+%s)" % self.operand.result()
else:
return self.operand.result() return self.operand.result()
...@@ -4216,6 +4322,45 @@ class TildeNode(UnopNode): ...@@ -4216,6 +4322,45 @@ class TildeNode(UnopNode):
return "(~%s)" % self.operand.result() return "(~%s)" % self.operand.result()
class CUnopNode(UnopNode):
def is_py_operation(self):
return False
class DereferenceNode(CUnopNode):
# unary * operator
operator = '*'
def analyse_c_operation(self, env):
if self.operand.type.is_ptr:
self.type = self.operand.type.base_type
else:
self.type_error()
def calculate_result_code(self):
return "(*%s)" % self.operand.result()
class DecrementIncrementNode(CUnopNode):
# unary ++/-- operator
def analyse_c_operation(self, env):
if self.operand.type.is_ptr or self.operand.type.is_numeric:
self.type = self.operand.type
else:
self.type_error()
def calculate_result_code(self):
if self.is_prefix:
return "(%s%s)" % (self.operator, self.operand.result())
else:
return "(%s%s)" % (self.operand.result(), self.operator)
def inc_dec_constructor(is_prefix, operator):
return lambda pos, **kwds: DecrementIncrementNode(pos, is_prefix=is_prefix, operator=operator, **kwds)
class AmpersandNode(ExprNode): class AmpersandNode(ExprNode):
# The C address-of operator. # The C address-of operator.
# #
...@@ -4570,8 +4715,12 @@ class BinopNode(ExprNode): ...@@ -4570,8 +4715,12 @@ class BinopNode(ExprNode):
self.operand2.analyse_types(env) self.operand2.analyse_types(env)
if self.is_py_operation(): if self.is_py_operation():
self.coerce_operands_to_pyobjects(env) self.coerce_operands_to_pyobjects(env)
self.type = py_object_type self.type = self.result_type(self.operand1.type,
self.operand2.type)
assert self.type.is_pyobject
self.is_temp = 1 self.is_temp = 1
elif self.is_cpp_operation():
self.analyse_cpp_operation(env)
else: else:
self.analyse_c_operation(env) self.analyse_c_operation(env)
...@@ -4581,8 +4730,59 @@ class BinopNode(ExprNode): ...@@ -4581,8 +4730,59 @@ class BinopNode(ExprNode):
def is_py_operation_types(self, type1, type2): def is_py_operation_types(self, type1, type2):
return type1.is_pyobject or type2.is_pyobject return type1.is_pyobject or type2.is_pyobject
def is_cpp_operation(self):
type1 = self.operand1.type
type2 = self.operand2.type
if type1.is_reference:
type1 = type1.base_type
if type2.is_reference:
type2 = type2.base_type
return (type1.is_cpp_class
or type2.is_cpp_class)
def analyse_cpp_operation(self, env):
type1 = self.operand1.type
type2 = self.operand2.type
entry = env.lookup_operator(self.operator, [self.operand1, self.operand2])
if not entry:
self.type_error()
return
func_type = entry.type
if func_type.is_ptr:
func_type = func_type.base_type
if len(func_type.args) == 1:
self.operand2 = self.operand2.coerce_to(func_type.args[0].type, env)
else:
self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env)
self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env)
self.type = func_type.return_type
def result_type(self, type1, type2): def result_type(self, type1, type2):
if self.is_py_operation_types(type1, type2): if self.is_py_operation_types(type1, type2):
if type2.is_string:
type2 = Builtin.bytes_type
if type1.is_string:
type1 = Builtin.bytes_type
elif self.operator == '%' \
and type1 in (Builtin.str_type, Builtin.unicode_type):
# note that b'%s' % b'abc' doesn't work in Py3
return type1
if type1.is_builtin_type:
if type1 is type2:
if self.operator in '**%+|&^':
# FIXME: at least these operators should be safe - others?
return type1
elif self.operator == '*':
if type1 in (Builtin.bytes_type, Builtin.str_type, Builtin.unicode_type):
return type1
# multiplication of containers/numbers with an
# integer value always (?) returns the same type
if type2.is_int:
return type1
elif type2.is_builtin_type and type1.is_int and self.operator == '*':
# multiplication of containers/numbers with an
# integer value always (?) returns the same type
return type2
return py_object_type return py_object_type
else: else:
return self.compute_c_result_type(type1, type2) return self.compute_c_result_type(type1, type2)
...@@ -4790,6 +4990,8 @@ class DivNode(NumBinopNode): ...@@ -4790,6 +4990,8 @@ class DivNode(NumBinopNode):
else: else:
self.ctruedivision = self.truedivision self.ctruedivision = self.truedivision
NumBinopNode.analyse_types(self, env) NumBinopNode.analyse_types(self, env)
if self.is_cpp_operation():
self.cdivision = True
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']
...@@ -5184,6 +5386,15 @@ class CmpNode(object): ...@@ -5184,6 +5386,15 @@ class CmpNode(object):
result = result and cascade.compile_time_value(operand2, denv) result = result and cascade.compile_time_value(operand2, denv)
return result return result
def is_cpp_comparison(self):
type1 = self.operand1.type
type2 = self.operand2.type
if type1.is_reference:
type1 = type1.base_type
if type2.is_reference:
type2 = type2.base_type
return type1.is_cpp_class or type2.is_cpp_class
def find_common_int_type(self, env, op, operand1, operand2): def find_common_int_type(self, env, op, operand1, operand2):
# type1 != type2 and at least one of the types is not a C int # type1 != type2 and at least one of the types is not a C int
type1 = operand1.type type1 = operand1.type
...@@ -5442,6 +5653,11 @@ class PrimaryCmpNode(ExprNode, CmpNode): ...@@ -5442,6 +5653,11 @@ class PrimaryCmpNode(ExprNode, CmpNode):
def analyse_types(self, env): def analyse_types(self, env):
self.operand1.analyse_types(env) self.operand1.analyse_types(env)
self.operand2.analyse_types(env) self.operand2.analyse_types(env)
if self.is_cpp_comparison():
self.analyse_cpp_comparison(env)
if self.cascade:
error(self.pos, "Cascading comparison not yet supported for cpp types.")
return
if self.cascade: if self.cascade:
self.cascade.analyse_types(env) self.cascade.analyse_types(env)
...@@ -5471,6 +5687,26 @@ class PrimaryCmpNode(ExprNode, CmpNode): ...@@ -5471,6 +5687,26 @@ class PrimaryCmpNode(ExprNode, CmpNode):
if self.is_pycmp or self.cascade: if self.is_pycmp or self.cascade:
self.is_temp = 1 self.is_temp = 1
def analyse_cpp_comparison(self, env):
type1 = self.operand1.type
type2 = self.operand2.type
entry = env.lookup_operator(self.operator, [self.operand1, self.operand2])
if entry is None:
error(self.pos, "Invalid types for '%s' (%s, %s)" %
(self.operator, type1, type2))
self.type = PyrexTypes.error_type
self.result_code = "<error>"
return
func_type = entry.type
if func_type.is_ptr:
func_type = func_type.base_type
if len(func_type.args) == 1:
self.operand2 = self.operand2.coerce_to(func_type.args[0].type, env)
else:
self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env)
self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env)
self.type = func_type.return_type
def has_python_operands(self): def has_python_operands(self):
return (self.operand1.type.is_pyobject return (self.operand1.type.is_pyobject
or self.operand2.type.is_pyobject) or self.operand2.type.is_pyobject)
......
...@@ -17,7 +17,7 @@ class EmptyScope(object): ...@@ -17,7 +17,7 @@ class EmptyScope(object):
empty_scope = EmptyScope() empty_scope = EmptyScope()
def interpret_compiletime_options(optlist, optdict, type_env=None): def interpret_compiletime_options(optlist, optdict, type_env=None, type_args=()):
""" """
Tries to interpret a list of compile time option nodes. Tries to interpret a list of compile time option nodes.
The result will be a tuple (optlist, optdict) but where The result will be a tuple (optlist, optdict) but where
...@@ -34,21 +34,21 @@ def interpret_compiletime_options(optlist, optdict, type_env=None): ...@@ -34,21 +34,21 @@ def interpret_compiletime_options(optlist, optdict, type_env=None):
A CompileError will be raised if there are problems. A CompileError will be raised if there are problems.
""" """
def interpret(node): def interpret(node, ix):
if isinstance(node, CBaseTypeNode): if ix in type_args:
if type_env: if type_env:
return (node.analyse(type_env), node.pos) return (node.analyse_as_type(type_env), node.pos)
else: else:
raise CompileError(node.pos, "Type not allowed here.") raise CompileError(node.pos, "Type not allowed here.")
else: else:
return (node.compile_time_value(empty_scope), node.pos) return (node.compile_time_value(empty_scope), node.pos)
if optlist: if optlist:
optlist = [interpret(x) for x in optlist] optlist = [interpret(x, ix) for ix, x in enumerate(optlist)]
if optdict: if optdict:
assert isinstance(optdict, DictNode) assert isinstance(optdict, DictNode)
new_optdict = {} new_optdict = {}
for item in optdict.key_value_pairs: for item in optdict.key_value_pairs:
new_optdict[item.key.value] = interpret(item.value) new_optdict[item.key.value] = interpret(item.value, item.key.value)
optdict = new_optdict optdict = new_optdict
return (optlist, new_optdict) return (optlist, new_optdict)
...@@ -66,7 +66,7 @@ class Context(object): ...@@ -66,7 +66,7 @@ class Context(object):
# include_directories [string] # include_directories [string]
# future_directives [object] # future_directives [object]
def __init__(self, include_directories, compiler_directives): def __init__(self, include_directories, compiler_directives, cpp=False):
#self.modules = {"__builtin__" : BuiltinScope()} #self.modules = {"__builtin__" : BuiltinScope()}
import Builtin, CythonScope import Builtin, CythonScope
self.modules = {"__builtin__" : Builtin.builtin_scope} self.modules = {"__builtin__" : Builtin.builtin_scope}
...@@ -74,6 +74,7 @@ class Context(object): ...@@ -74,6 +74,7 @@ class Context(object):
self.include_directories = include_directories self.include_directories = include_directories
self.future_directives = set() self.future_directives = set()
self.compiler_directives = compiler_directives self.compiler_directives = compiler_directives
self.cpp = cpp
self.pxds = {} # full name -> node tree self.pxds = {} # full name -> node tree
...@@ -87,7 +88,7 @@ class Context(object): ...@@ -87,7 +88,7 @@ class Context(object):
from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
from TypeInference import MarkAssignments from TypeInference import MarkAssignments, MarkOverflowingArithmatic
from ParseTreeTransforms import AlignFunctionDefinitions, GilCheck from ParseTreeTransforms import AlignFunctionDefinitions, GilCheck
from AnalysedTreeTransforms import AutoTestDictTransform from AnalysedTreeTransforms import AutoTestDictTransform
from AutoDocTransforms import EmbedSignature from AutoDocTransforms import EmbedSignature
...@@ -134,6 +135,7 @@ class Context(object): ...@@ -134,6 +135,7 @@ class Context(object):
EmbedSignature(self), EmbedSignature(self),
EarlyReplaceBuiltinCalls(self), EarlyReplaceBuiltinCalls(self),
MarkAssignments(self), MarkAssignments(self),
MarkOverflowingArithmatic(self),
TransformBuiltinMethods(self), TransformBuiltinMethods(self),
IntroduceBufferAuxiliaryVars(self), IntroduceBufferAuxiliaryVars(self),
_check_c_declarations, _check_c_declarations,
...@@ -217,8 +219,11 @@ class Context(object): ...@@ -217,8 +219,11 @@ class Context(object):
for phase in pipeline: for phase in pipeline:
if phase is not None: if phase is not None:
if DebugFlags.debug_verbose_pipeline: if DebugFlags.debug_verbose_pipeline:
t = time()
print "Entering pipeline phase %r" % phase print "Entering pipeline phase %r" % phase
data = phase(data) data = phase(data)
if DebugFlags.debug_verbose_pipeline:
print " %.3f seconds" % (time() - t)
except CompileError, err: except CompileError, err:
# err is set # err is set
Errors.report_error(err) Errors.report_error(err)
...@@ -451,6 +456,7 @@ class Context(object): ...@@ -451,6 +456,7 @@ class Context(object):
if not isinstance(source_desc, FileSourceDescriptor): if not isinstance(source_desc, FileSourceDescriptor):
raise RuntimeError("Only file sources for code supported") raise RuntimeError("Only file sources for code supported")
source_filename = Utils.encode_filename(source_desc.filename) source_filename = Utils.encode_filename(source_desc.filename)
scope.cpp = self.cpp
# Parse the given source file and return a parse tree. # Parse the given source file and return a parse tree.
try: try:
f = Utils.open_source_file(source_filename, "rU") f = Utils.open_source_file(source_filename, "rU")
...@@ -540,7 +546,7 @@ def create_default_resultobj(compilation_source, options): ...@@ -540,7 +546,7 @@ def create_default_resultobj(compilation_source, options):
def run_pipeline(source, options, full_module_name = None): def run_pipeline(source, options, full_module_name = None):
# Set up context # Set up context
context = Context(options.include_path, options.compiler_directives) context = Context(options.include_path, options.compiler_directives, options.cplus)
# Set up source object # Set up source object
cwd = os.getcwd() cwd = os.getcwd()
......
...@@ -616,6 +616,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -616,6 +616,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
includes = [] includes = []
for filename in env.include_files: for filename in env.include_files:
# fake decoding of filenames to their original byte sequence # fake decoding of filenames to their original byte sequence
if filename[0] == '<' and filename[-1] == '>':
code.putln('#include %s' % filename)
else:
code.putln('#include "%s"' % filename) code.putln('#include "%s"' % filename)
def generate_filename_table(self, code): def generate_filename_table(self, code):
......
# #
# Pyrex - Parse tree nodes # Pyrex - Parse tree nodes
# #
...@@ -18,10 +19,10 @@ import PyrexTypes ...@@ -18,10 +19,10 @@ import PyrexTypes
import TypeSlots import TypeSlots
from PyrexTypes import py_object_type, error_type, CFuncType from PyrexTypes import py_object_type, error_type, CFuncType
from Symtab import ModuleScope, LocalScope, GeneratorLocalScope, \ from Symtab import ModuleScope, LocalScope, GeneratorLocalScope, \
StructOrUnionScope, PyClassScope, CClassScope StructOrUnionScope, PyClassScope, CClassScope, CppClassScope
from Cython.Utils import open_new_file, replace_suffix from Cython.Utils import open_new_file, replace_suffix
from Code import UtilityCode from Code import UtilityCode
from StringEncoding import EncodedString, escape_byte_string, split_docstring from StringEncoding import EncodedString, escape_byte_string, split_string_literal
import Options import Options
import ControlFlow import ControlFlow
import DebugFlags import DebugFlags
...@@ -144,6 +145,15 @@ class Node(object): ...@@ -144,6 +145,15 @@ class Node(object):
def gil_error(self, env=None): def gil_error(self, env=None):
error(self.pos, "%s not allowed without gil" % self.gil_message) error(self.pos, "%s not allowed without gil" % self.gil_message)
cpp_message = "Operation"
def cpp_check(self, env):
if not env.is_cpp():
self.cpp_error()
def cpp_error(self):
error(self.pos, "%s only allowed in c++" % self.cpp_message)
def clone_node(self): def clone_node(self):
"""Clone the node. This is defined as a shallow copy, except for member lists """Clone the node. This is defined as a shallow copy, except for member lists
amongst the child attributes (from get_child_accessors) which are also amongst the child attributes (from get_child_accessors) which are also
...@@ -448,6 +458,18 @@ class CPtrDeclaratorNode(CDeclaratorNode): ...@@ -448,6 +458,18 @@ class CPtrDeclaratorNode(CDeclaratorNode):
ptr_type = PyrexTypes.c_ptr_type(base_type) ptr_type = PyrexTypes.c_ptr_type(base_type)
return self.base.analyse(ptr_type, env, nonempty = nonempty) return self.base.analyse(ptr_type, env, nonempty = nonempty)
class CReferenceDeclaratorNode(CDeclaratorNode):
# base CDeclaratorNode
child_attrs = ["base"]
def analyse(self, base_type, env, nonempty = 0):
if base_type.is_pyobject:
error(self.pos,
"Reference base type cannot be a Python object")
ref_type = PyrexTypes.c_ref_type(base_type)
return self.base.analyse(ref_type, env, nonempty = nonempty)
class CArrayDeclaratorNode(CDeclaratorNode): class CArrayDeclaratorNode(CDeclaratorNode):
# base CDeclaratorNode # base CDeclaratorNode
# dimension ExprNode # dimension ExprNode
...@@ -455,6 +477,19 @@ class CArrayDeclaratorNode(CDeclaratorNode): ...@@ -455,6 +477,19 @@ class CArrayDeclaratorNode(CDeclaratorNode):
child_attrs = ["base", "dimension"] child_attrs = ["base", "dimension"]
def analyse(self, base_type, env, nonempty = 0): def analyse(self, base_type, env, nonempty = 0):
if base_type.is_cpp_class:
from ExprNodes import TupleNode
if isinstance(self.dimension, TupleNode):
args = self.dimension.args
else:
args = self.dimension,
values = [v.analyse_as_type(env) for v in args]
if None in values:
ix = values.index(None)
error(args[ix].pos, "Template parameter not a type.")
return error_type
base_type = base_type.specialize_here(self.pos, values)
return self.base.analyse(base_type, env, nonempty = nonempty)
if self.dimension: if self.dimension:
self.dimension.analyse_const_expression(env) self.dimension.analyse_const_expression(env)
if not self.dimension.type.is_int: if not self.dimension.type.is_int:
...@@ -626,6 +661,17 @@ class CArgDeclNode(Node): ...@@ -626,6 +661,17 @@ class CArgDeclNode(Node):
base_type = self.base_type.analyse(env, could_be_name = could_be_name) base_type = self.base_type.analyse(env, could_be_name = could_be_name)
if hasattr(self.base_type, 'arg_name') and self.base_type.arg_name: if hasattr(self.base_type, 'arg_name') and self.base_type.arg_name:
self.declarator.name = self.base_type.arg_name self.declarator.name = self.base_type.arg_name
# The parser is unable to resolve the ambiguity of [] as part of the
# type (e.g. in buffers) or empty declarator (as with arrays).
# This is only arises for empty multi-dimensional arrays.
if (base_type.is_array
and isinstance(self.base_type, TemplatedTypeNode)
and isinstance(self.declarator, CArrayDeclaratorNode)):
declarator = self.declarator
while isinstance(declarator.base, CArrayDeclaratorNode):
declarator = declarator.base
declarator.base = self.base_type.array_declarator
base_type = base_type.base_type
return self.declarator.analyse(base_type, env, nonempty = nonempty) return self.declarator.analyse(base_type, env, nonempty = nonempty)
else: else:
return self.name_declarator, self.type return self.name_declarator, self.type
...@@ -655,6 +701,9 @@ class CBaseTypeNode(Node): ...@@ -655,6 +701,9 @@ class CBaseTypeNode(Node):
pass pass
def analyse_as_type(self, env):
return self.analyse(env)
class CAnalysedBaseTypeNode(Node): class CAnalysedBaseTypeNode(Node):
# type type # type type
...@@ -713,6 +762,11 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -713,6 +762,11 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
else: else:
type = py_object_type type = py_object_type
self.arg_name = self.name self.arg_name = self.name
else:
if self.templates:
if not self.name in self.templates:
error(self.pos, "'%s' is not a type identifier" % self.name)
type = PyrexTypes.TemplatePlaceholderType(self.name)
else: else:
error(self.pos, "'%s' is not a type identifier" % self.name) error(self.pos, "'%s' is not a type identifier" % self.name)
if self.complex: if self.complex:
...@@ -725,14 +779,14 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -725,14 +779,14 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
else: else:
return PyrexTypes.error_type return PyrexTypes.error_type
class CBufferAccessTypeNode(CBaseTypeNode): class TemplatedTypeNode(CBaseTypeNode):
# After parsing: # After parsing:
# positional_args [ExprNode] List of positional arguments # positional_args [ExprNode] List of positional arguments
# keyword_args DictNode Keyword arguments # keyword_args DictNode Keyword arguments
# base_type_node CBaseTypeNode # base_type_node CBaseTypeNode
# After analysis: # After analysis:
# type PyrexType.BufferType ...containing the right options # type PyrexTypes.BufferType or PyrexTypes.CppClassType ...containing the right options
child_attrs = ["base_type_node", "positional_args", child_attrs = ["base_type_node", "positional_args",
...@@ -742,9 +796,24 @@ class CBufferAccessTypeNode(CBaseTypeNode): ...@@ -742,9 +796,24 @@ class CBufferAccessTypeNode(CBaseTypeNode):
name = None name = None
def analyse(self, env, could_be_name = False): def analyse(self, env, could_be_name = False, base_type = None):
if base_type is None:
base_type = self.base_type_node.analyse(env) base_type = self.base_type_node.analyse(env)
if base_type.is_error: return base_type if base_type.is_error: return base_type
if base_type.is_cpp_class:
# Templated class
if self.keyword_args and self.keyword_args.key_value_pairs:
error(self.pos, "c++ templates cannot take keyword arguments");
self.type = PyrexTypes.error_type
else:
template_types = []
for template_node in self.positional_args:
template_types.append(template_node.analyse_as_type(env))
self.type = base_type.specialize_here(self.pos, template_types)
elif base_type.is_pyobject:
# Buffer
import Buffer import Buffer
options = Buffer.analyse_buffer_options( options = Buffer.analyse_buffer_options(
...@@ -760,6 +829,25 @@ class CBufferAccessTypeNode(CBaseTypeNode): ...@@ -760,6 +829,25 @@ class CBufferAccessTypeNode(CBaseTypeNode):
for name, value in options.iteritems() ]) for name, value in options.iteritems() ])
self.type = PyrexTypes.BufferType(base_type, **options) self.type = PyrexTypes.BufferType(base_type, **options)
else:
# Array
empty_declarator = CNameDeclaratorNode(self.pos, name="", cname=None)
if len(self.positional_args) > 1 or self.keyword_args.key_value_pairs:
error(self.pos, "invalid array declaration")
self.type = PyrexTypes.error_type
else:
# It would be nice to merge this class with CArrayDeclaratorNode,
# but arrays are part of the declaration, not the type...
if not self.positional_args:
dimension = None
else:
dimension = self.positional_args[0]
self.array_declarator = CArrayDeclaratorNode(self.pos,
base = empty_declarator,
dimension = dimension)
self.type = self.array_declarator.analyse(base_type, env)[1]
return self.type return self.type
class CComplexBaseTypeNode(CBaseTypeNode): class CComplexBaseTypeNode(CBaseTypeNode):
...@@ -904,6 +992,46 @@ class CStructOrUnionDefNode(StatNode): ...@@ -904,6 +992,46 @@ class CStructOrUnionDefNode(StatNode):
pass pass
class CppClassNode(CStructOrUnionDefNode):
# name string
# cname string or None
# visibility "extern"
# in_pxd boolean
# attributes [CVarDefNode] or None
# entry Entry
# base_classes [string]
# templates [string] or None
def analyse_declarations(self, env):
scope = None
if len(self.attributes) != 0:
scope = CppClassScope(self.name, env)
else:
self.attributes = None
base_class_types = []
for base_class_name in self.base_classes:
base_class_entry = env.lookup(base_class_name)
if base_class_entry is None:
error(self.pos, "'%s' not found" % base_class_name)
elif not base_class_entry.is_type or not base_class_entry.type.is_cpp_class:
error(self.pos, "'%s' is not a cpp class type" % base_class_name)
else:
base_class_types.append(base_class_entry.type)
if self.templates is None:
template_types = None
else:
template_types = [PyrexTypes.TemplatePlaceholderType(template_name) for template_name in self.templates]
self.entry = env.declare_cpp_class(
self.name, scope, self.pos,
self.cname, base_class_types, visibility = self.visibility, templates = template_types)
self.entry.is_cpp_class = 1
if self.attributes is not None:
if self.in_pxd and not env.in_cinclude:
self.entry.defined_in_pxd = 1
for attr in self.attributes:
attr.analyse_declarations(scope)
class CEnumDefNode(StatNode): class CEnumDefNode(StatNode):
# name string or None # name string or None
# cname string or None # cname string or None
...@@ -1936,7 +2064,7 @@ class DefNode(FuncDefNode): ...@@ -1936,7 +2064,7 @@ class DefNode(FuncDefNode):
code.putln( code.putln(
'static char %s[] = "%s";' % ( 'static char %s[] = "%s";' % (
self.entry.doc_cname, self.entry.doc_cname,
split_docstring(escape_byte_string(docstr)))) split_string_literal(escape_byte_string(docstr))))
if with_pymethdef: if with_pymethdef:
code.put( code.put(
"static PyMethodDef %s = " % "static PyMethodDef %s = " %
...@@ -3391,8 +3519,14 @@ class DelStatNode(StatNode): ...@@ -3391,8 +3519,14 @@ class DelStatNode(StatNode):
def analyse_expressions(self, env): def analyse_expressions(self, env):
for arg in self.args: for arg in self.args:
arg.analyse_target_expression(env, None) arg.analyse_target_expression(env, None)
if not arg.type.is_pyobject: if arg.type.is_pyobject:
error(arg.pos, "Deletion of non-Python object") pass
elif arg.type.is_ptr and arg.type.base_type.is_cpp_class:
self.cpp_check(env)
elif arg.type.is_cpp_class:
error(arg.pos, "Deletion of non-heap C++ object")
else:
error(arg.pos, "Deletion of non-Python, non-C++ object")
#arg.release_target_temp(env) #arg.release_target_temp(env)
def nogil_check(self, env): def nogil_check(self, env):
...@@ -3406,6 +3540,9 @@ class DelStatNode(StatNode): ...@@ -3406,6 +3540,9 @@ class DelStatNode(StatNode):
for arg in self.args: for arg in self.args:
if arg.type.is_pyobject: if arg.type.is_pyobject:
arg.generate_deletion_code(code) arg.generate_deletion_code(code)
elif arg.type.is_ptr and arg.type.base_type.is_cpp_class:
arg.generate_result_code(code)
code.putln("delete %s;" % arg.result())
# else error reported earlier # else error reported earlier
def annotate(self, code): def annotate(self, code):
...@@ -4041,7 +4178,7 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -4041,7 +4178,7 @@ class ForFromStatNode(LoopNode, StatNode):
target_node = ExprNodes.PyTempNode(self.target.pos, None) target_node = ExprNodes.PyTempNode(self.target.pos, None)
target_node.allocate(code) target_node.allocate(code)
interned_cname = code.intern_identifier(self.target.entry.name) interned_cname = code.intern_identifier(self.target.entry.name)
code.putln("/*here*/") code.globalstate.use_utility_code(ExprNodes.get_name_interned_utility_code)
code.putln("%s = __Pyx_GetName(%s, %s); %s" % ( code.putln("%s = __Pyx_GetName(%s, %s); %s" % (
target_node.result(), target_node.result(),
Naming.module_cname, Naming.module_cname,
...@@ -4767,7 +4904,9 @@ class FromImportStatNode(StatNode): ...@@ -4767,7 +4904,9 @@ class FromImportStatNode(StatNode):
break break
else: else:
entry = env.lookup(target.name) entry = env.lookup(target.name)
if entry.is_type and entry.type.name == name and entry.type.module_name == self.module.module_name.value: if (entry.is_type and
entry.type.name == name and
entry.type.module_name == self.module.module_name.value):
continue # already cimported continue # already cimported
target.analyse_target_expression(env, None) target.analyse_target_expression(env, None)
if target.type is py_object_type: if target.type is py_object_type:
......
...@@ -89,10 +89,12 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -89,10 +89,12 @@ class IterationTransform(Visitor.VisitorTransform):
return self._transform_dict_iteration( return self._transform_dict_iteration(
node, dict_obj=iterator, keys=True, values=False) node, dict_obj=iterator, keys=True, values=False)
# C array slice iteration? # C array (slice) iteration?
if isinstance(iterator, ExprNodes.SliceIndexNode) and \ if isinstance(iterator, ExprNodes.SliceIndexNode) and \
(iterator.base.type.is_array or iterator.base.type.is_ptr): (iterator.base.type.is_array or iterator.base.type.is_ptr):
return self._transform_carray_iteration(node, iterator) return self._transform_carray_iteration(node, iterator)
elif iterator.type.is_array:
return self._transform_carray_iteration(node, iterator)
elif not isinstance(iterator, ExprNodes.SimpleCallNode): elif not isinstance(iterator, ExprNodes.SimpleCallNode):
return node return node
...@@ -131,13 +133,26 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -131,13 +133,26 @@ class IterationTransform(Visitor.VisitorTransform):
return node return node
def _transform_carray_iteration(self, node, slice_node): def _transform_carray_iteration(self, node, slice_node):
if isinstance(slice_node, ExprNodes.SliceIndexNode):
slice_base = slice_node.base
start = slice_node.start start = slice_node.start
stop = slice_node.stop stop = slice_node.stop
step = None step = None
if not stop: if not stop:
return node return node
elif slice_node.type.is_array and slice_node.type.size is not None:
slice_base = slice_node
start = None
stop = ExprNodes.IntNode(
slice_node.pos, value=str(slice_node.type.size))
step = None
else:
return node
carray_ptr = slice_node.base.coerce_to_simple(self.current_scope) ptr_type = slice_base.type
if ptr_type.is_array:
ptr_type = ptr_type.element_ptr_type()
carray_ptr = slice_base.coerce_to_simple(self.current_scope)
if start and start.constant_result != 0: if start and start.constant_result != 0:
start_ptr_node = ExprNodes.AddNode( start_ptr_node = ExprNodes.AddNode(
...@@ -145,7 +160,7 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -145,7 +160,7 @@ class IterationTransform(Visitor.VisitorTransform):
operand1=carray_ptr, operand1=carray_ptr,
operator='+', operator='+',
operand2=start, operand2=start,
type=carray_ptr.type) type=ptr_type)
else: else:
start_ptr_node = carray_ptr start_ptr_node = carray_ptr
...@@ -154,13 +169,13 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -154,13 +169,13 @@ class IterationTransform(Visitor.VisitorTransform):
operand1=carray_ptr, operand1=carray_ptr,
operator='+', operator='+',
operand2=stop, operand2=stop,
type=carray_ptr.type type=ptr_type
).coerce_to_simple(self.current_scope) ).coerce_to_simple(self.current_scope)
counter = UtilNodes.TempHandle(carray_ptr.type) counter = UtilNodes.TempHandle(ptr_type)
counter_temp = counter.ref(node.target.pos) counter_temp = counter.ref(node.target.pos)
if slice_node.base.type.is_string and node.target.type.is_pyobject: if slice_base.type.is_string and node.target.type.is_pyobject:
# special case: char* -> bytes # special case: char* -> bytes
target_value = ExprNodes.SliceIndexNode( target_value = ExprNodes.SliceIndexNode(
node.target.pos, node.target.pos,
...@@ -181,7 +196,7 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -181,7 +196,7 @@ class IterationTransform(Visitor.VisitorTransform):
type=PyrexTypes.c_int_type), type=PyrexTypes.c_int_type),
base=counter_temp, base=counter_temp,
is_buffer_access=False, is_buffer_access=False,
type=carray_ptr.type.base_type) type=ptr_type.base_type)
if target_value.type != node.target.type: if target_value.type != node.target.type:
target_value = target_value.coerce_to(node.target.type, target_value = target_value.coerce_to(node.target.type,
...@@ -1606,20 +1621,20 @@ impl = "" ...@@ -1606,20 +1621,20 @@ 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) {
#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. */
&& likely(PyList_GET_SIZE(L) > (((PyListObject*)L)->allocated >> 1))) { && likely(PyList_GET_SIZE(L) > (((PyListObject*)L)->allocated >> 1))) {
Py_SIZE(L) -= 1; Py_SIZE(L) -= 1;
return PyList_GET_ITEM(L, PyList_GET_SIZE(L)); return PyList_GET_ITEM(L, PyList_GET_SIZE(L));
} }
else { #endif
PyObject *r, *m; 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);
Py_DECREF(m); Py_DECREF(m);
return r; return r;
}
} }
""", """,
impl = "" impl = ""
...@@ -1632,6 +1647,7 @@ static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix); ...@@ -1632,6 +1647,7 @@ static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix);
impl = """ impl = """
static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix) { static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix) {
PyObject *r, *m, *t, *py_ix; PyObject *r, *m, *t, *py_ix;
#if PY_VERSION_HEX >= 0x02040000
if (likely(PyList_CheckExact(L))) { if (likely(PyList_CheckExact(L))) {
Py_ssize_t size = PyList_GET_SIZE(L); Py_ssize_t size = PyList_GET_SIZE(L);
if (likely(size > (((PyListObject*)L)->allocated >> 1))) { if (likely(size > (((PyListObject*)L)->allocated >> 1))) {
...@@ -1650,6 +1666,7 @@ static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix) { ...@@ -1650,6 +1666,7 @@ static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix) {
} }
} }
} }
#endif
py_ix = t = NULL; py_ix = t = NULL;
m = __Pyx_GetAttrString(L, "pop"); m = __Pyx_GetAttrString(L, "pop");
if (!m) goto bad; if (!m) goto bad;
......
...@@ -128,7 +128,6 @@ class PostParseError(CompileError): pass ...@@ -128,7 +128,6 @@ class PostParseError(CompileError): pass
# error strings checked by unit tests, so define them # error strings checked by unit tests, so define them
ERR_CDEF_INCLASS = 'Cannot assign default value to fields in cdef classes, structs or unions' ERR_CDEF_INCLASS = 'Cannot assign default value to fields in cdef classes, structs or unions'
ERR_BUF_LOCALONLY = 'Buffer types only allowed as function local variables'
ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)' ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)'
ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared' ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared'
class PostParse(CythonTransform): class PostParse(CythonTransform):
...@@ -145,7 +144,7 @@ class PostParse(CythonTransform): ...@@ -145,7 +144,7 @@ class PostParse(CythonTransform):
- Interpret some node structures into Python runtime values. - Interpret some node structures into Python runtime values.
Some nodes take compile-time arguments (currently: Some nodes take compile-time arguments (currently:
CBufferAccessTypeNode[args] and __cythonbufferdefaults__ = {args}), TemplatedTypeNode[args] and __cythonbufferdefaults__ = {args}),
which should be interpreted. This happens in a general way which should be interpreted. This happens in a general way
and other steps should be taken to ensure validity. and other steps should be taken to ensure validity.
...@@ -154,7 +153,7 @@ class PostParse(CythonTransform): ...@@ -154,7 +153,7 @@ class PostParse(CythonTransform):
- For __cythonbufferdefaults__ the arguments are checked for - For __cythonbufferdefaults__ the arguments are checked for
validity. validity.
CBufferAccessTypeNode has its directives interpreted: TemplatedTypeNode has its directives interpreted:
Any first positional argument goes into the "dtype" attribute, Any first positional argument goes into the "dtype" attribute,
any "ndim" keyword argument goes into the "ndim" attribute and any "ndim" keyword argument goes into the "ndim" attribute and
so on. Also it is checked that the directive combination is valid. so on. Also it is checked that the directive combination is valid.
...@@ -243,11 +242,6 @@ class PostParse(CythonTransform): ...@@ -243,11 +242,6 @@ class PostParse(CythonTransform):
self.context.nonfatal_error(e) self.context.nonfatal_error(e)
return None return None
def visit_CBufferAccessTypeNode(self, node):
if not self.scope_type == 'function':
raise PostParseError(node.pos, ERR_BUF_LOCALONLY)
return node
class PxdPostParse(CythonTransform, SkipDeclarations): class PxdPostParse(CythonTransform, SkipDeclarations):
""" """
Basic interpretation/validity checking that should only be Basic interpretation/validity checking that should only be
...@@ -329,7 +323,23 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -329,7 +323,23 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
duplication of functionality has to occur: We manually track cimports duplication of functionality has to occur: We manually track cimports
and which names the "cython" module may have been imported to. and which names the "cython" module may have been imported to.
""" """
special_methods = set(['declare', 'union', 'struct', 'typedef', 'sizeof', 'typeof', 'cast', 'address', 'pointer', 'compiled', 'NULL']) unop_method_nodes = {
'typeof': TypeofNode,
'operator.address': AmpersandNode,
'operator.dereference': DereferenceNode,
'operator.preincrement' : inc_dec_constructor(True, '++'),
'operator.predecrement' : inc_dec_constructor(True, '--'),
'operator.postincrement': inc_dec_constructor(False, '++'),
'operator.postdecrement': inc_dec_constructor(False, '--'),
# For backwards compatability.
'address': AmpersandNode,
}
special_methods = set(['declare', 'union', 'struct', 'typedef', 'sizeof',
'cast', 'pointer', 'compiled', 'NULL']
+ unop_method_nodes.keys())
def __init__(self, context, compilation_directive_defaults): def __init__(self, context, compilation_directive_defaults):
super(InterpretCompilerDirectives, self).__init__(context) super(InterpretCompilerDirectives, self).__init__(context)
...@@ -364,26 +374,37 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -364,26 +374,37 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
node.cython_module_names = self.cython_module_names node.cython_module_names = self.cython_module_names
return node return node
# Track cimports of the cython module. # The following four functions track imports and cimports that
# begin with "cython"
def is_cython_directive(self, name):
return (name in Options.directive_types or
name in self.special_methods or
PyrexTypes.parse_basic_type(name))
def visit_CImportStatNode(self, node): def visit_CImportStatNode(self, node):
if node.module_name == u"cython": if node.module_name == u"cython":
self.cython_module_names.add(node.as_name or u"cython")
elif node.module_name.startswith(u"cython."):
if node.as_name: if node.as_name:
modname = node.as_name self.directive_names[node.as_name] = node.module_name[7:]
else: else:
modname = u"cython" self.cython_module_names.add(u"cython")
self.cython_module_names.add(modname) # if this cimport was a compiler directive, we don't
# want to leave the cimport node sitting in the tree
return None
return node return node
def visit_FromCImportStatNode(self, node): def visit_FromCImportStatNode(self, node):
if node.module_name == u"cython": if (node.module_name == u"cython") or \
node.module_name.startswith(u"cython."):
submodule = (node.module_name + u".")[7:]
newimp = [] newimp = []
for pos, name, as_name, kind in node.imported_names: for pos, name, as_name, kind in node.imported_names:
if (name in Options.directive_types or full_name = submodule + name
name in self.special_methods or if self.is_cython_directive(full_name):
PyrexTypes.parse_basic_type(name)):
if as_name is None: if as_name is None:
as_name = name as_name = full_name
self.directive_names[as_name] = name self.directive_names[as_name] = full_name
if kind is not None: if kind is not None:
self.context.nonfatal_error(PostParseError(pos, self.context.nonfatal_error(PostParseError(pos,
"Compiler directive imports must be plain imports")) "Compiler directive imports must be plain imports"))
...@@ -395,13 +416,14 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -395,13 +416,14 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
return node return node
def visit_FromImportStatNode(self, node): def visit_FromImportStatNode(self, node):
if node.module.module_name.value == u"cython": if (node.module.module_name.value == u"cython") or \
node.module.module_name.value.startswith(u"cython."):
submodule = (node.module.module_name.value + u".")[7:]
newimp = [] newimp = []
for name, name_node in node.items: for name, name_node in node.items:
if (name in Options.directive_types or full_name = submodule + name
name in self.special_methods or if self.is_cython_directive(full_name):
PyrexTypes.parse_basic_type(name)): self.directive_names[name_node.name] = full_name
self.directive_names[name_node.name] = name
else: else:
newimp.append((name, name_node)) newimp.append((name, name_node))
if not newimp: if not newimp:
...@@ -1016,7 +1038,12 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -1016,7 +1038,12 @@ class TransformBuiltinMethods(EnvTransform):
# cython.foo # cython.foo
function = node.function.as_cython_attribute() function = node.function.as_cython_attribute()
if function: if function:
if function == u'cast': if function in InterpretCompilerDirectives.unop_method_nodes:
if len(node.args) != 1:
error(node.function.pos, u"%s() takes exactly one argument" % function)
else:
node = InterpretCompilerDirectives.unop_method_nodes[function](node.function.pos, operand=node.args[0])
elif function == u'cast':
if len(node.args) != 2: if len(node.args) != 2:
error(node.function.pos, u"cast() takes exactly two arguments") error(node.function.pos, u"cast() takes exactly two arguments")
else: else:
...@@ -1034,16 +1061,6 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -1034,16 +1061,6 @@ class TransformBuiltinMethods(EnvTransform):
node = SizeofTypeNode(node.function.pos, arg_type=type) node = SizeofTypeNode(node.function.pos, arg_type=type)
else: else:
node = SizeofVarNode(node.function.pos, operand=node.args[0]) node = SizeofVarNode(node.function.pos, operand=node.args[0])
elif function == 'typeof':
if len(node.args) != 1:
error(node.function.pos, u"typeof() takes exactly one argument")
else:
node = TypeofNode(node.function.pos, operand=node.args[0])
elif function == 'address':
if len(node.args) != 1:
error(node.function.pos, u"address() takes exactly one argument")
else:
node = AmpersandNode(node.function.pos, operand=node.args[0])
elif function == 'cmod': elif function == 'cmod':
if len(node.args) != 2: if len(node.args) != 2:
error(node.function.pos, u"cmod() takes exactly two arguments") error(node.function.pos, u"cmod() takes exactly two arguments")
......
...@@ -28,6 +28,7 @@ cpdef p_typecast(PyrexScanner s) ...@@ -28,6 +28,7 @@ cpdef p_typecast(PyrexScanner s)
cpdef p_sizeof(PyrexScanner s) cpdef p_sizeof(PyrexScanner s)
cpdef p_yield_expression(PyrexScanner s) cpdef p_yield_expression(PyrexScanner s)
cpdef p_power(PyrexScanner s) cpdef p_power(PyrexScanner s)
cpdef p_new_expr(PyrexScanner s)
cpdef p_trailer(PyrexScanner s, node1) cpdef p_trailer(PyrexScanner s, node1)
cpdef p_call(PyrexScanner s, function) cpdef p_call(PyrexScanner s, function)
cpdef p_index(PyrexScanner s, base) cpdef p_index(PyrexScanner s, base)
...@@ -99,13 +100,13 @@ cpdef p_IF_statement(PyrexScanner s, ctx) ...@@ -99,13 +100,13 @@ cpdef p_IF_statement(PyrexScanner s, ctx)
cpdef p_statement(PyrexScanner s, ctx, bint first_statement = *) cpdef p_statement(PyrexScanner s, ctx, bint first_statement = *)
cpdef p_statement_list(PyrexScanner s, ctx, bint first_statement = *) cpdef p_statement_list(PyrexScanner s, ctx, bint first_statement = *)
cpdef p_suite(PyrexScanner s, ctx = *, bint with_doc = *, bint with_pseudo_doc = *) cpdef p_suite(PyrexScanner s, ctx = *, bint with_doc = *, bint with_pseudo_doc = *)
cpdef p_positional_and_keyword_args(PyrexScanner s, end_sy_set, type_positions= *, type_keywords= * ) cpdef p_positional_and_keyword_args(PyrexScanner s, end_sy_set, templates = *)
cpdef p_c_base_type(PyrexScanner s, bint self_flag = *, bint nonempty = *) cpdef p_c_base_type(PyrexScanner s, bint self_flag = *, bint nonempty = *, templates = *)
cpdef p_calling_convention(PyrexScanner s) cpdef p_calling_convention(PyrexScanner s)
cpdef p_c_complex_base_type(PyrexScanner s) cpdef p_c_complex_base_type(PyrexScanner s)
cpdef p_c_simple_base_type(PyrexScanner s, self_flag, nonempty) cpdef p_c_simple_base_type(PyrexScanner s, bint self_flag, bint nonempty, templates = *)
cpdef p_buffer_access(PyrexScanner s, base_type_node) cpdef p_buffer_or_template(PyrexScanner s, base_type_node, templates)
cpdef bint looking_at_name(PyrexScanner s) except -2 cpdef bint looking_at_name(PyrexScanner s) except -2
cpdef bint looking_at_expr(PyrexScanner s) except -2 cpdef bint looking_at_expr(PyrexScanner s) except -2
cpdef bint looking_at_base_type(PyrexScanner s) except -2 cpdef bint looking_at_base_type(PyrexScanner s) except -2
...@@ -149,3 +150,4 @@ cpdef p_doc_string(PyrexScanner s) ...@@ -149,3 +150,4 @@ cpdef p_doc_string(PyrexScanner s)
cpdef p_code(PyrexScanner s, level= *) cpdef p_code(PyrexScanner s, level= *)
cpdef p_compiler_directive_comments(PyrexScanner s) cpdef p_compiler_directive_comments(PyrexScanner s)
cpdef p_module(PyrexScanner s, pxd, full_module_name) cpdef p_module(PyrexScanner s, pxd, full_module_name)
cpdef p_cpp_class_definition(PyrexScanner s, pos, ctx)
...@@ -10,6 +10,15 @@ cython.declare(Nodes=object, ExprNodes=object, EncodedString=object) ...@@ -10,6 +10,15 @@ cython.declare(Nodes=object, ExprNodes=object, EncodedString=object)
import os import os
import re import re
import sys import sys
try:
from __builtin__ import set
except ImportError:
try:
from builtins import set
except ImportError:
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
...@@ -30,6 +39,8 @@ class Ctx(object): ...@@ -30,6 +39,8 @@ class Ctx(object):
api = 0 api = 0
overridable = 0 overridable = 0
nogil = 0 nogil = 0
namespace = None
templates = None
def __init__(self, **kwds): def __init__(self, **kwds):
self.__dict__.update(kwds) self.__dict__.update(kwds)
...@@ -298,6 +309,8 @@ def p_yield_expression(s): ...@@ -298,6 +309,8 @@ def p_yield_expression(s):
#power: atom trailer* ('**' factor)* #power: atom trailer* ('**' factor)*
def p_power(s): def p_power(s):
if s.systring == 'new' and s.peek()[0] == 'IDENT':
return p_new_expr(s)
n1 = p_atom(s) n1 = p_atom(s)
while s.sy in ('(', '[', '.'): while s.sy in ('(', '[', '.'):
n1 = p_trailer(s, n1) n1 = p_trailer(s, n1)
...@@ -308,6 +321,19 @@ def p_power(s): ...@@ -308,6 +321,19 @@ def p_power(s):
n1 = ExprNodes.binop_node(pos, '**', n1, n2) n1 = ExprNodes.binop_node(pos, '**', n1, n2)
return n1 return n1
def p_new_expr(s):
# s.systring == 'new'.
pos = s.position()
s.next()
name = p_ident(s)
if s.sy == '[':
s.next()
template_parameters = p_simple_expr_list(s)
s.expect(']')
else:
template_parameters = None
return p_call(s, ExprNodes.NewExprNode(pos, cppclass = name, template_parameters = template_parameters))
#trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME #trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
def p_trailer(s, node1): def p_trailer(s, node1):
...@@ -1458,6 +1484,29 @@ def p_with_statement(s): ...@@ -1458,6 +1484,29 @@ def p_with_statement(s):
s.next() s.next()
body = p_suite(s) body = p_suite(s)
return Nodes.GILStatNode(pos, state = state, body = body) return Nodes.GILStatNode(pos, state = state, body = body)
elif s.systring == 'template':
templates = []
s.next()
s.expect('[')
#s.next()
templates.append(s.systring)
s.next()
while s.systring == ',':
s.next()
templates.append(s.systring)
s.next()
s.expect(']')
if s.sy == ':':
s.next()
s.expect_newline("Syntax error in template function declaration")
s.expect_indent()
body_ctx = Ctx()
body_ctx.templates = templates
func_or_var = p_c_func_or_var_declaration(s, pos, body_ctx)
s.expect_dedent()
return func_or_var
else:
error(pos, "Syntax error in template function declaration")
else: else:
manager = p_expr(s) manager = p_expr(s)
target = None target = None
...@@ -1683,16 +1732,12 @@ def p_suite(s, ctx = Ctx(), with_doc = 0, with_pseudo_doc = 0): ...@@ -1683,16 +1732,12 @@ def p_suite(s, ctx = Ctx(), with_doc = 0, with_pseudo_doc = 0):
else: else:
return body return body
def p_positional_and_keyword_args(s, end_sy_set, type_positions=(), type_keywords=()): def p_positional_and_keyword_args(s, end_sy_set, templates = None):
""" """
Parses positional and keyword arguments. end_sy_set Parses positional and keyword arguments. end_sy_set
should contain any s.sy that terminate the argument list. should contain any s.sy that terminate the argument list.
Argument expansion (* and **) are not allowed. Argument expansion (* and **) are not allowed.
type_positions and type_keywords specifies which argument
positions and/or names which should be interpreted as
types. Other arguments will be treated as expressions.
Returns: (positional_args, keyword_args) Returns: (positional_args, keyword_args)
""" """
positional_args = [] positional_args = []
...@@ -1703,35 +1748,33 @@ def p_positional_and_keyword_args(s, end_sy_set, type_positions=(), type_keyword ...@@ -1703,35 +1748,33 @@ def p_positional_and_keyword_args(s, end_sy_set, type_positions=(), type_keyword
if s.sy == '*' or s.sy == '**': if s.sy == '*' or s.sy == '**':
s.error('Argument expansion not allowed here.') s.error('Argument expansion not allowed here.')
was_keyword = False
parsed_type = False parsed_type = False
if s.sy == 'IDENT': if s.sy == 'IDENT' and s.peek()[0] == '=':
# Since we can have either types or expressions as positional args,
# we use a strategy of looking an extra step forward for a '=' and
# if it is a positional arg we backtrack.
ident = s.systring ident = s.systring
s.next() # s.sy is '='
s.next() s.next()
if s.sy == '=': if looking_at_expr(s):
s.next()
# Is keyword arg
if ident in type_keywords:
arg = p_c_base_type(s)
parsed_type = True
else:
arg = p_simple_expr(s) arg = p_simple_expr(s)
else:
base_type = p_c_base_type(s, templates = templates)
declarator = p_c_declarator(s, empty = 1)
arg = Nodes.CComplexBaseTypeNode(base_type.pos,
base_type = base_type, declarator = declarator)
parsed_type = True
keyword_node = ExprNodes.IdentifierStringNode( keyword_node = ExprNodes.IdentifierStringNode(
arg.pos, value = EncodedString(ident)) arg.pos, value = EncodedString(ident))
keyword_args.append((keyword_node, arg)) keyword_args.append((keyword_node, arg))
was_keyword = True was_keyword = True
else:
s.put_back('IDENT', ident)
if not was_keyword:
if pos_idx in type_positions:
arg = p_c_base_type(s)
parsed_type = True
else: else:
if looking_at_expr(s):
arg = p_simple_expr(s) arg = p_simple_expr(s)
else:
base_type = p_c_base_type(s, templates = templates)
declarator = p_c_declarator(s, empty = 1)
arg = Nodes.CComplexBaseTypeNode(base_type.pos,
base_type = base_type, declarator = declarator)
parsed_type = True
positional_args.append(arg) positional_args.append(arg)
pos_idx += 1 pos_idx += 1
if len(keyword_args) > 0: if len(keyword_args) > 0:
...@@ -1741,20 +1784,18 @@ def p_positional_and_keyword_args(s, end_sy_set, type_positions=(), type_keyword ...@@ -1741,20 +1784,18 @@ def p_positional_and_keyword_args(s, end_sy_set, type_positions=(), type_keyword
if s.sy != ',': if s.sy != ',':
if s.sy not in end_sy_set: if s.sy not in end_sy_set:
if parsed_type: if parsed_type:
s.error("Expected: type") s.error("Unmatched %s" % " or ".join(end_sy_set))
else:
s.error("Expected: expression")
break break
s.next() s.next()
return positional_args, keyword_args return positional_args, keyword_args
def p_c_base_type(s, self_flag = 0, nonempty = 0): def p_c_base_type(s, self_flag = 0, nonempty = 0, templates = None):
# If self_flag is true, this is the base type for the # If self_flag is true, this is the base type for the
# self argument of a C method of an extension type. # self argument of a C method of an extension type.
if s.sy == '(': if s.sy == '(':
return p_c_complex_base_type(s) return p_c_complex_base_type(s)
else: else:
return p_c_simple_base_type(s, self_flag, nonempty = nonempty) return p_c_simple_base_type(s, self_flag, nonempty = nonempty, templates = templates)
def p_calling_convention(s): def p_calling_convention(s):
if s.sy == 'IDENT' and s.systring in calling_convention_words: if s.sy == 'IDENT' and s.systring in calling_convention_words:
...@@ -1776,7 +1817,7 @@ def p_c_complex_base_type(s): ...@@ -1776,7 +1817,7 @@ def p_c_complex_base_type(s):
return Nodes.CComplexBaseTypeNode(pos, return Nodes.CComplexBaseTypeNode(pos,
base_type = base_type, declarator = declarator) base_type = base_type, declarator = declarator)
def p_c_simple_base_type(s, self_flag, nonempty): def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
#print "p_c_simple_base_type: self_flag =", self_flag, nonempty #print "p_c_simple_base_type: self_flag =", self_flag, nonempty
is_basic = 0 is_basic = 0
signed = 1 signed = 1
...@@ -1832,26 +1873,22 @@ def p_c_simple_base_type(s, self_flag, nonempty): ...@@ -1832,26 +1873,22 @@ def p_c_simple_base_type(s, self_flag, nonempty):
name = name, module_path = module_path, name = name, module_path = module_path,
is_basic_c_type = is_basic, signed = signed, is_basic_c_type = is_basic, signed = signed,
complex = complex, longness = longness, complex = complex, longness = longness,
is_self_arg = self_flag) is_self_arg = self_flag, templates = templates)
# Treat trailing [] on type as buffer access if it appears in a context if s.sy == '[':
# where declarator names are required (so that it cannot mean int[] or return p_buffer_or_template(s, type_node, templates)
# sizeof(int[SIZE]))...
#
# (This means that buffers cannot occur where there can be empty declarators,
# which is an ok restriction to make.)
if nonempty and s.sy == '[':
return p_buffer_access(s, type_node)
else: else:
return type_node return type_node
def p_buffer_access(s, base_type_node): def p_buffer_or_template(s, base_type_node, templates):
# s.sy == '[' # s.sy == '['
pos = s.position() pos = s.position()
s.next() s.next()
# Note that buffer_positional_options_count=1, so the only positional argument is dtype.
# For templated types, all parameters are types.
positional_args, keyword_args = ( positional_args, keyword_args = (
p_positional_and_keyword_args(s, (']',), (0,), ('dtype',)) p_positional_and_keyword_args(s, (']',), templates)
) )
s.expect(']') s.expect(']')
...@@ -1860,8 +1897,7 @@ def p_buffer_access(s, base_type_node): ...@@ -1860,8 +1897,7 @@ def p_buffer_access(s, base_type_node):
ExprNodes.DictItemNode(pos=key.pos, key=key, value=value) ExprNodes.DictItemNode(pos=key.pos, key=key, value=value)
for key, value in keyword_args for key, value in keyword_args
]) ])
result = Nodes.TemplatedTypeNode(pos,
result = Nodes.CBufferAccessTypeNode(pos,
positional_args = positional_args, positional_args = positional_args,
keyword_args = keyword_dict, keyword_args = keyword_dict,
base_type_node = base_type_node) base_type_node = base_type_node)
...@@ -2018,6 +2054,13 @@ def p_c_func_declarator(s, pos, ctx, base, cmethod_flag): ...@@ -2018,6 +2054,13 @@ 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([
'+', '-', '*', '/', '%',
'++', '--', '~', '|', '&', '^', '<<', '>>',
'==', '!=', '>=', '>', '<=', '<',
'[]', '()',
])
def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag, def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
assignable, nonempty): assignable, nonempty):
pos = s.position() pos = s.position()
...@@ -2037,6 +2080,12 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag, ...@@ -2037,6 +2080,12 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
result = Nodes.CPtrDeclaratorNode(pos, result = Nodes.CPtrDeclaratorNode(pos,
base = Nodes.CPtrDeclaratorNode(pos, base = Nodes.CPtrDeclaratorNode(pos,
base = base)) base = base))
elif s.sy == '&':
s.next()
base = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
cmethod_flag = cmethod_flag,
assignable = assignable, nonempty = nonempty)
result = Nodes.CReferenceDeclaratorNode(pos, base = base)
else: else:
rhs = None rhs = None
if s.sy == 'IDENT': if s.sy == 'IDENT':
...@@ -2053,6 +2102,27 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag, ...@@ -2053,6 +2102,27 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
error(s.position(), "Empty declarator") error(s.position(), "Empty declarator")
name = "" name = ""
cname = None cname = None
if cname is None and ctx.namespace is not None:
cname = ctx.namespace + "::" + name
if name == 'operator' and ctx.visibility == 'extern':
op = s.sy
s.next()
# Handle diphthong operators.
if op == '(':
s.expect(')')
op = '()'
elif op == '[':
s.expect(']')
op = '[]'
if op in ['-', '+', '|', '&'] and s.sy == op:
op = op*2
s.next()
if s.sy == '=':
op += s.sy
s.next()
if op not in supported_overloaded_operators:
s.error("Overloading operator '%s' not yet supported." % op)
name = name+op
result = Nodes.CNameDeclaratorNode(pos, result = Nodes.CNameDeclaratorNode(pos,
name = name, cname = cname, default = rhs) name = name, cname = cname, default = rhs)
result.calling_convention = calling_convention result.calling_convention = calling_convention
...@@ -2184,6 +2254,10 @@ def p_cdef_statement(s, ctx): ...@@ -2184,6 +2254,10 @@ def p_cdef_statement(s, ctx):
if ctx.overridable: if ctx.overridable:
error(pos, "Extension types cannot be declared cpdef") error(pos, "Extension types cannot be declared cpdef")
return p_c_class_definition(s, pos, ctx) return p_c_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring == 'cppclass':
if ctx.visibility != 'extern':
error(pos, "C++ classes need to be declared extern")
return p_cpp_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring in ("struct", "union", "enum", "packed"): elif s.sy == 'IDENT' and s.systring in ("struct", "union", "enum", "packed"):
if ctx.level not in ('module', 'module_pxd'): if ctx.level not in ('module', 'module_pxd'):
error(pos, "C struct/union/enum definition not allowed here") error(pos, "C struct/union/enum definition not allowed here")
...@@ -2208,13 +2282,17 @@ def p_cdef_extern_block(s, pos, ctx): ...@@ -2208,13 +2282,17 @@ 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)
if s.systring == "namespace":
s.next()
ctx.namespace = p_dotted_name(s, as_allowed=False)[2].replace('.', '::')
ctx = ctx(cdef_flag = 1, visibility = 'extern') 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)
return Nodes.CDefExternNode(pos, return Nodes.CDefExternNode(pos,
include_file = include_file, include_file = include_file,
body = body) body = body,
namespace = ctx.namespace)
def p_c_enum_definition(s, pos, ctx): def p_c_enum_definition(s, pos, ctx):
# s.sy == ident 'enum' # s.sy == ident 'enum'
...@@ -2223,6 +2301,8 @@ def p_c_enum_definition(s, pos, ctx): ...@@ -2223,6 +2301,8 @@ def p_c_enum_definition(s, pos, ctx):
name = s.systring name = s.systring
s.next() s.next()
cname = p_opt_cname(s) cname = p_opt_cname(s)
if cname is None and ctx.namespace is not None:
cname = ctx.namespace + "::" + name
else: else:
name = None name = None
cname = None cname = None
...@@ -2277,6 +2357,8 @@ def p_c_struct_or_union_definition(s, pos, ctx): ...@@ -2277,6 +2357,8 @@ def p_c_struct_or_union_definition(s, pos, ctx):
s.next() s.next()
name = p_ident(s) name = p_ident(s)
cname = p_opt_cname(s) cname = p_opt_cname(s)
if cname is None and ctx.namespace is not None:
cname = ctx.namespace + "::" + name
attributes = None attributes = None
if s.sy == ':': if s.sy == ':':
s.next() s.next()
...@@ -2320,12 +2402,12 @@ def p_c_modifiers(s): ...@@ -2320,12 +2402,12 @@ def p_c_modifiers(s):
def p_c_func_or_var_declaration(s, pos, ctx): def p_c_func_or_var_declaration(s, pos, ctx):
cmethod_flag = ctx.level in ('c_class', 'c_class_pxd') cmethod_flag = ctx.level in ('c_class', 'c_class_pxd')
modifiers = p_c_modifiers(s) modifiers = p_c_modifiers(s)
base_type = p_c_base_type(s, nonempty = 1) base_type = p_c_base_type(s, nonempty = 1, templates = ctx.templates)
declarator = p_c_declarator(s, ctx, cmethod_flag = cmethod_flag, declarator = p_c_declarator(s, ctx, cmethod_flag = cmethod_flag,
assignable = 1, nonempty = 1) assignable = 1, nonempty = 1)
declarator.overridable = ctx.overridable declarator.overridable = ctx.overridable
if s.sy == ':': if s.sy == ':':
if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd'): if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd') and not ctx.templates:
s.error("C function definition not allowed here") s.error("C function definition not allowed here")
doc, suite = p_suite(s, Ctx(level = 'function'), with_doc = 1) doc, suite = p_suite(s, Ctx(level = 'function'), with_doc = 1)
result = Nodes.CFuncDefNode(pos, result = Nodes.CFuncDefNode(pos,
...@@ -2615,6 +2697,64 @@ def p_module(s, pxd, full_module_name): ...@@ -2615,6 +2697,64 @@ def p_module(s, pxd, full_module_name):
full_module_name = full_module_name, full_module_name = full_module_name,
directive_comments = directive_comments) directive_comments = directive_comments)
def p_cpp_class_definition(s, pos, ctx):
# s.sy == 'cppclass'
s.next()
module_path = []
class_name = p_ident(s)
cname = p_opt_cname(s)
if cname is None and ctx.namespace is not None:
cname = ctx.namespace + "::" + class_name
if s.sy == '.':
error(pos, "Qualified class name not allowed C++ class")
if s.sy == '[':
s.next()
templates = [p_ident(s)]
while s.sy == ',':
s.next()
templates.append(p_ident(s))
s.expect(']')
else:
templates = None
if s.sy == '(':
s.next()
base_classes = [p_dotted_name(s, False)[2]]
while s.sy == ',':
s.next()
base_classes.append(p_dotted_name(s, False)[2])
s.expect(')')
else:
base_classes = []
if s.sy == '[':
error(s.position(), "Name options not allowed for C++ class")
if s.sy == ':':
s.next()
s.expect('NEWLINE')
s.expect_indent()
attributes = []
body_ctx = Ctx(visibility = ctx.visibility)
body_ctx.templates = templates
while s.sy != 'DEDENT':
if s.sy != 'pass':
attributes.append(
p_c_func_or_var_declaration(s, s.position(), body_ctx))
else:
s.next()
s.expect_newline("Expected a newline")
s.expect_dedent()
else:
s.expect_newline("Syntax error in C++ class definition")
return Nodes.CppClassNode(pos,
name = class_name,
cname = cname,
base_classes = base_classes,
visibility = ctx.visibility,
in_pxd = ctx.level == 'module_pxd',
attributes = attributes,
templates = templates)
#---------------------------------------------- #----------------------------------------------
# #
# Debugging # Debugging
......
# #
# Pyrex - Types # Pyrex - Types
# #
...@@ -6,6 +8,7 @@ from Code import UtilityCode ...@@ -6,6 +8,7 @@ from Code import UtilityCode
import StringEncoding import StringEncoding
import Naming import Naming
import copy import copy
from Errors import error
class BaseType(object): class BaseType(object):
# #
...@@ -40,6 +43,7 @@ class PyrexType(BaseType): ...@@ -40,6 +43,7 @@ class PyrexType(BaseType):
# is_array boolean Is a C array type # is_array boolean Is a C array type
# is_ptr boolean Is a C pointer type # is_ptr boolean Is a C pointer type
# is_null_ptr boolean Is the type of NULL # is_null_ptr boolean Is the type of NULL
# is_reference boolean Is a C reference type
# is_cfunction boolean Is a C function type # is_cfunction boolean Is a C function type
# is_struct_or_union boolean Is a C struct or union type # is_struct_or_union boolean Is a C struct or union type
# is_struct boolean Is a C struct type # is_struct boolean Is a C struct type
...@@ -91,8 +95,10 @@ class PyrexType(BaseType): ...@@ -91,8 +95,10 @@ class PyrexType(BaseType):
is_array = 0 is_array = 0
is_ptr = 0 is_ptr = 0
is_null_ptr = 0 is_null_ptr = 0
is_reference = 0
is_cfunction = 0 is_cfunction = 0
is_struct_or_union = 0 is_struct_or_union = 0
is_cpp_class = 0
is_struct = 0 is_struct = 0
is_enum = 0 is_enum = 0
is_typedef = 0 is_typedef = 0
...@@ -109,6 +115,10 @@ class PyrexType(BaseType): ...@@ -109,6 +115,10 @@ class PyrexType(BaseType):
# If a typedef, returns the base type. # If a typedef, returns the base type.
return self return self
def specialize(self, values):
# TODO(danilo): Override wherever it makes sense.
return self
def literal_code(self, value): def literal_code(self, value):
# Returns a C code fragment representing a literal # Returns a C code fragment representing a literal
# value of this type. # value of this type.
...@@ -1328,16 +1338,63 @@ class CPtrType(CType): ...@@ -1328,16 +1338,63 @@ class CPtrType(CType):
return self.base_type.pointer_assignable_from_resolved_type(other_type) return self.base_type.pointer_assignable_from_resolved_type(other_type)
else: else:
return 0 return 0
if (self.base_type.is_cpp_class and other_type.is_ptr
and other_type.base_type.is_cpp_class and other_type.base_type.is_subclass(self.base_type)):
return 1
if other_type.is_array or other_type.is_ptr: if other_type.is_array or other_type.is_ptr:
return self.base_type.is_void or self.base_type.same_as(other_type.base_type) return self.base_type.is_void or self.base_type.same_as(other_type.base_type)
return 0 return 0
def specialize(self, values):
base_type = self.base_type.specialize(values)
if base_type == self.base_type:
return self
else:
return CPtrType(base_type)
class CNullPtrType(CPtrType): class CNullPtrType(CPtrType):
is_null_ptr = 1 is_null_ptr = 1
class CReferenceType(CType):
is_reference = 1
def __init__(self, base_type):
self.base_type = base_type
def __repr__(self):
return "<CReferenceType %s>" % repr(self.base_type)
def same_as_resolved_type(self, other_type):
return other_type.is_reference and self.base_type.same_as(other_type.base_type)
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
#print "CReferenceType.declaration_code: pointer to", self.base_type ###
return self.base_type.declaration_code(
"&%s" % entity_code,
for_display, dll_linkage, pyrex)
def assignable_from_resolved_type(self, other_type):
if other_type is error_type:
return 1
elif other_type.is_reference and self.base_type == other_type.base_type:
return 1
elif other_type == self.base_type:
return 1
else: #for now
return 0
def specialize(self, values):
base_type = self.base_type.specialize(values)
if base_type == self.base_type:
return self
else:
return CReferenceType(base_type)
class CFuncType(CType): class CFuncType(CType):
# return_type CType # return_type CType
# args [CFuncTypeArg] # args [CFuncTypeArg]
...@@ -1347,13 +1404,15 @@ class CFuncType(CType): ...@@ -1347,13 +1404,15 @@ class CFuncType(CType):
# calling_convention string Function calling convention # calling_convention string Function calling convention
# nogil boolean Can be called without gil # nogil boolean Can be called without gil
# with_gil boolean Acquire gil around function body # with_gil boolean Acquire gil around function body
# templates [string] or None
is_cfunction = 1 is_cfunction = 1
original_sig = None original_sig = None
def __init__(self, return_type, args, has_varargs = 0, def __init__(self, return_type, args, has_varargs = 0,
exception_value = None, exception_check = 0, calling_convention = "", exception_value = None, exception_check = 0, calling_convention = "",
nogil = 0, with_gil = 0, is_overridable = 0, optional_arg_count = 0): nogil = 0, with_gil = 0, is_overridable = 0, optional_arg_count = 0,
templates = None):
self.return_type = return_type self.return_type = return_type
self.args = args self.args = args
self.has_varargs = has_varargs self.has_varargs = has_varargs
...@@ -1364,6 +1423,7 @@ class CFuncType(CType): ...@@ -1364,6 +1423,7 @@ class CFuncType(CType):
self.nogil = nogil self.nogil = nogil
self.with_gil = with_gil self.with_gil = with_gil
self.is_overridable = is_overridable self.is_overridable = is_overridable
self.templates = templates
def __repr__(self): def __repr__(self):
arg_reprs = map(repr, self.args) arg_reprs = map(repr, self.args)
...@@ -1567,6 +1627,23 @@ class CFuncType(CType): ...@@ -1567,6 +1627,23 @@ class CFuncType(CType):
s = self.declaration_code("(*)", with_calling_convention=False) s = self.declaration_code("(*)", with_calling_convention=False)
return '(%s)' % s return '(%s)' % s
def specialize(self, values):
if self.templates is None:
new_templates = None
else:
new_templates = [v.specialize(values) for v in self.templates]
return CFuncType(self.return_type.specialize(values),
[arg.specialize(values) for arg in self.args],
has_varargs = 0,
exception_value = self.exception_value,
exception_check = self.exception_check,
calling_convention = self.calling_convention,
nogil = self.nogil,
with_gil = self.with_gil,
is_overridable = self.is_overridable,
optional_arg_count = self.optional_arg_count,
templates = new_templates)
def opt_arg_cname(self, arg_name): def opt_arg_cname(self, arg_name):
return self.op_arg_struct.base_type.scope.lookup(arg_name).cname return self.op_arg_struct.base_type.scope.lookup(arg_name).cname
...@@ -1594,6 +1671,9 @@ class CFuncTypeArg(object): ...@@ -1594,6 +1671,9 @@ class CFuncTypeArg(object):
def declaration_code(self, for_display = 0): def declaration_code(self, for_display = 0):
return self.type.declaration_code(self.cname, for_display) return self.type.declaration_code(self.cname, for_display)
def specialize(self, values):
return CFuncTypeArg(self.name, self.type.specialize(values), self.pos, self.cname)
class StructUtilityCode(object): class StructUtilityCode(object):
def __init__(self, type, forward_decl): def __init__(self, type, forward_decl):
self.type = type self.type = type
...@@ -1732,6 +1812,124 @@ class CStructOrUnionType(CType): ...@@ -1732,6 +1812,124 @@ class CStructOrUnionType(CType):
for x in self.scope.var_entries] for x in self.scope.var_entries]
return max(child_depths) + 1 return max(child_depths) + 1
class CppClassType(CType):
# name string
# cname string
# scope CppClassScope
# templates [string] or None
is_cpp_class = 1
has_attributes = 1
exception_check = True
def __init__(self, name, scope, cname, base_classes, templates = None, template_type = None):
self.name = name
self.cname = cname
self.scope = scope
self.base_classes = base_classes
self.operators = []
self.templates = templates
self.template_type = template_type
self.specializations = {}
def specialize_here(self, pos, template_values = None):
if self.templates is None:
error(pos, "'%s' type is not a template" % self);
return PyrexTypes.error_type
if len(self.templates) != len(template_values):
error(pos, "%s templated type receives %d arguments, got %d" %
(self.name, len(self.templates), len(template_values)))
return error_type
return self.specialize(dict(zip(self.templates, template_values)))
def specialize(self, values):
if not self.templates:
return self
key = tuple(values.items())
if key in self.specializations:
return self.specializations[key]
template_values = [t.specialize(values) for t in self.templates]
specialized = self.specializations[key] = \
CppClassType(self.name, None, self.cname, self.base_classes, template_values, template_type=self)
specialized.scope = self.scope.specialize(values)
return specialized
def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0):
if self.templates:
template_strings = [param.declaration_code('', for_display, pyrex) for param in self.templates]
templates = "<" + ",".join(template_strings) + ">"
else:
templates = ""
if for_display or pyrex:
name = self.name
else:
name = self.cname
return "%s%s %s" % (name, templates, entity_code)
def is_subclass(self, other_type):
# TODO(danilo): Handle templates.
if self.same_as_resolved_type(other_type):
return 1
for base_class in self.base_classes:
if base_class.is_subclass(other_type):
return 1
return 0
def same_as_resolved_type(self, other_type):
if other_type.is_cpp_class:
if self == other_type:
return 1
elif self.template_type and self.template_type == other_type.template_type:
if self.templates == other_type.templates:
return 1
for t1, t2 in zip(self.templates, other_type.templates):
if not t1.same_as_resolved_type(t2):
return 0
return 1
return 0
def assignable_from_resolved_type(self, other_type):
# TODO: handle operator=(...) here?
if other_type is error_type:
return True
return other_type.is_cpp_class and other_type.is_subclass(self)
def attributes_known(self):
return self.scope is not None
class TemplatePlaceholderType(CType):
def __init__(self, name):
self.name = name
def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0):
if entity_code:
return self.name + " " + entity_code
else:
return self.name
def specialize(self, values):
if self in values:
return values[self]
else:
return self
def same_as_resolved_type(self, other_type):
if isinstance(other_type, TemplatePlaceholderType):
return self.name == other_type.name
else:
return 0
def __hash__(self):
return hash(self.name)
def __cmp__(self, other):
if isinstance(other, TemplatePlaceholderType):
return cmp(self.name, other.name)
else:
return cmp(type(self), type(other))
class CEnumType(CType): class CEnumType(CType):
# name string # name string
# cname string or None # cname string or None
...@@ -2001,6 +2199,137 @@ modifiers_and_name_to_type = { ...@@ -2001,6 +2199,137 @@ modifiers_and_name_to_type = {
(1, 0, "bint"): c_bint_type, (1, 0, "bint"): c_bint_type,
} }
def is_promotion0(src_type, dst_type):
if src_type.is_numeric and dst_type.is_numeric:
if src_type.is_int and dst_type.is_int:
if src_type.is_enum:
return True
elif src_type.signed:
return dst_type.signed and src_type.rank <= dst_type.rank
elif dst_type.signed: # and not src_type.signed
src_type.rank < dst_type.rank
else:
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):
# It's hard to find a hard definition of promotion, but empirical
# evidence suggests that the below is all that's allowed.
if src_type.is_numeric:
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)
elif dst_type.same_as(c_double_type):
return src_type.is_float and src_type.rank <= dst_type.rank
return False
def best_match(args, functions, pos=None):
"""
Given a list args of arguments and a list of functions, choose one
to call which seems to be the "best" fit for this list of arguments.
This function is used, e.g., when deciding which overloaded method
to dispatch for C++ classes.
We first eliminate functions based on arity, and if only one
function has the correct arity, we return it. Otherwise, we weight
functions based on how much work must be done to convert the
arguments, with the following priorities:
* identical types or pointers to identical types
* promotions
* non-Python types
That is, we prefer functions where no arguments need converted,
and failing that, functions where only promotions are required, and
so on.
If no function is deemed a good fit, or if two or more functions have
the same weight, we return None (as there is no best match). If pos
is not None, we also generate an error.
"""
# TODO: args should be a list of types, not a list of Nodes.
actual_nargs = len(args)
candidates = []
errors = []
for func in functions:
error_mesg = ""
func_type = func.type
if func_type.is_ptr:
func_type = func_type.base_type
# Check function type
if not func_type.is_cfunction:
if not func_type.is_error and pos is not None:
error_mesg = "Calling non-function type '%s'" % func_type
errors.append((func, error_mesg))
continue
# Check no. of args
max_nargs = len(func_type.args)
min_nargs = max_nargs - func_type.optional_arg_count
if actual_nargs < min_nargs or \
(not func_type.has_varargs and actual_nargs > max_nargs):
if max_nargs == min_nargs and not func_type.has_varargs:
expectation = max_nargs
elif actual_nargs < min_nargs:
expectation = "at least %s" % min_nargs
else:
expectation = "at most %s" % max_nargs
error_mesg = "Call with wrong number of arguments (expected %s, got %s)" \
% (expectation, actual_nargs)
errors.append((func, error_mesg))
continue
candidates.append((func, func_type))
# Optimize the most common case of no overloading...
if len(candidates) == 1:
return candidates[0][0]
elif len(candidates) == 0:
if len(errors) == 1 and pos is not None:
error(pos, errors[0][1])
return None
possibilities = []
bad_types = []
for func, func_type in candidates:
score = [0,0,0]
for i in range(min(len(args), len(func_type.args))):
src_type = args[i].type
dst_type = func_type.args[i].type
if dst_type.assignable_from(src_type):
if src_type == dst_type or (dst_type.is_reference and \
src_type == dst_type.base_type) \
or dst_type.same_as(src_type):
pass # score 0
elif is_promotion(src_type, dst_type):
score[2] += 1
elif not src_type.is_pyobject:
score[1] += 1
else:
score[0] += 1
else:
error_mesg = "Invalid conversion from '%s' to '%s'"%(src_type,
dst_type)
bad_types.append((func, error_mesg))
break
else:
possibilities.append((score, func)) # so we can sort it
if possibilities:
possibilities.sort()
if len(possibilities) > 1 and possibilities[0][0] == possibilities[1][0]:
if pos is not None:
error(pos, "ambiguous overloaded method")
return None
return possibilities[0][1]
if pos is not None:
if len(bad_types) == 1:
error(pos, bad_types[0][1])
else:
error(pos, "no suitable method found")
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.
...@@ -2039,6 +2368,17 @@ def spanning_type(type1, type2): ...@@ -2039,6 +2368,17 @@ def spanning_type(type1, type2):
return widest_numeric_type(type1, c_double_type) return widest_numeric_type(type1, c_double_type)
elif type1.is_pyobject ^ type2.is_pyobject: elif type1.is_pyobject ^ type2.is_pyobject:
return py_object_type return py_object_type
elif type1.is_extension_type and type2.is_extension_type:
if type1.typeobj_is_imported() or type2.typeobj_is_imported():
return py_object_type
while True:
if type1.subtype_of(type2):
return type2
elif type2.subtype_of(type1):
return type1
type1, type2 = type1.base_type, type2.base_type
if type1 is None or type2 is None:
return py_object_type
elif type1.assignable_from(type2): elif type1.assignable_from(type2):
if type1.is_extension_type and type1.typeobj_is_imported(): if type1.is_extension_type and type1.typeobj_is_imported():
# external types are unsafe, so we use PyObject instead # external types are unsafe, so we use PyObject instead
...@@ -2092,6 +2432,26 @@ def c_ptr_type(base_type): ...@@ -2092,6 +2432,26 @@ def c_ptr_type(base_type):
else: else:
return CPtrType(base_type) return CPtrType(base_type)
def c_ref_type(base_type):
# Construct a C reference type
if base_type is error_type:
return error_type
else:
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)
......
...@@ -97,7 +97,10 @@ def initial_compile_time_env(): ...@@ -97,7 +97,10 @@ def initial_compile_time_env():
'UNAME_VERSION', 'UNAME_MACHINE') 'UNAME_VERSION', 'UNAME_MACHINE')
for name, value in zip(names, platform.uname()): for name, value in zip(names, platform.uname()):
benv.declare(name, value) benv.declare(name, value)
try:
import __builtin__ as builtins import __builtin__ as builtins
except ImportError:
import builtins
names = ('False', 'True', names = ('False', 'True',
'abs', 'bool', 'chr', 'cmp', 'complex', 'dict', 'divmod', 'enumerate', 'abs', 'bool', 'chr', 'cmp', 'complex', 'dict', 'divmod', 'enumerate',
'float', 'hash', 'hex', 'int', 'len', 'list', 'long', 'map', 'max', 'min', 'float', 'hash', 'hex', 'int', 'len', 'list', 'long', 'map', 'max', 'min',
...@@ -355,6 +358,14 @@ class PyrexScanner(Scanner): ...@@ -355,6 +358,14 @@ class PyrexScanner(Scanner):
t = "%s %s" % (self.sy, self.systring) t = "%s %s" % (self.sy, self.systring)
print("--- %3d %2d %s" % (line, col, t)) print("--- %3d %2d %s" % (line, col, t))
def peek(self):
saved = self.sy, self.systring
self.next()
next = self.sy, self.systring
self.unread(*next)
self.sy, self.systring = saved
return next
def put_back(self, sy, systring): def put_back(self, sy, systring):
self.unread(self.sy, self.systring) self.unread(self.sy, self.systring)
self.sy = sy self.sy = sy
......
...@@ -185,7 +185,9 @@ def escape_byte_string(s): ...@@ -185,7 +185,9 @@ def escape_byte_string(s):
append(c) append(c)
return join_bytes(l).decode('ISO-8859-1') return join_bytes(l).decode('ISO-8859-1')
def split_docstring(s): def split_string_literal(s):
# MSVC can't handle long string literals.
if len(s) < 2047: if len(s) < 2047:
return s return s
return '\\n\"\"'.join(s.split(r'\n')) else:
return '""'.join([s[i:i+2000] for i in range(0, len(s), 2000)]).replace(r'\""', '""\\')
...@@ -75,6 +75,7 @@ class Entry(object): ...@@ -75,6 +75,7 @@ class Entry(object):
# is_unbound_cmethod boolean Is an unbound C method of an extension type # is_unbound_cmethod boolean Is an unbound C method of an extension type
# is_type boolean Is a type definition # is_type boolean Is a type definition
# is_cclass boolean Is an extension class # is_cclass boolean Is an extension class
# is_cpp_class boolean Is a C++ class
# is_const boolean Is a constant # is_const boolean Is a constant
# is_property boolean Is a property of an extension type: # is_property boolean Is a property of an extension type:
# doc_cname string or None C const holding the docstring # doc_cname string or None C const holding the docstring
...@@ -118,6 +119,8 @@ class Entry(object): ...@@ -118,6 +119,8 @@ class Entry(object):
# inline_func_in_pxd boolean Hacky special case for inline function in pxd file. # inline_func_in_pxd boolean Hacky special case for inline function in pxd file.
# Ideally this should not be necesarry. # Ideally this should not be necesarry.
# assignments [ExprNode] List of expressions that get assigned to this entry. # assignments [ExprNode] List of expressions that get assigned to this entry.
# might_overflow boolean In an arithmatic expression that could cause
# overflow (used for type inference).
inline_func_in_pxd = False inline_func_in_pxd = False
borrowed = 0 borrowed = 0
...@@ -133,6 +136,7 @@ class Entry(object): ...@@ -133,6 +136,7 @@ class Entry(object):
is_unbound_cmethod = 0 is_unbound_cmethod = 0
is_type = 0 is_type = 0
is_cclass = 0 is_cclass = 0
is_cpp_class = 0
is_const = 0 is_const = 0
is_property = 0 is_property = 0
doc_cname = None doc_cname = None
...@@ -165,6 +169,7 @@ class Entry(object): ...@@ -165,6 +169,7 @@ class Entry(object):
is_overridable = 0 is_overridable = 0
buffer_aux = None buffer_aux = None
prev_entry = None prev_entry = None
might_overflow = 0
def __init__(self, name, cname, type, pos = None, init = None): def __init__(self, name, cname, type, pos = None, init = None):
self.name = name self.name = name
...@@ -172,6 +177,7 @@ class Entry(object): ...@@ -172,6 +177,7 @@ class Entry(object):
self.type = type self.type = type
self.pos = pos self.pos = pos
self.init = init self.init = init
self.overloaded_alternatives = []
self.assignments = [] self.assignments = []
def __repr__(self): def __repr__(self):
...@@ -181,6 +187,9 @@ class Entry(object): ...@@ -181,6 +187,9 @@ class Entry(object):
error(pos, "'%s' does not match previous declaration" % self.name) error(pos, "'%s' does not match previous declaration" % self.name)
error(self.pos, "Previous declaration is here") error(self.pos, "Previous declaration is here")
def all_alternatives(self):
return [self] + self.overloaded_alternatives
class Scope(object): class Scope(object):
# name string Unqualified name # name string Unqualified name
# outer_scope Scope or None Enclosing scope # outer_scope Scope or None Enclosing scope
...@@ -290,6 +299,8 @@ class Scope(object): ...@@ -290,6 +299,8 @@ class Scope(object):
# Create new entry, and add to dictionary if # Create new entry, and add to dictionary if
# name is not None. Reports a warning if already # name is not None. Reports a warning if already
# declared. # declared.
if type.is_buffer and not isinstance(self, LocalScope):
error(pos, ERR_BUF_LOCALONLY)
if not self.in_cinclude and cname and re.match("^_[_A-Z]+$", cname): if not self.in_cinclude and cname and re.match("^_[_A-Z]+$", cname):
# See http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html#Reserved-Names # See http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html#Reserved-Names
warning(pos, "'%s' is a reserved name in C." % cname, -1) warning(pos, "'%s' is a reserved name in C." % cname, -1)
...@@ -303,6 +314,10 @@ class Scope(object): ...@@ -303,6 +314,10 @@ class Scope(object):
entry.in_cinclude = self.in_cinclude entry.in_cinclude = self.in_cinclude
if name: if name:
entry.qualified_name = self.qualify_name(name) entry.qualified_name = self.qualify_name(name)
# if name in entries and self.is_cpp():
# entries[name].overloaded_alternatives.append(entry)
# else:
# entries[name] = entry
entries[name] = entry entries[name] = entry
entry.scope = self entry.scope = self
entry.visibility = visibility entry.visibility = visibility
...@@ -419,6 +434,10 @@ class Scope(object): ...@@ -419,6 +434,10 @@ class Scope(object):
cname = name cname = name
else: else:
cname = self.mangle(Naming.var_prefix, name) cname = self.mangle(Naming.var_prefix, name)
if type.is_cpp_class and visibility != 'extern':
constructor = type.scope.lookup(u'<init>')
if constructor is not None and PyrexTypes.best_match([], constructor.all_alternatives()) is None:
error(pos, "C++ class must have a default constructor to be stack allocated")
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1 entry.is_variable = 1
self.control_flow.set_state((), (name, 'initalized'), False) self.control_flow.set_state((), (name, 'initalized'), False)
...@@ -445,22 +464,27 @@ class Scope(object): ...@@ -445,22 +464,27 @@ class Scope(object):
cname = None, visibility = 'private', defining = 0, cname = None, visibility = 'private', defining = 0,
api = 0, in_pxd = 0, modifiers = ()): api = 0, in_pxd = 0, modifiers = ()):
# Add an entry for a C function. # Add an entry for a C function.
if not cname:
if api or visibility != 'private':
cname = name
else:
cname = self.mangle(Naming.func_prefix, name)
entry = self.lookup_here(name) entry = self.lookup_here(name)
if entry: if entry:
if visibility != 'private' and visibility != entry.visibility: if visibility != 'private' and visibility != entry.visibility:
warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1) warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1)
if not entry.type.same_as(type): if not entry.type.same_as(type):
if visibility == 'extern' and entry.visibility == 'extern': if visibility == 'extern' and entry.visibility == 'extern':
if self.is_cpp():
temp = self.add_cfunction(name, type, pos, cname, visibility, modifiers)
temp.overloaded_alternatives = entry.all_alternatives()
entry = temp
else:
warning(pos, "Function signature does not match previous declaration", 1) warning(pos, "Function signature does not match previous declaration", 1)
entry.type = type entry.type = type
else: else:
error(pos, "Function signature does not match previous declaration") error(pos, "Function signature does not match previous declaration")
else: else:
if not cname:
if api or visibility != 'private':
cname = name
else:
cname = self.mangle(Naming.func_prefix, name)
entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers) entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers)
entry.func_cname = cname entry.func_cname = cname
if in_pxd and visibility != 'extern': if in_pxd and visibility != 'extern':
...@@ -538,6 +562,21 @@ class Scope(object): ...@@ -538,6 +562,21 @@ class Scope(object):
if entry and entry.is_type: if entry and entry.is_type:
return entry.type return entry.type
def lookup_operator(self, operator, operands):
if operands[0].type.is_cpp_class:
obj_type = operands[0].type
if obj_type.is_reference:
obj_type = obj_type.base_type
method = obj_type.scope.lookup("operator%s" % operator)
if method is not None:
res = PyrexTypes.best_match(operands[1:], method.all_alternatives())
if res is not None:
return res
function = self.lookup("operator%s" % operator)
if function is None:
return None
return PyrexTypes.best_match(operands, function.all_alternatives())
def use_utility_code(self, new_code): def use_utility_code(self, new_code):
self.global_scope().use_utility_code(new_code) self.global_scope().use_utility_code(new_code)
...@@ -557,6 +596,13 @@ class Scope(object): ...@@ -557,6 +596,13 @@ class Scope(object):
from TypeInference import get_type_inferer from TypeInference import get_type_inferer
get_type_inferer().infer_types(self) get_type_inferer().infer_types(self)
def is_cpp(self):
outer = self.outer_scope
if outer is None:
return False
else:
return outer.is_cpp()
class PreImportScope(Scope): class PreImportScope(Scope):
namespace_cname = Naming.preimport_cname namespace_cname = Naming.preimport_cname
...@@ -684,6 +730,7 @@ class ModuleScope(Scope): ...@@ -684,6 +730,7 @@ class ModuleScope(Scope):
# cimported_modules [ModuleScope] Modules imported with cimport # cimported_modules [ModuleScope] Modules imported with cimport
# types_imported {PyrexType : 1} Set of types for which import code generated # types_imported {PyrexType : 1} Set of types for which import code generated
# has_import_star boolean Module contains import * # has_import_star boolean Module contains import *
# cpp boolean Compiling a C++ file
is_module_scope = 1 is_module_scope = 1
has_import_star = 0 has_import_star = 0
...@@ -957,6 +1004,42 @@ class ModuleScope(Scope): ...@@ -957,6 +1004,42 @@ class ModuleScope(Scope):
if typedef_flag and not self.in_cinclude: if typedef_flag and not self.in_cinclude:
error(pos, "Forward-referenced type must use 'cdef', not 'ctypedef'") error(pos, "Forward-referenced type must use 'cdef', not 'ctypedef'")
def declare_cpp_class(self, name, scope,
pos, cname = None, base_classes = [],
visibility = 'extern', templates = None):
if visibility != 'extern':
error(pos, "C++ classes may only be extern")
if cname is None:
cname = name
entry = self.lookup(name)
if not entry:
type = PyrexTypes.CppClassType(
name, scope, cname, base_classes, templates = templates)
entry = self.declare_type(name, type, pos, cname,
visibility = visibility, defining = scope is not None)
else:
if not (entry.is_type and entry.type.is_cpp_class):
warning(pos, "'%s' redeclared " % name, 0)
elif scope and entry.type.scope:
warning(pos, "'%s' already defined (ignoring second definition)" % name, 0)
else:
if scope:
entry.type.scope = scope
self.type_entries.append(entry)
if not scope and not entry.type.scope:
entry.type.scope = CppClassScope(name, self)
if templates is not None:
for T in templates:
template_entry = entry.type.scope.declare(T.name, T.name, T, None, 'extern')
template_entry.is_type = 1
def declare_inherited_attributes(entry, base_classes):
for base_class in base_classes:
declare_inherited_attributes(entry, base_class.base_classes)
entry.type.scope.declare_inherited_cpp_attributes(base_class.scope)
declare_inherited_attributes(entry, base_classes)
return entry
def allocate_vtable_names(self, entry): def allocate_vtable_names(self, entry):
# If extension type has a vtable, allocate vtable struct and # If extension type has a vtable, allocate vtable struct and
# slot names for it. # slot names for it.
...@@ -1062,6 +1145,9 @@ class ModuleScope(Scope): ...@@ -1062,6 +1145,9 @@ class ModuleScope(Scope):
var_entry.is_readonly = 1 var_entry.is_readonly = 1
entry.as_variable = var_entry entry.as_variable = var_entry
def is_cpp(self):
return self.cpp
def infer_types(self): def infer_types(self):
from TypeInference import PyObjectTypeInferer from TypeInference import PyObjectTypeInferer
PyObjectTypeInferer().infer_types(self) PyObjectTypeInferer().infer_types(self)
...@@ -1281,6 +1367,8 @@ class CClassScope(ClassScope): ...@@ -1281,6 +1367,8 @@ class CClassScope(ClassScope):
cname = name cname = name
if visibility == 'private': if visibility == 'private':
cname = c_safe_identifier(cname) cname = c_safe_identifier(cname)
if type.is_cpp_class and visibility != 'extern':
error(pos, "C++ classes not allowed as members of an extension type, use a pointer or reference instead")
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1 entry.is_variable = 1
self.var_entries.append(entry) self.var_entries.append(entry)
...@@ -1420,6 +1508,67 @@ class CClassScope(ClassScope): ...@@ -1420,6 +1508,67 @@ class CClassScope(ClassScope):
entry.is_inherited = 1 entry.is_inherited = 1
class CppClassScope(Scope):
# Namespace of a C++ class.
inherited_var_entries = []
def __init__(self, name, outer_scope):
Scope.__init__(self, name, outer_scope, None)
self.directives = outer_scope.directives
def declare_var(self, name, type, pos,
cname = None, visibility = 'extern', is_cdef = 0, allow_pyobject = 0):
# Add an entry for an attribute.
if not cname:
cname = name
if type.is_cfunction:
type = PyrexTypes.CPtrType(type)
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
self.var_entries.append(entry)
if type.is_pyobject and not allow_pyobject:
error(pos,
"C++ class member cannot be a Python object")
return entry
def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'extern', defining = 0,
api = 0, in_pxd = 0, modifiers = ()):
if name == self.name.split('::')[-1] and cname is None:
name = '<init>'
type.return_type = self.lookup(self.name).type
prev_entry = self.lookup_here(name)
entry = self.declare_var(name, type, pos, cname, visibility)
if prev_entry:
entry.overloaded_alternatives = prev_entry.all_alternatives()
def declare_inherited_cpp_attributes(self, base_scope):
# Declare entries for all the C++ attributes of an
# inherited type, with cnames modified appropriately
# to work with this type.
for base_entry in \
base_scope.inherited_var_entries + base_scope.var_entries:
entry = self.declare(base_entry.name, base_entry.cname,
base_entry.type, None, 'extern')
entry.is_variable = 1
self.inherited_var_entries.append(entry)
for base_entry in base_scope.cfunc_entries:
entry = self.declare_cfunction(base_entry.name, base_entry.type,
base_entry.pos, base_entry.cname,
base_entry.visibility, base_entry.func_modifiers)
entry.is_inherited = 1
def specialize(self, values):
scope = CppClassScope(self.name, self.outer_scope)
for entry in self.entries.values():
scope.declare_var(entry.name,
entry.type.specialize(values),
entry.pos,
entry.cname,
entry.visibility)
return scope
class PropertyScope(Scope): class PropertyScope(Scope):
# Scope holding the __get__, __set__ and __del__ methods for # Scope holding the __get__, __set__ and __del__ methods for
# a property of an extension type. # a property of an extension type.
...@@ -1479,3 +1628,7 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) { ...@@ -1479,3 +1628,7 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
return NULL; return NULL;
} }
""") """)
#------------------------------------------------------------------------------------
ERR_BUF_LOCALONLY = 'Buffer types only allowed as function local variables'
...@@ -21,7 +21,7 @@ class TestBufferParsing(CythonTest): ...@@ -21,7 +21,7 @@ class TestBufferParsing(CythonTest):
def test_basic(self): def test_basic(self):
t = self.parse(u"cdef object[float, 4, ndim=2, foo=foo] x") t = self.parse(u"cdef object[float, 4, ndim=2, foo=foo] x")
bufnode = t.stats[0].base_type bufnode = t.stats[0].base_type
self.assert_(isinstance(bufnode, CBufferAccessTypeNode)) self.assert_(isinstance(bufnode, TemplatedTypeNode))
self.assertEqual(2, len(bufnode.positional_args)) self.assertEqual(2, len(bufnode.positional_args))
# print bufnode.dump() # print bufnode.dump()
# should put more here... # should put more here...
...@@ -32,14 +32,6 @@ class TestBufferParsing(CythonTest): ...@@ -32,14 +32,6 @@ class TestBufferParsing(CythonTest):
def test_type_keyword(self): def test_type_keyword(self):
self.parse(u"cdef object[foo=foo, dtype=short unsigned int] x") self.parse(u"cdef object[foo=foo, dtype=short unsigned int] x")
def test_notype_as_expr1(self):
self.not_parseable("Expected: expression",
u"cdef object[foo2=short unsigned int] x")
def test_notype_as_expr2(self):
self.not_parseable("Expected: expression",
u"cdef object[int, short unsigned int] x")
def test_pos_after_key(self): def test_pos_after_key(self):
self.not_parseable("Non-keyword arg following keyword arg", self.not_parseable("Non-keyword arg following keyword arg",
u"cdef object[foo=1, 2] x") u"cdef object[foo=1, 2] x")
...@@ -65,7 +57,7 @@ class TestBufferOptions(CythonTest): ...@@ -65,7 +57,7 @@ class TestBufferOptions(CythonTest):
vardef = root.stats[0].body.stats[0] vardef = root.stats[0].body.stats[0]
assert isinstance(vardef, CVarDefNode) # use normal assert as this is to validate the test code assert isinstance(vardef, CVarDefNode) # use normal assert as this is to validate the test code
buftype = vardef.base_type buftype = vardef.base_type
self.assert_(isinstance(buftype, CBufferAccessTypeNode)) self.assert_(isinstance(buftype, TemplatedTypeNode))
self.assert_(isinstance(buftype.base_type_node, CSimpleBaseTypeNode)) self.assert_(isinstance(buftype.base_type_node, CSimpleBaseTypeNode))
self.assertEqual(u"object", buftype.base_type_node.name) self.assertEqual(u"object", buftype.base_type_node.name)
return buftype return buftype
......
...@@ -112,6 +112,62 @@ class MarkAssignments(CythonTransform): ...@@ -112,6 +112,62 @@ class MarkAssignments(CythonTransform):
self.visitchildren(node) self.visitchildren(node)
return node return node
class MarkOverflowingArithmatic(CythonTransform):
# It may be possible to integrate this with the above for
# performance improvements (though likely not worth it).
might_overflow = False
def __call__(self, root):
self.env_stack = []
self.env = root.scope
return super(MarkOverflowingArithmatic, self).__call__(root)
def visit_safe_node(self, node):
self.might_overflow, saved = False, self.might_overflow
self.visitchildren(node)
self.might_overflow = saved
return node
def visit_neutral_node(self, node):
self.visitchildren(node)
return node
def visit_dangerous_node(self, node):
self.might_overflow, saved = True, self.might_overflow
self.visitchildren(node)
self.might_overflow = saved
return node
def visit_FuncDefNode(self, node):
self.env_stack.append(self.env)
self.env = node.local_scope
self.visit_safe_node(node)
self.env = self.env_stack.pop()
return node
def visit_NameNode(self, node):
if self.might_overflow:
entry = node.entry or self.env.lookup(node.name)
if entry:
entry.might_overflow = True
return node
def visit_BinopNode(self, node):
if node.operator in '&|^':
return self.visit_neutral_node(node)
else:
return self.visit_dangerous_node(node)
visit_UnopNode = visit_neutral_node
visit_UnaryMinusNode = visit_dangerous_node
visit_InPlaceAssignmentNode = visit_dangerous_node
visit_Node = visit_safe_node
class PyObjectTypeInferer: class PyObjectTypeInferer:
""" """
...@@ -175,7 +231,7 @@ class SimpleAssignmentTypeInferer: ...@@ -175,7 +231,7 @@ class SimpleAssignmentTypeInferer:
entry = ready_to_infer.pop() entry = ready_to_infer.pop()
types = [expr.infer_type(scope) for expr in entry.assignments] types = [expr.infer_type(scope) for expr in entry.assignments]
if types: if types:
entry.type = spanning_type(types) entry.type = spanning_type(types, entry.might_overflow)
else: else:
# FIXME: raise a warning? # FIXME: raise a warning?
# print "No assignments", entry.pos, entry # print "No assignments", entry.pos, entry
...@@ -188,9 +244,9 @@ class SimpleAssignmentTypeInferer: ...@@ -188,9 +244,9 @@ class SimpleAssignmentTypeInferer:
if len(deps) == 1 and deps == set([entry]): if len(deps) == 1 and deps == set([entry]):
types = [expr.infer_type(scope) for expr in entry.assignments if expr.type_dependencies(scope) == ()] types = [expr.infer_type(scope) for expr in entry.assignments if expr.type_dependencies(scope) == ()]
if types: if types:
entry.type = spanning_type(types) entry.type = spanning_type(types, entry.might_overflow)
types = [expr.infer_type(scope) for expr in entry.assignments] types = [expr.infer_type(scope) for expr in entry.assignments]
entry.type = spanning_type(types) # might be wider... entry.type = spanning_type(types, entry.might_overflow) # might be wider...
resolve_dependancy(entry) resolve_dependancy(entry)
del dependancies_by_entry[entry] del dependancies_by_entry[entry]
if ready_to_infer: if ready_to_infer:
...@@ -218,11 +274,11 @@ def find_spanning_type(type1, type2): ...@@ -218,11 +274,11 @@ def find_spanning_type(type1, type2):
return PyrexTypes.c_double_type return PyrexTypes.c_double_type
return result_type return result_type
def aggressive_spanning_type(types): def aggressive_spanning_type(types, might_overflow):
result_type = reduce(find_spanning_type, types) result_type = reduce(find_spanning_type, types)
return result_type return result_type
def safe_spanning_type(types): def safe_spanning_type(types, might_overflow):
result_type = reduce(find_spanning_type, types) result_type = reduce(find_spanning_type, types)
if result_type.is_pyobject: if result_type.is_pyobject:
# any specific Python type is always safe to infer # any specific Python type is always safe to infer
...@@ -235,6 +291,22 @@ def safe_spanning_type(types): ...@@ -235,6 +291,22 @@ def safe_spanning_type(types):
# find_spanning_type() only returns 'bint' for clean boolean # find_spanning_type() only returns 'bint' for clean boolean
# operations without other int types, so this is safe, too # operations without other int types, so this is safe, too
return result_type return result_type
elif result_type.is_ptr and not (result_type.is_int and result_type.rank == 0):
# Any pointer except (signed|unsigned|) char* can't implicitly
# become a PyObject.
return result_type
elif result_type.is_cpp_class:
# These can't implicitly become Python objects either.
return result_type
elif result_type.is_struct:
# Though we have struct -> object for some structs, this is uncommonly
# used, won't arise in pure Python, and there shouldn't be side
# effects, so I'm declaring this safe.
return result_type
# TODO: double complex should be OK as well, but we need
# to make sure everything is supported.
elif result_type.is_int and not might_overflow:
return result_type
return py_object_type return py_object_type
......
...@@ -100,7 +100,8 @@ class TreeVisitor(BasicVisitor): ...@@ -100,7 +100,8 @@ class TreeVisitor(BasicVisitor):
def dump_node(self, node, indent=0): def dump_node(self, node, indent=0):
ignored = list(node.child_attrs) + [u'child_attrs', u'pos', ignored = list(node.child_attrs) + [u'child_attrs', u'pos',
u'gil_message', u'subexprs'] u'gil_message', u'cpp_message',
u'subexprs']
values = [] values = []
pos = node.pos pos = node.pos
if pos: if pos:
......
...@@ -7,5 +7,6 @@ ...@@ -7,5 +7,6 @@
# and keep the old one under the module name _build_ext, # and keep the old one under the module name _build_ext,
# so that *our* build_ext can make use of it. # so that *our* build_ext can make use of it.
from build_ext import build_ext from Cython.Distutils.build_ext import build_ext
# from extension import Extension # from extension import Extension
...@@ -15,16 +15,6 @@ from distutils.sysconfig import customize_compiler, get_python_version ...@@ -15,16 +15,6 @@ from distutils.sysconfig import customize_compiler, get_python_version
from distutils.dep_util import newer, newer_group from distutils.dep_util import newer, newer_group
from distutils import log from distutils import log
from distutils.dir_util import mkpath from distutils.dir_util import mkpath
try:
from Cython.Compiler.Main \
import CompilationOptions, \
default_options as pyrex_default_options, \
compile as cython_compile
from Cython.Compiler.Errors import PyrexError
except ImportError, e:
print "failed to import Cython: %s" % e
PyrexError = None
from distutils.command import build_ext as _build_ext from distutils.command import build_ext as _build_ext
extension_name_re = _build_ext.extension_name_re extension_name_re = _build_ext.extension_name_re
...@@ -83,18 +73,22 @@ class build_ext(_build_ext.build_ext): ...@@ -83,18 +73,22 @@ class build_ext(_build_ext.build_ext):
self.build_extension(ext) self.build_extension(ext)
def cython_sources(self, sources, extension): def cython_sources(self, sources, extension):
""" """
Walk the list of source files in 'sources', looking for Cython Walk the list of source files in 'sources', looking for Cython
source files (.pyx and .py). Run Cython on all that are source files (.pyx and .py). Run Cython on all that are
found, and return a modified 'sources' list with Cython source found, and return a modified 'sources' list with Cython source
files replaced by the generated C (or C++) files. files replaced by the generated C (or C++) files.
""" """
try:
if PyrexError == None: from Cython.Compiler.Main \
raise DistutilsPlatformError, \ import CompilationOptions, \
("Cython does not appear to be installed " default_options as pyrex_default_options, \
"on platform '%s'") % os.name compile as cython_compile
from Cython.Compiler.Errors import PyrexError
except ImportError:
e = sys.exc_info()[1]
print("failed to import Cython: %s" % e)
raise DistutilsPlatformError("Cython does not appear to be installed")
new_sources = [] new_sources = []
pyrex_sources = [] pyrex_sources = []
......
cdef extern from "<vector>" namespace std:
cdef cppclass vector[TYPE]:
#constructors
__init__()
__init__(vector&)
__init__(int)
__init__(int, TYPE&)
__init__(iterator, iterator)
#operators
TYPE& __getitem__(int)
TYPE& __setitem__(int, TYPE&)
vector __new__(vector&)
bool __eq__(vector&, vector&)
bool __ne__(vector&, vector&)
bool __lt__(vector&, vector&)
bool __gt__(vector&, vector&)
bool __le__(vector&, vector&)
bool __ge__(vector&, vector&)
#others
void assign(int, TYPE)
#void assign(iterator, iterator)
TYPE& at(int)
TYPE& back()
iterator begin()
int capacity()
void clear()
bool empty()
iterator end()
iterator erase(iterator)
iterator erase(iterator, iterator)
TYPE& front()
iterator insert(iterator, TYPE&)
void insert(iterator, int, TYPE&)
void insert(iterator, iterator)
int max_size()
void pop_back()
void push_back(TYPE&)
iterator rbegin()
iterator rend()
void reserve(int)
void resize(int)
void resize(int, TYPE&) #void resize(size_type num, const TYPE& = TYPE())
int size()
void swap(container&)
cdef extern from "<deque>" namespace std:
cdef cppclass deque[TYPE]:
#constructors
__init__()
__init__(deque&)
__init__(int)
__init__(int, TYPE&)
__init__(iterator, iterator)
#operators
TYPE& operator[]( size_type index );
const TYPE& operator[]( size_type index ) const;
deque __new__(deque&);
bool __eq__(deque&, deque&);
bool __ne__(deque&, deque&);
bool __lt__(deque&, deque&);
bool __gt__(deque&, deque&);
bool __le__(deque&, deque&);
bool __ge__(deque&, deque&);
#others
void assign(int, TYPE&)
void assign(iterator, iterator)
TYPE& at(int)
TYPE& back()
iterator begin()
void clear()
bool empty()
iterator end()
iterator erase(iterator)
iterator erase(iterator, iterator)
TYPE& front()
iterator insert(iterator, TYPE&)
void insert(iterator, int, TYPE&)
void insert(iterator, iterator, iterator)
int max_size()
void pop_back()
void pop_front()
void push_back(TYPE&)
void push_front(TYPE&)
iterator rbegin()
iterator rend()
void resize(int)
void resize(int, TYPE&)
int size()
void swap(container&)
...@@ -13,10 +13,11 @@ except: ...@@ -13,10 +13,11 @@ except:
ext_modules=[ ext_modules=[
Extension("primes", ["primes.pyx"]), Extension("primes", ["primes.pyx"]),
Extension("spam", ["spam.pyx"]), Extension("spam", ["spam.pyx"]),
Extension("square", ["square.pyx"], language="c++"),
] ]
for file in glob.glob("*.pyx"): for file in glob.glob("*.pyx"):
if file != "numeric_demo.pyx": if file != "numeric_demo.pyx" and file != "square.pyx":
ext_modules.append(Extension(file[:-4], [file], include_dirs = numpy_include_dirs)) ext_modules.append(Extension(file[:-4], [file], include_dirs = numpy_include_dirs))
setup( setup(
......
;;;; `Cython' mode. (add-to-list 'auto-mode-alist '("\\.pyx\\'" . cython-mode)) (define-derived-mode cython-mode python-mode "Cython" (font-lock-add-keywords nil `((,(concat "\\<\\(NULL" "\\|c\\(def\\|har\\|typedef\\)" "\\|e\\(num\\|xtern\\)" "\\|float" "\\|in\\(clude\\|t\\)" "\\|object\\|public\\|struct\\|type\\|union\\|void" "\\)\\>") 1 font-lock-keyword-face t)))) ;; Cython mode
\ No newline at end of file
(require 'python-mode)
(add-to-list 'auto-mode-alist '("\\.pyx\\'" . cython-mode))
(add-to-list 'auto-mode-alist '("\\.pxd\\'" . cython-mode))
(add-to-list 'auto-mode-alist '("\\.pxi\\'" . cython-mode))
(defun cython-compile ()
"Compile the file via Cython."
(interactive)
(let ((cy-buffer (current-buffer)))
(with-current-buffer
(compile compile-command)
(set (make-local-variable 'cython-buffer) cy-buffer)
(add-to-list (make-local-variable 'compilation-finish-functions)
'cython-compilation-finish)))
)
(defun cython-compilation-finish (buffer how)
"Called when Cython compilation finishes."
;; XXX could annotate source here
)
(defvar cython-mode-map
(let ((map (make-sparse-keymap)))
;; Will inherit from `python-mode-map' thanks to define-derived-mode.
(define-key map "\C-c\C-c" 'cython-compile)
map)
"Keymap used in `cython-mode'.")
(defvar cython-font-lock-keywords
`(;; new keywords in Cython language
(,(regexp-opt '("by" "cdef" "cimport" "cpdef" "ctypedef" "enum" "except?"
"extern" "gil" "include" "nogil" "property" "public"
"readonly" "struct" "union" "DEF" "IF" "ELIF" "ELSE") 'words)
1 font-lock-keyword-face)
;; C and Python types (highlight as builtins)
(,(regexp-opt '("NULL" "bint" "char" "dict" "double" "float" "int" "list"
"long" "object" "Py_ssize_t" "short" "size_t" "void") 'words)
1 font-lock-builtin-face)
;; cdef is used for more than functions, so simply highlighting the next
;; word is problematic. struct, enum and property work though.
("\\<\\(?:struct\\|enum\\)[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)"
1 py-class-name-face)
("\\<property[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)"
1 font-lock-function-name-face))
"Additional font lock keywords for Cython mode.")
(define-derived-mode cython-mode python-mode "Cython"
"Major mode for Cython development, derived from Python mode.
\\{cython-mode-map}"
(setcar font-lock-defaults
(append python-font-lock-keywords cython-font-lock-keywords))
(set (make-local-variable 'compile-command)
(concat "cython -a " buffer-file-name))
(add-to-list (make-local-variable 'compilation-finish-functions)
'cython-compilation-finish)
)
(provide 'cython-mode)
...@@ -28,8 +28,8 @@ from distutils.core import Extension ...@@ -28,8 +28,8 @@ from distutils.core import Extension
from distutils.command.build_ext import build_ext as _build_ext from distutils.command.build_ext import build_ext as _build_ext
distutils_distro = Distribution() distutils_distro = Distribution()
TEST_DIRS = ['compile', 'errors', 'run', 'pyregr'] TEST_DIRS = ['compile', 'errors', 'run', 'wrappers', 'pyregr']
TEST_RUN_DIRS = ['run', 'pyregr'] TEST_RUN_DIRS = ['run', 'wrappers', 'pyregr']
# Lists external modules, and a matcher matching tests # Lists external modules, and a matcher matching tests
# which should be excluded if the module is not present. # which should be excluded if the module is not present.
...@@ -48,8 +48,8 @@ EXT_DEP_INCLUDES = [ ...@@ -48,8 +48,8 @@ EXT_DEP_INCLUDES = [
] ]
VER_DEP_MODULES = { VER_DEP_MODULES = {
# such as: (2,4) : (operator.le, lambda x: x in ['run.extern_builtins_T258'
# (2,4) : (operator.le, lambda x: x in ['run.set']), ]),
(3,): (operator.ge, lambda x: x in ['run.non_future_division', (3,): (operator.ge, lambda x: x in ['run.non_future_division',
'compile.extsetslice', 'compile.extsetslice',
'compile.extdelslice']), 'compile.extdelslice']),
...@@ -200,10 +200,10 @@ class TestBuilder(object): ...@@ -200,10 +200,10 @@ class TestBuilder(object):
fork=self.fork) fork=self.fork)
class CythonCompileTestCase(unittest.TestCase): class CythonCompileTestCase(unittest.TestCase):
def __init__(self, directory, workdir, module, language='c', def __init__(self, test_directory, workdir, module, language='c',
expect_errors=False, annotate=False, cleanup_workdir=True, expect_errors=False, annotate=False, cleanup_workdir=True,
cleanup_sharedlibs=True, cython_only=False, fork=True): cleanup_sharedlibs=True, cython_only=False, fork=True):
self.directory = directory self.test_directory = test_directory
self.workdir = workdir self.workdir = workdir
self.module = module self.module = module
self.language = language self.language = language
...@@ -257,8 +257,8 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -257,8 +257,8 @@ class CythonCompileTestCase(unittest.TestCase):
self.runCompileTest() self.runCompileTest()
def runCompileTest(self): def runCompileTest(self):
self.compile(self.directory, self.module, self.workdir, self.compile(self.test_directory, self.module, self.workdir,
self.directory, self.expect_errors, self.annotate) self.test_directory, self.expect_errors, self.annotate)
def find_module_source_file(self, source_file): def find_module_source_file(self, source_file):
if not os.path.exists(source_file): if not os.path.exists(source_file):
...@@ -269,8 +269,15 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -269,8 +269,15 @@ class CythonCompileTestCase(unittest.TestCase):
target = '%s.%s' % (module_name, self.language) target = '%s.%s' % (module_name, self.language)
return target return target
def split_source_and_output(self, directory, module, workdir): def find_source_files(self, test_directory, module_name):
source_file = os.path.join(directory, module) + '.pyx' is_related = re.compile('%s_.*[.]%s' % (module_name, self.language)).match
return [self.build_target_filename(module_name)] + [
os.path.join(test_directory, filename)
for filename in os.listdir(test_directory)
if is_related(filename) and os.path.isfile(os.path.join(test_directory, filename)) ]
def split_source_and_output(self, test_directory, module, workdir):
source_file = os.path.join(test_directory, module) + '.pyx'
source_and_output = codecs.open( source_and_output = codecs.open(
self.find_module_source_file(source_file), 'rU', 'ISO-8859-1') self.find_module_source_file(source_file), 'rU', 'ISO-8859-1')
out = codecs.open(os.path.join(workdir, module + '.pyx'), out = codecs.open(os.path.join(workdir, module + '.pyx'),
...@@ -289,12 +296,12 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -289,12 +296,12 @@ class CythonCompileTestCase(unittest.TestCase):
else: else:
return geterrors() return geterrors()
def run_cython(self, directory, module, targetdir, incdir, annotate): def run_cython(self, test_directory, module, targetdir, incdir, annotate):
include_dirs = INCLUDE_DIRS[:] include_dirs = INCLUDE_DIRS[:]
if incdir: if incdir:
include_dirs.append(incdir) include_dirs.append(incdir)
source = self.find_module_source_file( source = self.find_module_source_file(
os.path.join(directory, module + '.pyx')) os.path.join(test_directory, module + '.pyx'))
target = os.path.join(targetdir, self.build_target_filename(module)) target = os.path.join(targetdir, self.build_target_filename(module))
options = CompilationOptions( options = CompilationOptions(
pyrex_default_options, pyrex_default_options,
...@@ -309,7 +316,7 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -309,7 +316,7 @@ class CythonCompileTestCase(unittest.TestCase):
cython_compile(source, options=options, cython_compile(source, options=options,
full_module_name=module) full_module_name=module)
def run_distutils(self, module, workdir, incdir): def run_distutils(self, test_directory, module, workdir, incdir):
cwd = os.getcwd() cwd = os.getcwd()
os.chdir(workdir) os.chdir(workdir)
try: try:
...@@ -324,7 +331,7 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -324,7 +331,7 @@ class CythonCompileTestCase(unittest.TestCase):
ext_include_dirs += get_additional_include_dirs() ext_include_dirs += get_additional_include_dirs()
extension = Extension( extension = Extension(
module, module,
sources = [self.build_target_filename(module)], sources = self.find_source_files(test_directory, module),
include_dirs = ext_include_dirs, include_dirs = ext_include_dirs,
extra_compile_args = CFLAGS, extra_compile_args = CFLAGS,
) )
...@@ -337,19 +344,19 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -337,19 +344,19 @@ class CythonCompileTestCase(unittest.TestCase):
finally: finally:
os.chdir(cwd) os.chdir(cwd)
def compile(self, directory, module, workdir, incdir, def compile(self, test_directory, module, workdir, incdir,
expect_errors, annotate): expect_errors, annotate):
expected_errors = errors = () expected_errors = errors = ()
if expect_errors: if expect_errors:
expected_errors = self.split_source_and_output( expected_errors = self.split_source_and_output(
directory, module, workdir) test_directory, module, workdir)
directory = workdir test_directory = workdir
if WITH_CYTHON: if WITH_CYTHON:
old_stderr = sys.stderr old_stderr = sys.stderr
try: try:
sys.stderr = ErrorWriter() sys.stderr = ErrorWriter()
self.run_cython(directory, module, workdir, incdir, annotate) self.run_cython(test_directory, module, workdir, incdir, annotate)
errors = sys.stderr.geterrors() errors = sys.stderr.geterrors()
finally: finally:
sys.stderr = old_stderr sys.stderr = old_stderr
...@@ -373,7 +380,7 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -373,7 +380,7 @@ class CythonCompileTestCase(unittest.TestCase):
raise raise
else: else:
if not self.cython_only: if not self.cython_only:
self.run_distutils(module, workdir, incdir) self.run_distutils(test_directory, module, workdir, incdir)
class CythonRunTestCase(CythonCompileTestCase): class CythonRunTestCase(CythonCompileTestCase):
def shortDescription(self): def shortDescription(self):
...@@ -649,7 +656,7 @@ class FileListExcluder: ...@@ -649,7 +656,7 @@ class FileListExcluder:
self.excludes[line.split()[0]] = True self.excludes[line.split()[0]] = True
def __call__(self, testname): def __call__(self, testname):
return testname.split('.')[-1] in self.excludes return testname in self.excludes or testname.split('.')[-1] in self.excludes
if __name__ == '__main__': if __name__ == '__main__':
from optparse import OptionParser from optparse import OptionParser
......
...@@ -25,6 +25,11 @@ if sys.platform == "darwin": ...@@ -25,6 +25,11 @@ if sys.platform == "darwin":
setup_args = {} setup_args = {}
def add_command_class(name, cls):
cmdclasses = setup_args.get('cmdclass', {})
cmdclasses[name] = cls
setup_args['cmdclass'] = cmdclasses
if sys.version_info[0] >= 3: if sys.version_info[0] >= 3:
import lib2to3.refactor import lib2to3.refactor
from distutils.command.build_py \ from distutils.command.build_py \
...@@ -34,7 +39,7 @@ if sys.version_info[0] >= 3: ...@@ -34,7 +39,7 @@ if sys.version_info[0] >= 3:
if fix.split('fix_')[-1] not in ('next',) if fix.split('fix_')[-1] not in ('next',)
] ]
build_py.fixer_names = fixers build_py.fixer_names = fixers
setup_args['cmdclass'] = {"build_py" : build_py} add_command_class("build_py", build_py)
if sys.version_info < (2,4): if sys.version_info < (2,4):
...@@ -72,14 +77,45 @@ else: ...@@ -72,14 +77,45 @@ else:
else: else:
scripts = ["cython.py"] scripts = ["cython.py"]
def compile_cython_modules():
source_root = os.path.abspath(os.path.dirname(__file__))
compiled_modules = ["Cython.Plex.Scanners",
"Cython.Compiler.Scanning",
"Cython.Compiler.Parsing",
"Cython.Compiler.Visitor",
"Cython.Runtime.refnanny"]
extensions = []
try:
if sys.version_info[0] >= 3: if sys.version_info[0] >= 3:
raise ValueError from Cython.Distutils import build_ext as build_ext_orig
sys.argv.remove("--no-cython-compile") for module in compiled_modules:
except ValueError: source_file = os.path.join(source_root, *module.split('.'))
try: if os.path.exists(source_file + ".py"):
pyx_source_file = source_file + ".py"
else:
pyx_source_file = source_file + ".pyx"
extensions.append(
Extension(module, sources = [pyx_source_file])
)
class build_ext(build_ext_orig):
def build_extensions(self):
# add path where 2to3 installed the transformed sources
# and make sure Python (re-)imports them from there
already_imported = [ module for module in sys.modules
if module == 'Cython' or module.startswith('Cython.') ]
for module in already_imported:
del sys.modules[module]
sys.path.insert(0, os.path.join(source_root, self.build_lib))
build_ext_orig.build_extensions(self)
setup_args['ext_modules'] = extensions
add_command_class("build_ext", build_ext)
else: # Python 2.x
from distutils.command.build_ext import build_ext as build_ext_orig from distutils.command.build_ext import build_ext as build_ext_orig
try:
class build_ext(build_ext_orig): class build_ext(build_ext_orig):
def build_extension(self, ext, *args, **kargs): def build_extension(self, ext, *args, **kargs):
try: try:
...@@ -89,12 +125,6 @@ except ValueError: ...@@ -89,12 +125,6 @@ except ValueError:
from Cython.Compiler.Main import compile from Cython.Compiler.Main import compile
from Cython import Utils from Cython import Utils
source_root = os.path.dirname(__file__) source_root = os.path.dirname(__file__)
compiled_modules = ["Cython.Plex.Scanners",
"Cython.Compiler.Scanning",
"Cython.Compiler.Parsing",
"Cython.Compiler.Visitor",
"Cython.Runtime.refnanny"]
extensions = []
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('.'))
if os.path.exists(source_file + ".py"): if os.path.exists(source_file + ".py"):
...@@ -116,11 +146,16 @@ except ValueError: ...@@ -116,11 +146,16 @@ except ValueError:
print("Compilation failed") print("Compilation failed")
if extensions: if extensions:
setup_args['ext_modules'] = extensions setup_args['ext_modules'] = extensions
setup_args['cmdclass'] = {"build_ext" : build_ext} add_command_class("build_ext", build_ext)
except Exception: except Exception:
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")
try:
sys.argv.remove("--no-cython-compile")
except ValueError:
compile_cython_modules()
setup_args.update(setuptools_extra_args) setup_args.update(setuptools_extra_args)
from Cython.Compiler.Version import version from Cython.Compiler.Version import version
......
...@@ -8,3 +8,6 @@ unsignedbehaviour_T184 ...@@ -8,3 +8,6 @@ unsignedbehaviour_T184
missing_baseclass_in_predecl_T262 missing_baseclass_in_predecl_T262
cfunc_call_tuple_args_T408 cfunc_call_tuple_args_T408
cascaded_list_unpacking_T467 cascaded_list_unpacking_T467
compile.cpp_operators
cppwrap
cpp_overload_wrapper
cdef extern from "operators.h":
cdef cppclass Operators:
Operators(int)
Operators operator+(Operators)
Operators __add__(Operators, Operators)
Operators __sub__(Operators, Operators)
Operators __mul__(Operators, Operators)
Operators __div__(Operators, Operators)
bool __lt__(Operators, Operators)
bool __le__(Operators, Operators)
bool __eq__(Operators, Operators)
bool __ne__(Operators, Operators)
bool __gt__(Operators, Operators)
bool __ge__(Operators, Operators)
Operators __rshift__(Operators, int)
Operators __lshift__(Operators, int)
Operators __mod__(Operators, int)
cdef int v = 10
cdef Operators a
cdef Operators b
cdef Operators c
c = a + b
c = a - b
c = a * b
c = a / b
c = a << 2
c = a >> 1
c = b % 2
a < b
a <= b
a == b
a != b
a > b
a >= b
cdef extern from "templates.h":
cdef cppclass TemplateTest1[T]:
TemplateTest1()
T value
int t
T getValue()
cdef cppclass TemplateTest2[T, U]:
TemplateTest2()
T value1
U value2
T getValue1()
U getValue2()
cdef TemplateTest1[int] a
cdef TemplateTest1[int]* b = new TemplateTest1[int]()
cdef int c = a.getValue()
c = b.getValue()
cdef TemplateTest2[int, char] d
cdef TemplateTest2[int, char]* e = new TemplateTest2[int, char]()
c = d.getValue1()
c = e.getValue2()
cdef char f = d.getValue2()
f = e.getValue2()
del b, e
...@@ -11,6 +11,10 @@ cdef extern int (*iapfn())[5] ...@@ -11,6 +11,10 @@ cdef extern int (*iapfn())[5]
cdef extern char *(*cpapfn())[5] cdef extern char *(*cpapfn())[5]
cdef extern int fnargfn(int ()) cdef extern int fnargfn(int ())
cdef extern int ia[]
cdef extern int iaa[][3]
cdef extern int a(int[][3], int[][3][5])
cdef void f(): cdef void f():
cdef void *p=NULL cdef void *p=NULL
global ifnp, cpa global ifnp, cpa
......
"""A long module docstring.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer sit amet
mauris mauris, sit amet venenatis nisl. Vivamus a est porta enim sollicitudin
mollis. Proin fringilla massa vel ante gravida luctus. Nunc quis nunc id quam
hendrerit posuere. Cum sociis natoque penatibus et magnis dis parturient
montes, nascetur ridiculus mus. Aliquam porttitor interdum sollicitudin. Mauris
malesuada tellus tellus. Mauris condimentum nunc et sapien pellentesque
gravida. Suspendisse sed ipsum orci. Duis ut lacus dui. Integer ac gravida sem.
Vivamus fermentum porttitor velit ac blandit. Maecenas pulvinar ullamcorper
enim, vitae aliquet tortor scelerisque et. Vestibulum ante massa, sodales et
bibendum dignissim, consectetur vitae metus. Quisque vel dui erat, vel commodo
metus. Aliquam arcu dolor, viverra sit amet porttitor a, faucibus eu augue.
Sed ornare, enim eget ultricies suscipit, nunc dui lacinia enim, vitae tempus
nunc libero vitae ligula. Nam et commodo ligula. Pellentesque tincidunt lorem
at elit aliquam at fringilla libero tempor. Donec molestie consectetur nibh, ac
varius ante dictum id. Suspendisse lectus nibh, molestie vel dapibus eget,
egestas ut eros. Mauris vel mauris turpis, vitae bibendum nunc. Vestibulum
nulla enim, vestibulum vitae tincidunt et, gravida eu metus. Nulla sagittis,
odio a placerat laoreet, arcu lectus vestibulum nunc, in hendrerit tortor quam
sit amet turpis. In et purus vel dui pellentesque tincidunt. Donec dictum nibh
sed quam luctus sit amet luctus justo dapibus. Integer nulla elit, lacinia
aliquet euismod sed, tempus vitae lectus. Fusce non sapien dolor. Suspendisse
ut est ut dui tempor ultricies id ut elit. Aenean adipiscing sollicitudin enim,
nec porttitor est porttitor eget. Proin lobortis ante ut diam sodales volutpat.
Donec urna diam, porttitor nec laoreet ut, rhoncus non diam.
Ut sed mi vitae turpis semper semper. Integer sit amet lorem sapien. Aliquam
risus diam, vulputate id sagittis et, molestie ut lectus. Aliquam erat
volutpat. Morbi aliquet venenatis metus in posuere. Cras vitae purus nunc, ut
vestibulum ipsum. Nullam vehicula dui in urna iaculis lobortis. Ut a est non
est tincidunt iaculis. Vivamus rutrum velit non nunc malesuada sed bibendum mi
iaculis. Sed id lacus in sem tempor vestibulum. Cras bibendum accumsan
suscipit. Phasellus congue nisl consectetur turpis rhoncus aliquet posuere
libero fringilla. Sed eros tellus, hendrerit nec imperdiet vitae, blandit ac
dolor. Nulla facilisi. Morbi ullamcorper libero odio, at cursus tortor. Cras
ultricies tellus eget justo cursus cursus. Donec at mi massa, auctor suscipit
sem.
Proin dolor purus, semper sed ultrices ut, iaculis at tortor. Donec risus enim,
interdum et convallis nec, aliquam eget velit. Curabitur eget lectus dolor.
Integer id turpis eu nulla euismod tincidunt. Fusce elit nibh, dapibus sit amet
tempus ac, convallis eu libero. Donec dui justo, molestie sed euismod porta,
ultricies id orci. Praesent a tellus et risus faucibus porttitor pellentesque
in purus. Fusce blandit risus ac tortor viverra vitae molestie odio convallis.
Donec rhoncus volutpat mauris, sit amet mattis libero dapibus id. Ut rhoncus
venenatis nisi ac dictum. In non nulla eget massa convallis facilisis. Praesent
nec odio id odio semper lobortis non eu erat. Proin quis gravida magna. Sed
rhoncus lectus auctor arcu posuere a auctor dui pellentesque.
Sed enim nulla, luctus quis sagittis sed, vestibulum eget metus. Mauris ornare
pretium fringilla. Proin ligula eros, fermentum in placerat sit amet, placerat
vel mauris. Nulla magna enim, luctus eget euismod ac, lacinia vel lorem. Duis
mi leo, porttitor vitae dictum ac, ultrices iaculis metus. Quisque libero mi,
aliquet quis vestibulum eget, porttitor non justo. Praesent ac metus felis.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac
turpis egestas. Donec vel enim sit amet ante imperdiet commodo sed vel nisi.
Praesent semper viverra nulla vehicula sollicitudin. Fusce lacinia aliquet
ullamcorper. Donec vitae diam est. Integer volutpat hendrerit turpis ut
bibendum. Integer et dui augue.
Nunc ut nisl in felis feugiat semper nec sit amet purus. Proin convallis
ultrices nisl ut vehicula. Pellentesque neque mi, elementum vel placerat nec,
laoreet ac nulla. Pellentesque aliquam dui a metus iaculis posuere. Curabitur
dapibus faucibus metus. Donec quis diam dui. Proin at mi nec augue cursus
pulvinar eu vel metus. Curabitur eget turpis ac risus dignissim luctus sed id
ligula. Etiam lectus neque, varius ut euismod nec, euismod quis nulla. Ut
feugiat, quam id tempor luctus, metus eros lacinia diam, nec dapibus tellus dui
quis diam. Nam interdum, orci id fringilla mattis, ipsum eros pellentesque
turpis, hendrerit dignissim justo dui interdum ante. Curabitur aliquam nisi ut
dui lacinia tempor. Nulla lobortis tellus non sapien dignissim ut dapibus dui
aliquet. Nam scelerisque, urna a aliquam malesuada, mi tortor scelerisque
libero, quis pellentesque erat eros ut justo.
Phasellus nulla purus, suscipit vel gravida euismod, malesuada et odio.
Vestibulum non libero eget lacus venenatis auctor quis a est. Nunc id leo est.
Curabitur pulvinar viverra sapien at viverra. Cras pretium justo et lorem
lobortis id tempor nisi accumsan. Cras egestas tortor in risus hendrerit eu
varius purus suscipit. Nullam mauris eros, mattis at tempor vitae, mollis vitae
velit. Etiam at adipiscing lectus. Quisque molestie, metus id posuere pharetra,
lorem enim vehicula mauris, ut ultricies purus justo a lacus. Vivamus blandit
euismod adipiscing. Nam eu ligula at elit ultricies tempus. Nunc ac sodales
neque. Ut dui diam, porttitor a pulvinar vel, sodales sit amet turpis. Donec
vitae eros at neque luctus scelerisque. In consequat elementum iaculis. Donec
ullamcorper dolor eu quam volutpat rhoncus. Lorem ipsum dolor sit amet,
consectetur adipiscing elit. Cras laoreet ante eget dolor sagittis imperdiet.
Proin magna urna, porta id blandit nec, commodo eget lorem.
Etiam imperdiet, orci sit amet rutrum consectetur, orci augue tempus lacus, id
venenatis sapien nisl a est. Sed accumsan massa sed libero consectetur
scelerisque. Class aptent taciti sociosqu ad litora torquent per conubia
nostra, per inceptos himenaeos. Sed nunc risus, lobortis id egestas nec,
suscipit id magna. Morbi at iaculis mauris. Proin felis sem, tempus non
pellentesque congue, vehicula sit amet eros. Maecenas porttitor erat ac dolor
pharetra iaculis. Cras tincidunt, nulla eget malesuada egestas, sem diam
consequat quam, sed feugiat nulla orci at mauris. Quisque non arcu diam, ac
lacinia felis. Nunc iaculis mollis egestas. Etiam imperdiet dolor consectetur
eros feugiat fringilla sed in lacus. Nunc nec tincidunt dolor. Etiam sagittis
tortor condimentum nunc fermentum vestibulum. Vivamus lobortis, magna sit amet
scelerisque lobortis, sem eros molestie leo, eget aliquet ligula est in lectus.
Duis placerat porta pulvinar. Sed sed adipiscing ante. Vestibulum ante ipsum
primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nam accumsan
iaculis augue, sed varius dui sagittis id. Etiam sit amet eleifend augue.
Ut sit amet nibh sit amet justo tempor condimentum. Ut faucibus sagittis
volutpat. Duis vestibulum feugiat sollicitudin. Aenean cursus luctus urna at
consectetur. Nullam tincidunt, eros a iaculis sodales, tellus est imperdiet
arcu, sit amet tincidunt orci felis et tortor. Mauris rutrum venenatis nunc ut
rutrum. Phasellus nec erat magna, in tincidunt orci. Sed sit amet suscipit
tellus. Mauris ut nisi turpis. Suspendisse augue turpis, condimentum ac
bibendum in, vestibulum nec eros. Curabitur dapibus pulvinar vehicula. Fusce
consequat, erat in malesuada hendrerit, tellus urna pharetra lacus, sed euismod
nisi urna sed nisi. Etiam fermentum accumsan nunc, sed bibendum dui iaculis id.
Etiam blandit fermentum ligula nec viverra. Vivamus venenatis arcu in nulla
euismod euismod. Donec sit amet augue nec metus varius fringilla. Vivamus
pulvinar elit ac mi rhoncus in luctus diam egestas. Curabitur a felis eget arcu
pretium tempus eu sed mauris. Vestibulum ante ipsum primis in faucibus orci
luctus et ultrices posuere cubilia Curae;
Mauris malesuada, nibh ac venenatis hendrerit, ligula dui condimentum tellus,
sit amet pretium diam tortor vel risus. Suspendisse suscipit consequat eros id
dignissim. Cras interdum lorem ac massa euismod non porta enim pretium. Aliquam
ultrices nibh vitae ligula consectetur vel sollicitudin lacus volutpat.
Phasellus vulputate iaculis sem nec laoreet. Nam leo sem, tempor eu condimentum
id, imperdiet sed dolor. Donec pharetra velit non libero euismod tempor.
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
cubilia Curae; Sed fermentum, libero a posuere posuere, enim elit imperdiet
enim, a sollicitudin est felis non libero. Sed vel dolor ut arcu dapibus
iaculis nec a mauris. Morbi ullamcorper ultrices venenatis. Fusce luctus ante
sit amet lacus venenatis ut rutrum elit lobortis. Nulla fermentum tortor ac
sapien fringilla quis iaculis quam egestas.
Aliquam et tortor est, at elementum mauris. Morbi posuere erat nec leo
vulputate in pellentesque tortor condimentum. Vestibulum at orci augue. Aenean
pellentesque sapien id felis consequat varius. Suspendisse bibendum enim sit
amet mi imperdiet vel suscipit nisi tristique. Curabitur velit massa,
consectetur ac mattis vel, accumsan at nunc. Donec porta, nibh nec consequat
convallis, urna neque auctor erat, eu convallis lorem leo convallis turpis.
Morbi non mauris non metus ornare vulputate. Sed aliquet, dolor ut egestas
fermentum, metus purus mollis elit, nec commodo odio quam quis nisl. Aliquam
erat volutpat. Suspendisse sed faucibus urna. Integer suscipit rutrum
condimentum. Praesent dignissim libero eget metus luctus consectetur.
Vestibulum ac erat felis, vitae iaculis erat. Duis interdum lacinia arcu, non
lacinia urna luctus in. Curabitur feugiat sapien sapien, in vestibulum diam.
Phasellus lobortis massa ut metus pretium dignissim. Fusce quis sem odio.
Integer pellentesque sodales augue id tincidunt. Pellentesque habitant morbi
tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum
lorem odio, semper vel scelerisque sit amet, sagittis ac libero. Vestibulum
ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
Nam egestas ultricies dui at gravida. Duis tristique, eros id consectetur
pellentesque, nulla arcu ultricies tortor, ut pulvinar sapien lacus in elit.
Vivamus dolor massa, pulvinar at mollis vitae, euismod ut dolor. Vivamus a
magna ante. Vestibulum vitae fringilla leo. Ut gravida magna in quam fringilla
ultricies. Mauris rhoncus enim id sem interdum blandit. Pellentesque luctus leo
sit amet felis viverra ac accumsan purus mollis. Aenean pretium fringilla quam
nec laoreet.
Nulla id mauris mauris. Nam varius bibendum tristique. Integer ante felis,
volutpat sed dignissim vel, interdum molestie nisi. Etiam mollis accumsan elit,
ut gravida eros molestie nec. Nullam quis velit ac purus imperdiet sodales.
Donec semper placerat venenatis. Cras dolor risus, sodales sed scelerisque nec,
sollicitudin pretium felis. Quisque pretium felis id turpis bibendum pulvinar
ornare id nibh. Morbi lobortis leo non mi porttitor vulputate. Vestibulum nec
odio tellus, ut blandit ligula. In pellentesque neque sit amet dui pulvinar sed
laoreet dui vehicula. In hac habitasse platea dictumst. Etiam feugiat dictum
blandit. Praesent lacinia tincidunt elit, quis consectetur tortor molestie
commodo.
Ut sit amet accumsan lorem. Cras quam nunc, malesuada tempor volutpat vitae,
aliquam eu diam. Sed sem nibh, bibendum nec sollicitudin at, interdum et magna.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur
ridiculus mus. Aliquam vitae sem non elit pharetra vestibulum et condimentum
libero. Nam egestas ultricies hendrerit. Nunc nec fringilla nulla. Aliquam
risus tellus, hendrerit non dapibus a, tincidunt vel ante. Vivamus mollis,
magna et lacinia tincidunt, dui massa porta odio, ac ornare felis massa nec
lorem. Mauris sagittis lacus sed metus mollis ac egestas lectus porttitor.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque
penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer
vitae lacinia libero. Phasellus at neque enim, sit amet dictum mi.
Ut risus nisi, vestibulum vel congue eget, egestas in ipsum. Duis faucibus
tempus sodales. Duis convallis pellentesque arcu rhoncus congue. Nunc ac mauris
eu purus vestibulum congue. Praesent convallis semper augue vel volutpat.
Integer dictum varius placerat. Vestibulum convallis tortor non mi lacinia ac
aliquet dui ultricies. Donec ultrices purus eros. Maecenas venenatis posuere
massa, nec consectetur lacus cursus eget. Donec quam lacus, tempus id placerat
et, posuere sed libero. Proin auctor diam ut arcu viverra ut imperdiet tellus
dapibus.
Morbi ac mauris quis tellus porttitor eleifend. Sed et ante magna, ut sodales
sapien. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices
posuere cubilia Curae; Integer mattis venenatis mi non ullamcorper. Vestibulum
magna enim, aliquam non interdum ut, dignissim vitae ante. Praesent dignissim,
est at pretium posuere, nisl ante varius felis, vitae posuere enim nulla et
nunc. Morbi sagittis suscipit leo, eu accumsan ligula volutpat non. Donec ut
tincidunt magna. Integer ac libero mi. Sed non eros dolor, in tincidunt enim.
Curabitur iaculis erat quis felis iaculis ut volutpat augue malesuada.
Pellentesque eget arcu ligula, ut volutpat purus. Suspendisse dictum lorem quis
sapien lacinia pretium. Lorem ipsum dolor sit amet, consectetur adipiscing
elit.
Proin sagittis egestas massa et tempor. Mauris et eros ante, id porta sem. Duis
ac eros vitae ipsum ultrices malesuada eget a risus. Morbi imperdiet, est a
hendrerit tristique, mi erat molestie lacus, ac tempor risus nulla id erat.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac
turpis egestas. Etiam congue, lacus quis ultricies consequat, diam metus
convallis enim, ut volutpat enim urna vitae erat. In quam risus, molestie et
dapibus id, elementum sit amet ligula. Nam faucibus lacus id dolor facilisis
viverra. Nullam vehicula massa ac arcu consectetur vulputate. Praesent nec
augue ac justo dapibus vehicula. Aliquam consectetur hendrerit dolor, et mollis
nisl auctor ut.
Ut sagittis risus at felis fringilla ultricies. Vestibulum non urna nibh, nec
pretium dolor. Nulla imperdiet lobortis eros at pharetra. Vivamus cursus
pellentesque ornare. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Fusce arcu quam, pulvinar at rutrum vitae, ornare vitae leo. Maecenas vehicula
magna sit amet nulla bibendum condimentum. Curabitur ultrices tempor fringilla.
Vivamus pretium suscipit molestie. Donec arcu diam, ultricies ac pellentesque
eu, venenatis et sapien.
Nam dictum orci augue, vel eleifend leo. Nam at lacus sapien, nec pretium eros.
In egestas, enim sed sagittis feugiat, purus odio tristique lectus, vel
condimentum leo turpis ac odio. Nam iaculis mi quis odio posuere et venenatis
velit ultricies. Nulla facilisi. Proin nec dolor ac quam euismod gravida quis
et eros. Nam interdum condimentum mattis. Cum sociis natoque penatibus et
magnis dis parturient montes, nascetur ridiculus mus. Praesent a nisi eu massa
mollis posuere sed a nunc. Aenean tempus enim a justo rhoncus quis ultrices
nisl commodo.
Aenean imperdiet mauris a ipsum venenatis vel scelerisque lorem rutrum. Donec
ut nunc eros, eget accumsan felis. Nullam ullamcorper porta dictum. Donec
accumsan cursus vestibulum. Aenean in sapien velit. Vivamus nec massa mi. Fusce
felis tortor, bibendum non volutpat a, fringilla quis nisi. Duis varius
bibendum erat, quis fermentum sem accumsan eget. Maecenas massa felis, porta
sed laoreet eu, luctus eu lectus. Cras id nibh vitae erat fringilla rutrum.
Maecenas eget consequat est. Vivamus viverra, felis vel faucibus rhoncus, quam
ipsum elementum libero, quis convallis urna purus ut mauris. Nam quis urna
vitae enim consequat placerat. Vivamus congue augue sit amet lectus luctus
tempor. Cras ut justo convallis est egestas pellentesque ac nec orci.
Vivamus rutrum bibendum ante, at cursus erat pulvinar ornare. Proin imperdiet
scelerisque ante eu vestibulum. Nullam ullamcorper metus nec purus auctor
lobortis. Proin sed lacus et ipsum tempor tempus. Vivamus odio dolor, vulputate
vitae semper sit amet, aliquet egestas orci. Nullam non quam eu quam sagittis
porta. Nunc in velit id erat commodo viverra. Praesent nec est augue, nec
sagittis erat. Cras sed turpis quis enim tempor sagittis. Donec in justo ac
nisl porta condimentum id vestibulum nulla. Nam elementum ultricies nunc a
bibendum.
Aenean tincidunt nisl non augue pellentesque sit amet convallis neque semper.
Cras placerat suscipit massa sed volutpat. Integer vulputate imperdiet enim,
vitae vulputate sapien mattis feugiat. Vivamus pharetra facilisis mauris a
gravida. Nulla non venenatis est. Duis lobortis consectetur sem ac aliquam. In
eget sapien odio. Vivamus pulvinar ultricies magna, quis laoreet dui porta et.
Integer tempus malesuada velit, et consequat odio ultrices sed. Aliquam
malesuada commodo diam vel posuere. Morbi porttitor, elit vitae auctor gravida,
lorem massa bibendum arcu, vel placerat nulla justo at augue.
Aliquam libero quam, mattis blandit congue sit amet, fermentum ac augue.
Aliquam malesuada molestie vulputate. Duis id porta augue. Vestibulum diam
dolor, ultrices sit amet porttitor id, convallis id lectus. Etiam ac augue
tincidunt nisi tempor molestie euismod id nisl. Nam et tortor ac arcu viverra
pulvinar. Fusce pulvinar rhoncus leo, a faucibus enim interdum non. Aliquam
vulputate mattis consectetur. Pellentesque sit amet quam sem. Cras eget arcu eu
elit volutpat volutpat. Integer sed varius enim. Integer sit amet felis orci,
id dignissim sapien. Sed vitae lorem sed libero facilisis fringilla.
Pellentesque congue tristique purus, eleifend semper risus suscipit quis.
Phasellus rutrum quam vitae arcu vulputate porta. Sed tristique arcu nec mi
porttitor lacinia.
Donec congue feugiat diam quis pretium. Vivamus at luctus nunc. Integer
vulputate laoreet mauris quis auctor. Nunc at ultrices libero. Maecenas porta
faucibus purus non vehicula. Sed sit amet metus vitae mi ultrices scelerisque
nec quis risus. Phasellus pellentesque tincidunt massa id ultricies. Aliquam
dictum arcu ac dolor interdum rutrum. Nulla facilisi. Duis nisi est, tincidunt
a sagittis id, sollicitudin at odio. Curabitur sed est eu sapien faucibus
dignissim in quis tortor.
Nunc ac elit tortor, non lobortis massa. Proin posuere ante ut metus vehicula
suscipit. Proin mattis mauris ac lectus consequat rutrum. Nam arcu lectus,
commodo non pretium a, pharetra semper dolor. Fusce eleifend hendrerit
adipiscing. Nunc et eleifend erat. Suspendisse tempus nisl ut arcu blandit ut
adipiscing nisi tristique. Suspendisse molestie facilisis risus sed fermentum.
Praesent tempor convallis ultricies. Integer et elit velit, at consectetur
risus.
Vestibulum mollis adipiscing sodales. Vestibulum ante ipsum primis in faucibus
orci luctus et ultrices posuere cubilia Curae; Mauris dictum molestie porta.
Nam convallis nisl quis lacus vulputate in convallis risus sagittis. Vivamus
accumsan faucibus cursus. Ut ultricies imperdiet ligula scelerisque blandit. In
ornare egestas purus, at convallis velit egestas laoreet. Class aptent taciti
sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla
quis imperdiet est. Nunc tempus magna quis lacus feugiat et posuere lacus
vehicula. Cras lacinia aliquam est at vehicula. Aenean congue elit in ante
dignissim vitae fermentum lectus aliquam. Mauris at odio magna, at interdum
dui. Cras fringilla mi velit, nec varius neque.
Fusce et volutpat lacus. Suspendisse id turpis et urna varius convallis in eu
purus. Nulla facilisi. Etiam mauris nisl, ultrices ac porttitor sit amet,
facilisis ut neque. Nullam ut velit quis velit tincidunt rhoncus. Praesent
tristique porttitor euismod. Nulla non felis ante, feugiat commodo turpis. In
nec venenatis mi. Duis tempus tempor purus, vitae consectetur mi ornare eu.
Proin sed consequat erat. Quisque nec sem dui. Nam semper, ligula facilisis
pretium interdum, diam lectus sollicitudin lorem, in elementum nisi lorem
scelerisque justo. Nullam ac fringilla nunc. Maecenas malesuada ligula in massa
sollicitudin sit amet auctor ipsum malesuada. Vestibulum ut augue in magna
lobortis varius eget in ipsum. In hac habitasse platea dictumst.
Cras vel sagittis mi. Aenean urna sapien, ultrices et tristique et, aliquam vel
libero. Nullam in consequat ante. Suspendisse libero augue, pulvinar a
dignissim vitae, fringilla malesuada dui. Phasellus augue ante, pulvinar eget
tincidunt vel, venenatis sed arcu. Pellentesque ac purus orci, vel molestie
turpis. Nulla consectetur sollicitudin dolor, sed ornare arcu accumsan
fermentum. Fusce vestibulum nisi at leo interdum eu sollicitudin lacus dictum.
Fusce malesuada consequat ipsum ut convallis. Maecenas in eros sit amet elit
consectetur fringilla nec a nibh. Ut et velit vel ligula pharetra elementum.
Nullam aliquam, tellus vel cursus lacinia, dui libero dictum turpis, nec
lacinia dolor nunc vel diam. Pellentesque convallis dui quis lacus ornare at
rutrum lorem pellentesque. Suspendisse potenti. Cum sociis natoque penatibus et
magnis dis parturient montes, nascetur ridiculus mus.
Nunc ac nibh sed mauris ornare cursus. Praesent enim mauris, tincidunt vitae
convallis ac, ultricies imperdiet sapien. Duis sodales ligula eget lorem
suscipit sed consectetur metus pretium. Nam in magna augue, quis volutpat
mauris. Quisque pretium lobortis orci quis laoreet. Nam ut nisi diam. Sed
ultrices ultrices dapibus. Integer feugiat mauris id orci pulvinar eu tempus
nibh viverra. Etiam venenatis bibendum massa a consequat. Fusce interdum velit
ac mauris rhoncus non cursus neque consectetur. Vestibulum dictum eros ac metus
fringilla venenatis. Phasellus auctor dui non nulla molestie id malesuada
mauris euismod. Aenean id tortor ac justo eleifend mollis non vel arcu. Duis ac
lorem tortor. Donec volutpat purus sed nunc luctus interdum hendrerit nulla
ullamcorper. Sed consectetur interdum aliquet. Proin ullamcorper risus ut ante
lacinia sagittis. Nunc varius eleifend purus, ac pellentesque urna viverra id.
Praesent euismod, sapien accumsan gravida dictum, massa massa euismod sapien,
ut auctor tellus arcu sed diam.
Vivamus tincidunt dolor non lorem pellentesque at tempus elit adipiscing.
Vestibulum tempor aliquam consectetur. Mauris nec dictum nisl. Donec
scelerisque ornare condimentum. Phasellus laoreet justo nec nibh convallis
convallis. Duis id orci sapien, eget pulvinar justo. Aenean id arcu felis, eu
iaculis nibh. Aenean eleifend pretium rutrum. Aliquam molestie sem quis tellus
aliquam eleifend. Mauris et purus orci. Nunc et accumsan tortor. Phasellus
semper eleifend nisi, a faucibus risus vehicula id. Lorem ipsum dolor sit amet,
consectetur adipiscing elit. Maecenas in felis et est lacinia eleifend vel sed
ipsum. Aliquam commodo molestie lorem id hendrerit. Nam sed tellus urna, sed
dignissim eros.
"""
A_LONG_STRING = """A long string.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer sit amet
mauris mauris, sit amet venenatis nisl. Vivamus a est porta enim sollicitudin
mollis. Proin fringilla massa vel ante gravida luctus. Nunc quis nunc id quam
hendrerit posuere. Cum sociis natoque penatibus et magnis dis parturient
montes, nascetur ridiculus mus. Aliquam porttitor interdum sollicitudin. Mauris
malesuada tellus tellus. Mauris condimentum nunc et sapien pellentesque
gravida. Suspendisse sed ipsum orci. Duis ut lacus dui. Integer ac gravida sem.
Vivamus fermentum porttitor velit ac blandit. Maecenas pulvinar ullamcorper
enim, vitae aliquet tortor scelerisque et. Vestibulum ante massa, sodales et
bibendum dignissim, consectetur vitae metus. Quisque vel dui erat, vel commodo
metus. Aliquam arcu dolor, viverra sit amet porttitor a, faucibus eu augue.
Sed ornare, enim eget ultricies suscipit, nunc dui lacinia enim, vitae tempus
nunc libero vitae ligula. Nam et commodo ligula. Pellentesque tincidunt lorem
at elit aliquam at fringilla libero tempor. Donec molestie consectetur nibh, ac
varius ante dictum id. Suspendisse lectus nibh, molestie vel dapibus eget,
egestas ut eros. Mauris vel mauris turpis, vitae bibendum nunc. Vestibulum
nulla enim, vestibulum vitae tincidunt et, gravida eu metus. Nulla sagittis,
odio a placerat laoreet, arcu lectus vestibulum nunc, in hendrerit tortor quam
sit amet turpis. In et purus vel dui pellentesque tincidunt. Donec dictum nibh
sed quam luctus sit amet luctus justo dapibus. Integer nulla elit, lacinia
aliquet euismod sed, tempus vitae lectus. Fusce non sapien dolor. Suspendisse
ut est ut dui tempor ultricies id ut elit. Aenean adipiscing sollicitudin enim,
nec porttitor est porttitor eget. Proin lobortis ante ut diam sodales volutpat.
Donec urna diam, porttitor nec laoreet ut, rhoncus non diam.
Ut sed mi vitae turpis semper semper. Integer sit amet lorem sapien. Aliquam
risus diam, vulputate id sagittis et, molestie ut lectus. Aliquam erat
volutpat. Morbi aliquet venenatis metus in posuere. Cras vitae purus nunc, ut
vestibulum ipsum. Nullam vehicula dui in urna iaculis lobortis. Ut a est non
est tincidunt iaculis. Vivamus rutrum velit non nunc malesuada sed bibendum mi
iaculis. Sed id lacus in sem tempor vestibulum. Cras bibendum accumsan
suscipit. Phasellus congue nisl consectetur turpis rhoncus aliquet posuere
libero fringilla. Sed eros tellus, hendrerit nec imperdiet vitae, blandit ac
dolor. Nulla facilisi. Morbi ullamcorper libero odio, at cursus tortor. Cras
ultricies tellus eget justo cursus cursus. Donec at mi massa, auctor suscipit
sem.
Proin dolor purus, semper sed ultrices ut, iaculis at tortor. Donec risus enim,
interdum et convallis nec, aliquam eget velit. Curabitur eget lectus dolor.
Integer id turpis eu nulla euismod tincidunt. Fusce elit nibh, dapibus sit amet
tempus ac, convallis eu libero. Donec dui justo, molestie sed euismod porta,
ultricies id orci. Praesent a tellus et risus faucibus porttitor pellentesque
in purus. Fusce blandit risus ac tortor viverra vitae molestie odio convallis.
Donec rhoncus volutpat mauris, sit amet mattis libero dapibus id. Ut rhoncus
venenatis nisi ac dictum. In non nulla eget massa convallis facilisis. Praesent
nec odio id odio semper lobortis non eu erat. Proin quis gravida magna. Sed
rhoncus lectus auctor arcu posuere a auctor dui pellentesque.
Sed enim nulla, luctus quis sagittis sed, vestibulum eget metus. Mauris ornare
pretium fringilla. Proin ligula eros, fermentum in placerat sit amet, placerat
vel mauris. Nulla magna enim, luctus eget euismod ac, lacinia vel lorem. Duis
mi leo, porttitor vitae dictum ac, ultrices iaculis metus. Quisque libero mi,
aliquet quis vestibulum eget, porttitor non justo. Praesent ac metus felis.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac
turpis egestas. Donec vel enim sit amet ante imperdiet commodo sed vel nisi.
Praesent semper viverra nulla vehicula sollicitudin. Fusce lacinia aliquet
ullamcorper. Donec vitae diam est. Integer volutpat hendrerit turpis ut
bibendum. Integer et dui augue.
Nunc ut nisl in felis feugiat semper nec sit amet purus. Proin convallis
ultrices nisl ut vehicula. Pellentesque neque mi, elementum vel placerat nec,
laoreet ac nulla. Pellentesque aliquam dui a metus iaculis posuere. Curabitur
dapibus faucibus metus. Donec quis diam dui. Proin at mi nec augue cursus
pulvinar eu vel metus. Curabitur eget turpis ac risus dignissim luctus sed id
ligula. Etiam lectus neque, varius ut euismod nec, euismod quis nulla. Ut
feugiat, quam id tempor luctus, metus eros lacinia diam, nec dapibus tellus dui
quis diam. Nam interdum, orci id fringilla mattis, ipsum eros pellentesque
turpis, hendrerit dignissim justo dui interdum ante. Curabitur aliquam nisi ut
dui lacinia tempor. Nulla lobortis tellus non sapien dignissim ut dapibus dui
aliquet. Nam scelerisque, urna a aliquam malesuada, mi tortor scelerisque
libero, quis pellentesque erat eros ut justo.
Phasellus nulla purus, suscipit vel gravida euismod, malesuada et odio.
Vestibulum non libero eget lacus venenatis auctor quis a est. Nunc id leo est.
Curabitur pulvinar viverra sapien at viverra. Cras pretium justo et lorem
lobortis id tempor nisi accumsan. Cras egestas tortor in risus hendrerit eu
varius purus suscipit. Nullam mauris eros, mattis at tempor vitae, mollis vitae
velit. Etiam at adipiscing lectus. Quisque molestie, metus id posuere pharetra,
lorem enim vehicula mauris, ut ultricies purus justo a lacus. Vivamus blandit
euismod adipiscing. Nam eu ligula at elit ultricies tempus. Nunc ac sodales
neque. Ut dui diam, porttitor a pulvinar vel, sodales sit amet turpis. Donec
vitae eros at neque luctus scelerisque. In consequat elementum iaculis. Donec
ullamcorper dolor eu quam volutpat rhoncus. Lorem ipsum dolor sit amet,
consectetur adipiscing elit. Cras laoreet ante eget dolor sagittis imperdiet.
Proin magna urna, porta id blandit nec, commodo eget lorem.
Etiam imperdiet, orci sit amet rutrum consectetur, orci augue tempus lacus, id
venenatis sapien nisl a est. Sed accumsan massa sed libero consectetur
scelerisque. Class aptent taciti sociosqu ad litora torquent per conubia
nostra, per inceptos himenaeos. Sed nunc risus, lobortis id egestas nec,
suscipit id magna. Morbi at iaculis mauris. Proin felis sem, tempus non
pellentesque congue, vehicula sit amet eros. Maecenas porttitor erat ac dolor
pharetra iaculis. Cras tincidunt, nulla eget malesuada egestas, sem diam
consequat quam, sed feugiat nulla orci at mauris. Quisque non arcu diam, ac
lacinia felis. Nunc iaculis mollis egestas. Etiam imperdiet dolor consectetur
eros feugiat fringilla sed in lacus. Nunc nec tincidunt dolor. Etiam sagittis
tortor condimentum nunc fermentum vestibulum. Vivamus lobortis, magna sit amet
scelerisque lobortis, sem eros molestie leo, eget aliquet ligula est in lectus.
Duis placerat porta pulvinar. Sed sed adipiscing ante. Vestibulum ante ipsum
primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nam accumsan
iaculis augue, sed varius dui sagittis id. Etiam sit amet eleifend augue.
Ut sit amet nibh sit amet justo tempor condimentum. Ut faucibus sagittis
volutpat. Duis vestibulum feugiat sollicitudin. Aenean cursus luctus urna at
consectetur. Nullam tincidunt, eros a iaculis sodales, tellus est imperdiet
arcu, sit amet tincidunt orci felis et tortor. Mauris rutrum venenatis nunc ut
rutrum. Phasellus nec erat magna, in tincidunt orci. Sed sit amet suscipit
tellus. Mauris ut nisi turpis. Suspendisse augue turpis, condimentum ac
bibendum in, vestibulum nec eros. Curabitur dapibus pulvinar vehicula. Fusce
consequat, erat in malesuada hendrerit, tellus urna pharetra lacus, sed euismod
nisi urna sed nisi. Etiam fermentum accumsan nunc, sed bibendum dui iaculis id.
Etiam blandit fermentum ligula nec viverra. Vivamus venenatis arcu in nulla
euismod euismod. Donec sit amet augue nec metus varius fringilla. Vivamus
pulvinar elit ac mi rhoncus in luctus diam egestas. Curabitur a felis eget arcu
pretium tempus eu sed mauris. Vestibulum ante ipsum primis in faucibus orci
luctus et ultrices posuere cubilia Curae;
Mauris malesuada, nibh ac venenatis hendrerit, ligula dui condimentum tellus,
sit amet pretium diam tortor vel risus. Suspendisse suscipit consequat eros id
dignissim. Cras interdum lorem ac massa euismod non porta enim pretium. Aliquam
ultrices nibh vitae ligula consectetur vel sollicitudin lacus volutpat.
Phasellus vulputate iaculis sem nec laoreet. Nam leo sem, tempor eu condimentum
id, imperdiet sed dolor. Donec pharetra velit non libero euismod tempor.
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
cubilia Curae; Sed fermentum, libero a posuere posuere, enim elit imperdiet
enim, a sollicitudin est felis non libero. Sed vel dolor ut arcu dapibus
iaculis nec a mauris. Morbi ullamcorper ultrices venenatis. Fusce luctus ante
sit amet lacus venenatis ut rutrum elit lobortis. Nulla fermentum tortor ac
sapien fringilla quis iaculis quam egestas.
Aliquam et tortor est, at elementum mauris. Morbi posuere erat nec leo
vulputate in pellentesque tortor condimentum. Vestibulum at orci augue. Aenean
pellentesque sapien id felis consequat varius. Suspendisse bibendum enim sit
amet mi imperdiet vel suscipit nisi tristique. Curabitur velit massa,
consectetur ac mattis vel, accumsan at nunc. Donec porta, nibh nec consequat
convallis, urna neque auctor erat, eu convallis lorem leo convallis turpis.
Morbi non mauris non metus ornare vulputate. Sed aliquet, dolor ut egestas
fermentum, metus purus mollis elit, nec commodo odio quam quis nisl. Aliquam
erat volutpat. Suspendisse sed faucibus urna. Integer suscipit rutrum
condimentum. Praesent dignissim libero eget metus luctus consectetur.
Vestibulum ac erat felis, vitae iaculis erat. Duis interdum lacinia arcu, non
lacinia urna luctus in. Curabitur feugiat sapien sapien, in vestibulum diam.
Phasellus lobortis massa ut metus pretium dignissim. Fusce quis sem odio.
Integer pellentesque sodales augue id tincidunt. Pellentesque habitant morbi
tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum
lorem odio, semper vel scelerisque sit amet, sagittis ac libero. Vestibulum
ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
Nam egestas ultricies dui at gravida. Duis tristique, eros id consectetur
pellentesque, nulla arcu ultricies tortor, ut pulvinar sapien lacus in elit.
Vivamus dolor massa, pulvinar at mollis vitae, euismod ut dolor. Vivamus a
magna ante. Vestibulum vitae fringilla leo. Ut gravida magna in quam fringilla
ultricies. Mauris rhoncus enim id sem interdum blandit. Pellentesque luctus leo
sit amet felis viverra ac accumsan purus mollis. Aenean pretium fringilla quam
nec laoreet.
Nulla id mauris mauris. Nam varius bibendum tristique. Integer ante felis,
volutpat sed dignissim vel, interdum molestie nisi. Etiam mollis accumsan elit,
ut gravida eros molestie nec. Nullam quis velit ac purus imperdiet sodales.
Donec semper placerat venenatis. Cras dolor risus, sodales sed scelerisque nec,
sollicitudin pretium felis. Quisque pretium felis id turpis bibendum pulvinar
ornare id nibh. Morbi lobortis leo non mi porttitor vulputate. Vestibulum nec
odio tellus, ut blandit ligula. In pellentesque neque sit amet dui pulvinar sed
laoreet dui vehicula. In hac habitasse platea dictumst. Etiam feugiat dictum
blandit. Praesent lacinia tincidunt elit, quis consectetur tortor molestie
commodo.
Ut sit amet accumsan lorem. Cras quam nunc, malesuada tempor volutpat vitae,
aliquam eu diam. Sed sem nibh, bibendum nec sollicitudin at, interdum et magna.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur
ridiculus mus. Aliquam vitae sem non elit pharetra vestibulum et condimentum
libero. Nam egestas ultricies hendrerit. Nunc nec fringilla nulla. Aliquam
risus tellus, hendrerit non dapibus a, tincidunt vel ante. Vivamus mollis,
magna et lacinia tincidunt, dui massa porta odio, ac ornare felis massa nec
lorem. Mauris sagittis lacus sed metus mollis ac egestas lectus porttitor.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque
penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer
vitae lacinia libero. Phasellus at neque enim, sit amet dictum mi.
Ut risus nisi, vestibulum vel congue eget, egestas in ipsum. Duis faucibus
tempus sodales. Duis convallis pellentesque arcu rhoncus congue. Nunc ac mauris
eu purus vestibulum congue. Praesent convallis semper augue vel volutpat.
Integer dictum varius placerat. Vestibulum convallis tortor non mi lacinia ac
aliquet dui ultricies. Donec ultrices purus eros. Maecenas venenatis posuere
massa, nec consectetur lacus cursus eget. Donec quam lacus, tempus id placerat
et, posuere sed libero. Proin auctor diam ut arcu viverra ut imperdiet tellus
dapibus.
Morbi ac mauris quis tellus porttitor eleifend. Sed et ante magna, ut sodales
sapien. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices
posuere cubilia Curae; Integer mattis venenatis mi non ullamcorper. Vestibulum
magna enim, aliquam non interdum ut, dignissim vitae ante. Praesent dignissim,
est at pretium posuere, nisl ante varius felis, vitae posuere enim nulla et
nunc. Morbi sagittis suscipit leo, eu accumsan ligula volutpat non. Donec ut
tincidunt magna. Integer ac libero mi. Sed non eros dolor, in tincidunt enim.
Curabitur iaculis erat quis felis iaculis ut volutpat augue malesuada.
Pellentesque eget arcu ligula, ut volutpat purus. Suspendisse dictum lorem quis
sapien lacinia pretium. Lorem ipsum dolor sit amet, consectetur adipiscing
elit.
Proin sagittis egestas massa et tempor. Mauris et eros ante, id porta sem. Duis
ac eros vitae ipsum ultrices malesuada eget a risus. Morbi imperdiet, est a
hendrerit tristique, mi erat molestie lacus, ac tempor risus nulla id erat.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac
turpis egestas. Etiam congue, lacus quis ultricies consequat, diam metus
convallis enim, ut volutpat enim urna vitae erat. In quam risus, molestie et
dapibus id, elementum sit amet ligula. Nam faucibus lacus id dolor facilisis
viverra. Nullam vehicula massa ac arcu consectetur vulputate. Praesent nec
augue ac justo dapibus vehicula. Aliquam consectetur hendrerit dolor, et mollis
nisl auctor ut.
Ut sagittis risus at felis fringilla ultricies. Vestibulum non urna nibh, nec
pretium dolor. Nulla imperdiet lobortis eros at pharetra. Vivamus cursus
pellentesque ornare. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Fusce arcu quam, pulvinar at rutrum vitae, ornare vitae leo. Maecenas vehicula
magna sit amet nulla bibendum condimentum. Curabitur ultrices tempor fringilla.
Vivamus pretium suscipit molestie. Donec arcu diam, ultricies ac pellentesque
eu, venenatis et sapien.
Nam dictum orci augue, vel eleifend leo. Nam at lacus sapien, nec pretium eros.
In egestas, enim sed sagittis feugiat, purus odio tristique lectus, vel
condimentum leo turpis ac odio. Nam iaculis mi quis odio posuere et venenatis
velit ultricies. Nulla facilisi. Proin nec dolor ac quam euismod gravida quis
et eros. Nam interdum condimentum mattis. Cum sociis natoque penatibus et
magnis dis parturient montes, nascetur ridiculus mus. Praesent a nisi eu massa
mollis posuere sed a nunc. Aenean tempus enim a justo rhoncus quis ultrices
nisl commodo.
Aenean imperdiet mauris a ipsum venenatis vel scelerisque lorem rutrum. Donec
ut nunc eros, eget accumsan felis. Nullam ullamcorper porta dictum. Donec
accumsan cursus vestibulum. Aenean in sapien velit. Vivamus nec massa mi. Fusce
felis tortor, bibendum non volutpat a, fringilla quis nisi. Duis varius
bibendum erat, quis fermentum sem accumsan eget. Maecenas massa felis, porta
sed laoreet eu, luctus eu lectus. Cras id nibh vitae erat fringilla rutrum.
Maecenas eget consequat est. Vivamus viverra, felis vel faucibus rhoncus, quam
ipsum elementum libero, quis convallis urna purus ut mauris. Nam quis urna
vitae enim consequat placerat. Vivamus congue augue sit amet lectus luctus
tempor. Cras ut justo convallis est egestas pellentesque ac nec orci.
Vivamus rutrum bibendum ante, at cursus erat pulvinar ornare. Proin imperdiet
scelerisque ante eu vestibulum. Nullam ullamcorper metus nec purus auctor
lobortis. Proin sed lacus et ipsum tempor tempus. Vivamus odio dolor, vulputate
vitae semper sit amet, aliquet egestas orci. Nullam non quam eu quam sagittis
porta. Nunc in velit id erat commodo viverra. Praesent nec est augue, nec
sagittis erat. Cras sed turpis quis enim tempor sagittis. Donec in justo ac
nisl porta condimentum id vestibulum nulla. Nam elementum ultricies nunc a
bibendum.
Aenean tincidunt nisl non augue pellentesque sit amet convallis neque semper.
Cras placerat suscipit massa sed volutpat. Integer vulputate imperdiet enim,
vitae vulputate sapien mattis feugiat. Vivamus pharetra facilisis mauris a
gravida. Nulla non venenatis est. Duis lobortis consectetur sem ac aliquam. In
eget sapien odio. Vivamus pulvinar ultricies magna, quis laoreet dui porta et.
Integer tempus malesuada velit, et consequat odio ultrices sed. Aliquam
malesuada commodo diam vel posuere. Morbi porttitor, elit vitae auctor gravida,
lorem massa bibendum arcu, vel placerat nulla justo at augue.
Aliquam libero quam, mattis blandit congue sit amet, fermentum ac augue.
Aliquam malesuada molestie vulputate. Duis id porta augue. Vestibulum diam
dolor, ultrices sit amet porttitor id, convallis id lectus. Etiam ac augue
tincidunt nisi tempor molestie euismod id nisl. Nam et tortor ac arcu viverra
pulvinar. Fusce pulvinar rhoncus leo, a faucibus enim interdum non. Aliquam
vulputate mattis consectetur. Pellentesque sit amet quam sem. Cras eget arcu eu
elit volutpat volutpat. Integer sed varius enim. Integer sit amet felis orci,
id dignissim sapien. Sed vitae lorem sed libero facilisis fringilla.
Pellentesque congue tristique purus, eleifend semper risus suscipit quis.
Phasellus rutrum quam vitae arcu vulputate porta. Sed tristique arcu nec mi
porttitor lacinia.
Donec congue feugiat diam quis pretium. Vivamus at luctus nunc. Integer
vulputate laoreet mauris quis auctor. Nunc at ultrices libero. Maecenas porta
faucibus purus non vehicula. Sed sit amet metus vitae mi ultrices scelerisque
nec quis risus. Phasellus pellentesque tincidunt massa id ultricies. Aliquam
dictum arcu ac dolor interdum rutrum. Nulla facilisi. Duis nisi est, tincidunt
a sagittis id, sollicitudin at odio. Curabitur sed est eu sapien faucibus
dignissim in quis tortor.
Nunc ac elit tortor, non lobortis massa. Proin posuere ante ut metus vehicula
suscipit. Proin mattis mauris ac lectus consequat rutrum. Nam arcu lectus,
commodo non pretium a, pharetra semper dolor. Fusce eleifend hendrerit
adipiscing. Nunc et eleifend erat. Suspendisse tempus nisl ut arcu blandit ut
adipiscing nisi tristique. Suspendisse molestie facilisis risus sed fermentum.
Praesent tempor convallis ultricies. Integer et elit velit, at consectetur
risus.
Vestibulum mollis adipiscing sodales. Vestibulum ante ipsum primis in faucibus
orci luctus et ultrices posuere cubilia Curae; Mauris dictum molestie porta.
Nam convallis nisl quis lacus vulputate in convallis risus sagittis. Vivamus
accumsan faucibus cursus. Ut ultricies imperdiet ligula scelerisque blandit. In
ornare egestas purus, at convallis velit egestas laoreet. Class aptent taciti
sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla
quis imperdiet est. Nunc tempus magna quis lacus feugiat et posuere lacus
vehicula. Cras lacinia aliquam est at vehicula. Aenean congue elit in ante
dignissim vitae fermentum lectus aliquam. Mauris at odio magna, at interdum
dui. Cras fringilla mi velit, nec varius neque.
Fusce et volutpat lacus. Suspendisse id turpis et urna varius convallis in eu
purus. Nulla facilisi. Etiam mauris nisl, ultrices ac porttitor sit amet,
facilisis ut neque. Nullam ut velit quis velit tincidunt rhoncus. Praesent
tristique porttitor euismod. Nulla non felis ante, feugiat commodo turpis. In
nec venenatis mi. Duis tempus tempor purus, vitae consectetur mi ornare eu.
Proin sed consequat erat. Quisque nec sem dui. Nam semper, ligula facilisis
pretium interdum, diam lectus sollicitudin lorem, in elementum nisi lorem
scelerisque justo. Nullam ac fringilla nunc. Maecenas malesuada ligula in massa
sollicitudin sit amet auctor ipsum malesuada. Vestibulum ut augue in magna
lobortis varius eget in ipsum. In hac habitasse platea dictumst.
Cras vel sagittis mi. Aenean urna sapien, ultrices et tristique et, aliquam vel
libero. Nullam in consequat ante. Suspendisse libero augue, pulvinar a
dignissim vitae, fringilla malesuada dui. Phasellus augue ante, pulvinar eget
tincidunt vel, venenatis sed arcu. Pellentesque ac purus orci, vel molestie
turpis. Nulla consectetur sollicitudin dolor, sed ornare arcu accumsan
fermentum. Fusce vestibulum nisi at leo interdum eu sollicitudin lacus dictum.
Fusce malesuada consequat ipsum ut convallis. Maecenas in eros sit amet elit
consectetur fringilla nec a nibh. Ut et velit vel ligula pharetra elementum.
Nullam aliquam, tellus vel cursus lacinia, dui libero dictum turpis, nec
lacinia dolor nunc vel diam. Pellentesque convallis dui quis lacus ornare at
rutrum lorem pellentesque. Suspendisse potenti. Cum sociis natoque penatibus et
magnis dis parturient montes, nascetur ridiculus mus.
Nunc ac nibh sed mauris ornare cursus. Praesent enim mauris, tincidunt vitae
convallis ac, ultricies imperdiet sapien. Duis sodales ligula eget lorem
suscipit sed consectetur metus pretium. Nam in magna augue, quis volutpat
mauris. Quisque pretium lobortis orci quis laoreet. Nam ut nisi diam. Sed
ultrices ultrices dapibus. Integer feugiat mauris id orci pulvinar eu tempus
nibh viverra. Etiam venenatis bibendum massa a consequat. Fusce interdum velit
ac mauris rhoncus non cursus neque consectetur. Vestibulum dictum eros ac metus
fringilla venenatis. Phasellus auctor dui non nulla molestie id malesuada
mauris euismod. Aenean id tortor ac justo eleifend mollis non vel arcu. Duis ac
lorem tortor. Donec volutpat purus sed nunc luctus interdum hendrerit nulla
ullamcorper. Sed consectetur interdum aliquet. Proin ullamcorper risus ut ante
lacinia sagittis. Nunc varius eleifend purus, ac pellentesque urna viverra id.
Praesent euismod, sapien accumsan gravida dictum, massa massa euismod sapien,
ut auctor tellus arcu sed diam.
Vivamus tincidunt dolor non lorem pellentesque at tempus elit adipiscing.
Vestibulum tempor aliquam consectetur. Mauris nec dictum nisl. Donec
scelerisque ornare condimentum. Phasellus laoreet justo nec nibh convallis
convallis. Duis id orci sapien, eget pulvinar justo. Aenean id arcu felis, eu
iaculis nibh. Aenean eleifend pretium rutrum. Aliquam molestie sem quis tellus
aliquam eleifend. Mauris et purus orci. Nunc et accumsan tortor. Phasellus
semper eleifend nisi, a faucibus risus vehicula id. Lorem ipsum dolor sit amet,
consectetur adipiscing elit. Maecenas in felis et est lacinia eleifend vel sed
ipsum. Aliquam commodo molestie lorem id hendrerit. Nam sed tellus urna, sed
dignissim eros.
"""
def a_function():
""""A long function docstring.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer sit amet
mauris mauris, sit amet venenatis nisl. Vivamus a est porta enim
sollicitudin mollis. Proin fringilla massa vel ante gravida luctus. Nunc
quis nunc id quam hendrerit posuere. Cum sociis natoque penatibus et magnis
dis parturient montes, nascetur ridiculus mus. Aliquam porttitor interdum
sollicitudin. Mauris malesuada tellus tellus. Mauris condimentum nunc et
sapien pellentesque gravida. Suspendisse sed ipsum orci. Duis ut lacus dui.
Integer ac gravida sem. Vivamus fermentum porttitor velit ac blandit.
Maecenas pulvinar ullamcorper enim, vitae aliquet tortor scelerisque et.
Vestibulum ante massa, sodales et bibendum dignissim, consectetur vitae
metus. Quisque vel dui erat, vel commodo metus. Aliquam arcu dolor, viverra
sit amet porttitor a, faucibus eu augue.
Sed ornare, enim eget ultricies suscipit, nunc dui lacinia enim, vitae
tempus nunc libero vitae ligula. Nam et commodo ligula. Pellentesque
tincidunt lorem at elit aliquam at fringilla libero tempor. Donec molestie
consectetur nibh, ac varius ante dictum id. Suspendisse lectus nibh,
molestie vel dapibus eget, egestas ut eros. Mauris vel mauris turpis, vitae
bibendum nunc. Vestibulum nulla enim, vestibulum vitae tincidunt et,
gravida eu metus. Nulla sagittis, odio a placerat laoreet, arcu lectus
vestibulum nunc, in hendrerit tortor quam sit amet turpis. In et purus vel
dui pellentesque tincidunt. Donec dictum nibh sed quam luctus sit amet
luctus justo dapibus. Integer nulla elit, lacinia aliquet euismod sed,
tempus vitae lectus. Fusce non sapien dolor. Suspendisse ut est ut dui
tempor ultricies id ut elit. Aenean adipiscing sollicitudin enim, nec
porttitor est porttitor eget. Proin lobortis ante ut diam sodales volutpat.
Donec urna diam, porttitor nec laoreet ut, rhoncus non diam.
Ut sed mi vitae turpis semper semper. Integer sit amet lorem sapien.
Aliquam risus diam, vulputate id sagittis et, molestie ut lectus. Aliquam
erat volutpat. Morbi aliquet venenatis metus in posuere. Cras vitae purus
nunc, ut vestibulum ipsum. Nullam vehicula dui in urna iaculis lobortis. Ut
a est non est tincidunt iaculis. Vivamus rutrum velit non nunc malesuada
sed bibendum mi iaculis. Sed id lacus in sem tempor vestibulum. Cras
bibendum accumsan suscipit. Phasellus congue nisl consectetur turpis
rhoncus aliquet posuere libero fringilla. Sed eros tellus, hendrerit nec
imperdiet vitae, blandit ac dolor. Nulla facilisi. Morbi ullamcorper libero
odio, at cursus tortor. Cras ultricies tellus eget justo cursus cursus.
Donec at mi massa, auctor suscipit sem.
Proin dolor purus, semper sed ultrices ut, iaculis at tortor. Donec risus
enim, interdum et convallis nec, aliquam eget velit. Curabitur eget lectus
dolor. Integer id turpis eu nulla euismod tincidunt. Fusce elit nibh,
dapibus sit amet tempus ac, convallis eu libero. Donec dui justo, molestie
sed euismod porta, ultricies id orci. Praesent a tellus et risus faucibus
porttitor pellentesque in purus. Fusce blandit risus ac tortor viverra
vitae molestie odio convallis. Donec rhoncus volutpat mauris, sit amet
mattis libero dapibus id. Ut rhoncus venenatis nisi ac dictum. In non nulla
eget massa convallis facilisis. Praesent nec odio id odio semper lobortis
non eu erat. Proin quis gravida magna. Sed rhoncus lectus auctor arcu
posuere a auctor dui pellentesque.
Sed enim nulla, luctus quis sagittis sed, vestibulum eget metus. Mauris
ornare pretium fringilla. Proin ligula eros, fermentum in placerat sit
amet, placerat vel mauris. Nulla magna enim, luctus eget euismod ac,
lacinia vel lorem. Duis mi leo, porttitor vitae dictum ac, ultrices iaculis
metus. Quisque libero mi, aliquet quis vestibulum eget, porttitor non
justo. Praesent ac metus felis. Pellentesque habitant morbi tristique
senectus et netus et malesuada fames ac turpis egestas. Donec vel enim sit
amet ante imperdiet commodo sed vel nisi. Praesent semper viverra nulla
vehicula sollicitudin. Fusce lacinia aliquet ullamcorper. Donec vitae diam
est. Integer volutpat hendrerit turpis ut bibendum. Integer et dui augue.
Nunc ut nisl in felis feugiat semper nec sit amet purus. Proin convallis
ultrices nisl ut vehicula. Pellentesque neque mi, elementum vel placerat
nec, laoreet ac nulla. Pellentesque aliquam dui a metus iaculis posuere.
Curabitur dapibus faucibus metus. Donec quis diam dui. Proin at mi nec
augue cursus pulvinar eu vel metus. Curabitur eget turpis ac risus
dignissim luctus sed id ligula. Etiam lectus neque, varius ut euismod nec,
euismod quis nulla. Ut feugiat, quam id tempor luctus, metus eros lacinia
diam, nec dapibus tellus dui quis diam. Nam interdum, orci id fringilla
mattis, ipsum eros pellentesque turpis, hendrerit dignissim justo dui
interdum ante. Curabitur aliquam nisi ut dui lacinia tempor. Nulla lobortis
tellus non sapien dignissim ut dapibus dui aliquet. Nam scelerisque, urna a
aliquam malesuada, mi tortor scelerisque libero, quis pellentesque erat
eros ut justo.
Phasellus nulla purus, suscipit vel gravida euismod, malesuada et odio.
Vestibulum non libero eget lacus venenatis auctor quis a est. Nunc id leo
est. Curabitur pulvinar viverra sapien at viverra. Cras pretium justo et
lorem lobortis id tempor nisi accumsan. Cras egestas tortor in risus
hendrerit eu varius purus suscipit. Nullam mauris eros, mattis at tempor
vitae, mollis vitae velit. Etiam at adipiscing lectus. Quisque molestie,
metus id posuere pharetra, lorem enim vehicula mauris, ut ultricies purus
justo a lacus. Vivamus blandit euismod adipiscing. Nam eu ligula at elit
ultricies tempus. Nunc ac sodales neque. Ut dui diam, porttitor a pulvinar
vel, sodales sit amet turpis. Donec vitae eros at neque luctus scelerisque.
In consequat elementum iaculis. Donec ullamcorper dolor eu quam volutpat
rhoncus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras
laoreet ante eget dolor sagittis imperdiet. Proin magna urna, porta id
blandit nec, commodo eget lorem.
Etiam imperdiet, orci sit amet rutrum consectetur, orci augue tempus lacus,
id venenatis sapien nisl a est. Sed accumsan massa sed libero consectetur
scelerisque. Class aptent taciti sociosqu ad litora torquent per conubia
nostra, per inceptos himenaeos. Sed nunc risus, lobortis id egestas nec,
suscipit id magna. Morbi at iaculis mauris. Proin felis sem, tempus non
pellentesque congue, vehicula sit amet eros. Maecenas porttitor erat ac
dolor pharetra iaculis. Cras tincidunt, nulla eget malesuada egestas, sem
diam consequat quam, sed feugiat nulla orci at mauris. Quisque non arcu
diam, ac lacinia felis. Nunc iaculis mollis egestas. Etiam imperdiet dolor
consectetur eros feugiat fringilla sed in lacus. Nunc nec tincidunt dolor.
Etiam sagittis tortor condimentum nunc fermentum vestibulum. Vivamus
lobortis, magna sit amet scelerisque lobortis, sem eros molestie leo, eget
aliquet ligula est in lectus. Duis placerat porta pulvinar. Sed sed
adipiscing ante. Vestibulum ante ipsum primis in faucibus orci luctus et
ultrices posuere cubilia Curae; Nam accumsan iaculis augue, sed varius dui
sagittis id. Etiam sit amet eleifend augue.
Ut sit amet nibh sit amet justo tempor condimentum. Ut faucibus sagittis
volutpat. Duis vestibulum feugiat sollicitudin. Aenean cursus luctus urna
at consectetur. Nullam tincidunt, eros a iaculis sodales, tellus est
imperdiet arcu, sit amet tincidunt orci felis et tortor. Mauris rutrum
venenatis nunc ut rutrum. Phasellus nec erat magna, in tincidunt orci. Sed
sit amet suscipit tellus. Mauris ut nisi turpis. Suspendisse augue turpis,
condimentum ac bibendum in, vestibulum nec eros. Curabitur dapibus pulvinar
vehicula. Fusce consequat, erat in malesuada hendrerit, tellus urna
pharetra lacus, sed euismod nisi urna sed nisi. Etiam fermentum accumsan
nunc, sed bibendum dui iaculis id. Etiam blandit fermentum ligula nec
viverra. Vivamus venenatis arcu in nulla euismod euismod. Donec sit amet
augue nec metus varius fringilla. Vivamus pulvinar elit ac mi rhoncus in
luctus diam egestas. Curabitur a felis eget arcu pretium tempus eu sed
mauris. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices
posuere cubilia Curae;
Mauris malesuada, nibh ac venenatis hendrerit, ligula dui condimentum
tellus, sit amet pretium diam tortor vel risus. Suspendisse suscipit
consequat eros id dignissim. Cras interdum lorem ac massa euismod non porta
enim pretium. Aliquam ultrices nibh vitae ligula consectetur vel
sollicitudin lacus volutpat. Phasellus vulputate iaculis sem nec laoreet.
Nam leo sem, tempor eu condimentum id, imperdiet sed dolor. Donec pharetra
velit non libero euismod tempor. Vestibulum ante ipsum primis in faucibus
orci luctus et ultrices posuere cubilia Curae; Sed fermentum, libero a
posuere posuere, enim elit imperdiet enim, a sollicitudin est felis non
libero. Sed vel dolor ut arcu dapibus iaculis nec a mauris. Morbi
ullamcorper ultrices venenatis. Fusce luctus ante sit amet lacus venenatis
ut rutrum elit lobortis. Nulla fermentum tortor ac sapien fringilla quis
iaculis quam egestas.
Aliquam et tortor est, at elementum mauris. Morbi posuere erat nec leo
vulputate in pellentesque tortor condimentum. Vestibulum at orci augue.
Aenean pellentesque sapien id felis consequat varius. Suspendisse bibendum
enim sit amet mi imperdiet vel suscipit nisi tristique. Curabitur velit
massa, consectetur ac mattis vel, accumsan at nunc. Donec porta, nibh nec
consequat convallis, urna neque auctor erat, eu convallis lorem leo
convallis turpis. Morbi non mauris non metus ornare vulputate. Sed aliquet,
dolor ut egestas fermentum, metus purus mollis elit, nec commodo odio quam
quis nisl. Aliquam erat volutpat. Suspendisse sed faucibus urna. Integer
suscipit rutrum condimentum. Praesent dignissim libero eget metus luctus
consectetur.
Vestibulum ac erat felis, vitae iaculis erat. Duis interdum lacinia arcu,
non lacinia urna luctus in. Curabitur feugiat sapien sapien, in vestibulum
diam. Phasellus lobortis massa ut metus pretium dignissim. Fusce quis sem
odio. Integer pellentesque sodales augue id tincidunt. Pellentesque
habitant morbi tristique senectus et netus et malesuada fames ac turpis
egestas. Vestibulum lorem odio, semper vel scelerisque sit amet, sagittis
ac libero. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices
posuere cubilia Curae; Nam egestas ultricies dui at gravida. Duis
tristique, eros id consectetur pellentesque, nulla arcu ultricies tortor,
ut pulvinar sapien lacus in elit. Vivamus dolor massa, pulvinar at mollis
vitae, euismod ut dolor. Vivamus a magna ante. Vestibulum vitae fringilla
leo. Ut gravida magna in quam fringilla ultricies. Mauris rhoncus enim id
sem interdum blandit. Pellentesque luctus leo sit amet felis viverra ac
accumsan purus mollis. Aenean pretium fringilla quam nec laoreet.
Nulla id mauris mauris. Nam varius bibendum tristique. Integer ante felis,
volutpat sed dignissim vel, interdum molestie nisi. Etiam mollis accumsan
elit, ut gravida eros molestie nec. Nullam quis velit ac purus imperdiet
sodales. Donec semper placerat venenatis. Cras dolor risus, sodales sed
scelerisque nec, sollicitudin pretium felis. Quisque pretium felis id
turpis bibendum pulvinar ornare id nibh. Morbi lobortis leo non mi
porttitor vulputate. Vestibulum nec odio tellus, ut blandit ligula. In
pellentesque neque sit amet dui pulvinar sed laoreet dui vehicula. In hac
habitasse platea dictumst. Etiam feugiat dictum blandit. Praesent lacinia
tincidunt elit, quis consectetur tortor molestie commodo.
Ut sit amet accumsan lorem. Cras quam nunc, malesuada tempor volutpat
vitae, aliquam eu diam. Sed sem nibh, bibendum nec sollicitudin at,
interdum et magna. Cum sociis natoque penatibus et magnis dis parturient
montes, nascetur ridiculus mus. Aliquam vitae sem non elit pharetra
vestibulum et condimentum libero. Nam egestas ultricies hendrerit. Nunc nec
fringilla nulla. Aliquam risus tellus, hendrerit non dapibus a, tincidunt
vel ante. Vivamus mollis, magna et lacinia tincidunt, dui massa porta odio,
ac ornare felis massa nec lorem. Mauris sagittis lacus sed metus mollis ac
egestas lectus porttitor. Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient
montes, nascetur ridiculus mus. Integer vitae lacinia libero. Phasellus at
neque enim, sit amet dictum mi.
Ut risus nisi, vestibulum vel congue eget, egestas in ipsum. Duis faucibus
tempus sodales. Duis convallis pellentesque arcu rhoncus congue. Nunc ac
mauris eu purus vestibulum congue. Praesent convallis semper augue vel
volutpat. Integer dictum varius placerat. Vestibulum convallis tortor non
mi lacinia ac aliquet dui ultricies. Donec ultrices purus eros. Maecenas
venenatis posuere massa, nec consectetur lacus cursus eget. Donec quam
lacus, tempus id placerat et, posuere sed libero. Proin auctor diam ut arcu
viverra ut imperdiet tellus dapibus.
Morbi ac mauris quis tellus porttitor eleifend. Sed et ante magna, ut
sodales sapien. Vestibulum ante ipsum primis in faucibus orci luctus et
ultrices posuere cubilia Curae; Integer mattis venenatis mi non
ullamcorper. Vestibulum magna enim, aliquam non interdum ut, dignissim
vitae ante. Praesent dignissim, est at pretium posuere, nisl ante varius
felis, vitae posuere enim nulla et nunc. Morbi sagittis suscipit leo, eu
accumsan ligula volutpat non. Donec ut tincidunt magna. Integer ac libero
mi. Sed non eros dolor, in tincidunt enim. Curabitur iaculis erat quis
felis iaculis ut volutpat augue malesuada. Pellentesque eget arcu ligula,
ut volutpat purus. Suspendisse dictum lorem quis sapien lacinia pretium.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Proin sagittis egestas massa et tempor. Mauris et eros ante, id porta sem.
Duis ac eros vitae ipsum ultrices malesuada eget a risus. Morbi imperdiet,
est a hendrerit tristique, mi erat molestie lacus, ac tempor risus nulla id
erat. Pellentesque habitant morbi tristique senectus et netus et malesuada
fames ac turpis egestas. Etiam congue, lacus quis ultricies consequat, diam
metus convallis enim, ut volutpat enim urna vitae erat. In quam risus,
molestie et dapibus id, elementum sit amet ligula. Nam faucibus lacus id
dolor facilisis viverra. Nullam vehicula massa ac arcu consectetur
vulputate. Praesent nec augue ac justo dapibus vehicula. Aliquam
consectetur hendrerit dolor, et mollis nisl auctor ut.
Ut sagittis risus at felis fringilla ultricies. Vestibulum non urna nibh,
nec pretium dolor. Nulla imperdiet lobortis eros at pharetra. Vivamus
cursus pellentesque ornare. Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Fusce arcu quam, pulvinar at rutrum vitae, ornare vitae
leo. Maecenas vehicula magna sit amet nulla bibendum condimentum. Curabitur
ultrices tempor fringilla. Vivamus pretium suscipit molestie. Donec arcu
diam, ultricies ac pellentesque eu, venenatis et sapien.
Nam dictum orci augue, vel eleifend leo. Nam at lacus sapien, nec pretium
eros. In egestas, enim sed sagittis feugiat, purus odio tristique lectus,
vel condimentum leo turpis ac odio. Nam iaculis mi quis odio posuere et
venenatis velit ultricies. Nulla facilisi. Proin nec dolor ac quam euismod
gravida quis et eros. Nam interdum condimentum mattis. Cum sociis natoque
penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent
a nisi eu massa mollis posuere sed a nunc. Aenean tempus enim a justo
rhoncus quis ultrices nisl commodo.
Aenean imperdiet mauris a ipsum venenatis vel scelerisque lorem rutrum.
Donec ut nunc eros, eget accumsan felis. Nullam ullamcorper porta dictum.
Donec accumsan cursus vestibulum. Aenean in sapien velit. Vivamus nec massa
mi. Fusce felis tortor, bibendum non volutpat a, fringilla quis nisi. Duis
varius bibendum erat, quis fermentum sem accumsan eget. Maecenas massa
felis, porta sed laoreet eu, luctus eu lectus. Cras id nibh vitae erat
fringilla rutrum. Maecenas eget consequat est. Vivamus viverra, felis vel
faucibus rhoncus, quam ipsum elementum libero, quis convallis urna purus ut
mauris. Nam quis urna vitae enim consequat placerat. Vivamus congue augue
sit amet lectus luctus tempor. Cras ut justo convallis est egestas
pellentesque ac nec orci.
Vivamus rutrum bibendum ante, at cursus erat pulvinar ornare. Proin
imperdiet scelerisque ante eu vestibulum. Nullam ullamcorper metus nec
purus auctor lobortis. Proin sed lacus et ipsum tempor tempus. Vivamus odio
dolor, vulputate vitae semper sit amet, aliquet egestas orci. Nullam non
quam eu quam sagittis porta. Nunc in velit id erat commodo viverra.
Praesent nec est augue, nec sagittis erat. Cras sed turpis quis enim tempor
sagittis. Donec in justo ac nisl porta condimentum id vestibulum nulla. Nam
elementum ultricies nunc a bibendum.
Aenean tincidunt nisl non augue pellentesque sit amet convallis neque
semper. Cras placerat suscipit massa sed volutpat. Integer vulputate
imperdiet enim, vitae vulputate sapien mattis feugiat. Vivamus pharetra
facilisis mauris a gravida. Nulla non venenatis est. Duis lobortis
consectetur sem ac aliquam. In eget sapien odio. Vivamus pulvinar ultricies
magna, quis laoreet dui porta et. Integer tempus malesuada velit, et
consequat odio ultrices sed. Aliquam malesuada commodo diam vel posuere.
Morbi porttitor, elit vitae auctor gravida, lorem massa bibendum arcu, vel
placerat nulla justo at augue.
Aliquam libero quam, mattis blandit congue sit amet, fermentum ac augue.
Aliquam malesuada molestie vulputate. Duis id porta augue. Vestibulum diam
dolor, ultrices sit amet porttitor id, convallis id lectus. Etiam ac augue
tincidunt nisi tempor molestie euismod id nisl. Nam et tortor ac arcu
viverra pulvinar. Fusce pulvinar rhoncus leo, a faucibus enim interdum non.
Aliquam vulputate mattis consectetur. Pellentesque sit amet quam sem. Cras
eget arcu eu elit volutpat volutpat. Integer sed varius enim. Integer sit
amet felis orci, id dignissim sapien. Sed vitae lorem sed libero facilisis
fringilla. Pellentesque congue tristique purus, eleifend semper risus
suscipit quis. Phasellus rutrum quam vitae arcu vulputate porta. Sed
tristique arcu nec mi porttitor lacinia.
Donec congue feugiat diam quis pretium. Vivamus at luctus nunc. Integer
vulputate laoreet mauris quis auctor. Nunc at ultrices libero. Maecenas
porta faucibus purus non vehicula. Sed sit amet metus vitae mi ultrices
scelerisque nec quis risus. Phasellus pellentesque tincidunt massa id
ultricies. Aliquam dictum arcu ac dolor interdum rutrum. Nulla facilisi.
Duis nisi est, tincidunt a sagittis id, sollicitudin at odio. Curabitur sed
est eu sapien faucibus dignissim in quis tortor.
Nunc ac elit tortor, non lobortis massa. Proin posuere ante ut metus
vehicula suscipit. Proin mattis mauris ac lectus consequat rutrum. Nam arcu
lectus, commodo non pretium a, pharetra semper dolor. Fusce eleifend
hendrerit adipiscing. Nunc et eleifend erat. Suspendisse tempus nisl ut
arcu blandit ut adipiscing nisi tristique. Suspendisse molestie facilisis
risus sed fermentum. Praesent tempor convallis ultricies. Integer et elit
velit, at consectetur risus.
Vestibulum mollis adipiscing sodales. Vestibulum ante ipsum primis in
faucibus orci luctus et ultrices posuere cubilia Curae; Mauris dictum
molestie porta. Nam convallis nisl quis lacus vulputate in convallis risus
sagittis. Vivamus accumsan faucibus cursus. Ut ultricies imperdiet ligula
scelerisque blandit. In ornare egestas purus, at convallis velit egestas
laoreet. Class aptent taciti sociosqu ad litora torquent per conubia
nostra, per inceptos himenaeos. Nulla quis imperdiet est. Nunc tempus magna
quis lacus feugiat et posuere lacus vehicula. Cras lacinia aliquam est at
vehicula. Aenean congue elit in ante dignissim vitae fermentum lectus
aliquam. Mauris at odio magna, at interdum dui. Cras fringilla mi velit,
nec varius neque.
Fusce et volutpat lacus. Suspendisse id turpis et urna varius convallis in
eu purus. Nulla facilisi. Etiam mauris nisl, ultrices ac porttitor sit
amet, facilisis ut neque. Nullam ut velit quis velit tincidunt rhoncus.
Praesent tristique porttitor euismod. Nulla non felis ante, feugiat commodo
turpis. In nec venenatis mi. Duis tempus tempor purus, vitae consectetur mi
ornare eu. Proin sed consequat erat. Quisque nec sem dui. Nam semper,
ligula facilisis pretium interdum, diam lectus sollicitudin lorem, in
elementum nisi lorem scelerisque justo. Nullam ac fringilla nunc. Maecenas
malesuada ligula in massa sollicitudin sit amet auctor ipsum malesuada.
Vestibulum ut augue in magna lobortis varius eget in ipsum. In hac
habitasse platea dictumst.
Cras vel sagittis mi. Aenean urna sapien, ultrices et tristique et, aliquam
vel libero. Nullam in consequat ante. Suspendisse libero augue, pulvinar a
dignissim vitae, fringilla malesuada dui. Phasellus augue ante, pulvinar
eget tincidunt vel, venenatis sed arcu. Pellentesque ac purus orci, vel
molestie turpis. Nulla consectetur sollicitudin dolor, sed ornare arcu
accumsan fermentum. Fusce vestibulum nisi at leo interdum eu sollicitudin
lacus dictum. Fusce malesuada consequat ipsum ut convallis. Maecenas in
eros sit amet elit consectetur fringilla nec a nibh. Ut et velit vel ligula
pharetra elementum. Nullam aliquam, tellus vel cursus lacinia, dui libero
dictum turpis, nec lacinia dolor nunc vel diam. Pellentesque convallis dui
quis lacus ornare at rutrum lorem pellentesque. Suspendisse potenti. Cum
sociis natoque penatibus et magnis dis parturient montes, nascetur
ridiculus mus.
Nunc ac nibh sed mauris ornare cursus. Praesent enim mauris, tincidunt
vitae convallis ac, ultricies imperdiet sapien. Duis sodales ligula eget
lorem suscipit sed consectetur metus pretium. Nam in magna augue, quis
volutpat mauris. Quisque pretium lobortis orci quis laoreet. Nam ut nisi
diam. Sed ultrices ultrices dapibus. Integer feugiat mauris id orci
pulvinar eu tempus nibh viverra. Etiam venenatis bibendum massa a
consequat. Fusce interdum velit ac mauris rhoncus non cursus neque
consectetur. Vestibulum dictum eros ac metus fringilla venenatis. Phasellus
auctor dui non nulla molestie id malesuada mauris euismod. Aenean id tortor
ac justo eleifend mollis non vel arcu. Duis ac lorem tortor. Donec volutpat
purus sed nunc luctus interdum hendrerit nulla ullamcorper. Sed consectetur
interdum aliquet. Proin ullamcorper risus ut ante lacinia sagittis. Nunc
varius eleifend purus, ac pellentesque urna viverra id. Praesent euismod,
sapien accumsan gravida dictum, massa massa euismod sapien, ut auctor
tellus arcu sed diam.
Vivamus tincidunt dolor non lorem pellentesque at tempus elit adipiscing.
Vestibulum tempor aliquam consectetur. Mauris nec dictum nisl. Donec
scelerisque ornare condimentum. Phasellus laoreet justo nec nibh convallis
convallis. Duis id orci sapien, eget pulvinar justo. Aenean id arcu felis,
eu iaculis nibh. Aenean eleifend pretium rutrum. Aliquam molestie sem quis
tellus aliquam eleifend. Mauris et purus orci. Nunc et accumsan tortor.
Phasellus semper eleifend nisi, a faucibus risus vehicula id. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Maecenas in felis et est
lacinia eleifend vel sed ipsum. Aliquam commodo molestie lorem id
hendrerit. Nam sed tellus urna, sed dignissim eros.
"""
return A_LONG_STRING
#ifndef _OPERATORS_H_
#define _OPERATORS_H_
class Operators
{
public:
int value;
Operators() { }
Operators(int value) { this->value = value; }
virtual ~Operators() { }
Operators operator+(Operators f) { return Operators(this->value + f.value); }
Operators operator-(Operators f) { return Operators(this->value - f.value); }
Operators operator*(Operators f) { return Operators(this->value * f.value); }
Operators operator/(Operators f) { return Operators(this->value / f.value); }
bool operator<(Operators f) { return this->value < f.value; }
bool operator<=(Operators f) { return this->value <= f.value; }
bool operator==(Operators f) { return this->value == f.value; }
bool operator!=(Operators f) { return this->value != f.value; }
bool operator>(Operators f) { return this->value > f.value; }
bool operator>=(Operators f) { return this->value >= f.value; }
Operators operator>>(int v) { return Operators(this->value >> v); }
Operators operator<<(int v) { return Operators(this->value << v); }
Operators operator%(int v) { return Operators(this->value % v); }
};
#endif
#ifndef _TEMPLATES_H_
#define _TEMPLATES_H_
template<class T>
class TemplateTest1
{
public:
T value;
int t;
TemplateTest1() { }
T getValue() { return value; }
};
template<class T, class U>
class TemplateTest2
{
public:
T value1;
U value2;
TemplateTest2() { }
T getValue1() { return value1; }
U getValue2() { return value2; }
};
#endif
...@@ -12,9 +12,9 @@ def f(): ...@@ -12,9 +12,9 @@ def f():
cdef object[int, 2, well] buf6 cdef object[int, 2, well] buf6
_ERRORS = u""" _ERRORS = u"""
1:11: Buffer types only allowed as function local variables 1:17: Buffer types only allowed as function local variables
3:15: Buffer types only allowed as function local variables 3:21: Buffer types only allowed as function local variables
6:27: "fakeoption" is not a buffer option 6:31: "fakeoption" is not a buffer option
""" """
#TODO: #TODO:
#7:22: "ndim" must be non-negative #7:22: "ndim" must be non-negative
......
...@@ -12,7 +12,7 @@ def f(a): ...@@ -12,7 +12,7 @@ def f(a):
del s.m # error: deletion of non-Python object del s.m # error: deletion of non-Python object
_ERRORS = u""" _ERRORS = u"""
8:6: Cannot assign to or delete this 8:6: Cannot assign to or delete this
9:45: Deletion of non-Python object 9:45: Deletion of non-Python, non-C++ object
11:6: Deletion of non-Python object 11:6: Deletion of non-Python, non-C++ object
12:6: Deletion of non-Python object 12:6: Deletion of non-Python, non-C++ object
""" """
...@@ -111,21 +111,84 @@ def slice_charptr_for_loop_c_enumerate(): ...@@ -111,21 +111,84 @@ def slice_charptr_for_loop_c_enumerate():
############################################################ ############################################################
# tests for int* slicing # tests for int* slicing
## cdef int cints[6] cdef int cints[6]
## for i in range(6): for i in range(6):
## cints[i] = i cints[i] = i
## @cython.test_assert_path_exists("//ForFromStatNode", @cython.test_assert_path_exists("//ForFromStatNode",
## "//ForFromStatNode//IndexNode") "//ForFromStatNode//IndexNode")
## @cython.test_fail_if_path_exists("//ForInStatNode") @cython.test_fail_if_path_exists("//ForInStatNode")
## def slice_intptr_for_loop_c(): def slice_intarray_for_loop_c():
## """ """
## >>> slice_intptr_for_loop_c() >>> slice_intarray_for_loop_c()
## [0, 1, 2] [0, 1, 2]
## [1, 2, 3, 4] [1, 2, 3, 4]
## [4, 5] [4, 5]
## """ """
## cdef int i cdef int i
## print [ i for i in cints[:3] ] print [ i for i in cints[:3] ]
## print [ i for i in cints[1:5] ] print [ i for i in cints[1:5] ]
## print [ i for i in cints[4:6] ] print [ i for i in cints[4:6] ]
@cython.test_assert_path_exists("//ForFromStatNode",
"//ForFromStatNode//IndexNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def iter_intarray_for_loop_c():
"""
>>> iter_intarray_for_loop_c()
[0, 1, 2, 3, 4, 5]
"""
cdef int i
print [ i for i in cints ]
@cython.test_assert_path_exists("//ForFromStatNode",
"//ForFromStatNode//IndexNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def slice_intptr_for_loop_c():
"""
>>> slice_intptr_for_loop_c()
[0, 1, 2]
[1, 2, 3, 4]
[4, 5]
"""
cdef int* nums = cints
cdef int i
print [ i for i in nums[:3] ]
print [ i for i in nums[1:5] ]
print [ i for i in nums[4:6] ]
############################################################
# tests for slicing other arrays
cdef double cdoubles[6]
for i in range(6):
cdoubles[i] = i + 0.5
cdef double* cdoubles_ptr = cdoubles
@cython.test_assert_path_exists("//ForFromStatNode",
"//ForFromStatNode//IndexNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def slice_doublptr_for_loop_c():
"""
>>> slice_doublptr_for_loop_c()
[0.5, 1.5, 2.5]
[1.5, 2.5, 3.5, 4.5]
[4.5, 5.5]
"""
cdef double d
print [ d for d in cdoubles_ptr[:3] ]
print [ d for d in cdoubles_ptr[1:5] ]
print [ d for d in cdoubles_ptr[4:6] ]
@cython.test_assert_path_exists("//ForFromStatNode",
"//ForFromStatNode//IndexNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def iter_doublearray_for_loop_c():
"""
>>> iter_doublearray_for_loop_c()
[0.5, 1.5, 2.5, 3.5, 4.5, 5.5]
"""
cdef double d
print [ d for d in cdoubles ]
cimport cython
cdef extern from "Python.h":
cdef cython.unicode PyUnicode_DecodeUTF8(char* s, Py_ssize_t size, char* errors)
def test_capi():
"""
>>> print(test_capi())
abc
"""
return PyUnicode_DecodeUTF8("abc", 3, NULL)
...@@ -21,7 +21,7 @@ def test_arithmetic(double complex z, double complex w): ...@@ -21,7 +21,7 @@ def test_arithmetic(double complex z, double complex w):
>>> test_arithmetic(5-10j, 3+4j) >>> test_arithmetic(5-10j, 3+4j)
((5-10j), (-5+10j), (8-6j), (2-14j), (55-10j), (-1-2j)) ((5-10j), (-5+10j), (8-6j), (2-14j), (55-10j), (-1-2j))
""" """
return +z, -z, z+w, z-w, z*w, z/w return +z, -z+0, z+w, z-w, z*w, z/w
@cython.cdivision(False) @cython.cdivision(False)
def test_div_by_zero(double complex z): def test_div_by_zero(double complex z):
......
__doc__ = u"""
>>> test_new_del()
(2, 2)
>>> test_rect_area(3, 4)
12.0
>>> test_square_area(15)
(225.0, 225.0)
"""
cdef extern from "shapes.h" namespace shapes:
cdef cppclass Shape:
float area()
cdef cppclass Circle(Shape):
int radius
Circle(int)
cdef cppclass Rectangle(Shape):
int width
int height
Rectangle(int, int)
cdef cppclass Square(Rectangle):
int side
Square(int)
int constructor_count, destructor_count
def test_new_del():
cdef Rectangle *rect = new Rectangle(10, 20)
cdef Circle *circ = new Circle(15)
del rect, circ
return constructor_count, destructor_count
def test_rect_area(w, h):
cdef Rectangle *rect = new Rectangle(w, h)
try:
return rect.area()
finally:
del rect
def test_square_area(w):
cdef Square *sqr = new Square(w)
cdef Rectangle *rect = sqr
try:
return rect.area(), sqr.area()
finally:
del sqr
cdef double get_area(Rectangle s):
return s.area()
def test_value_call(int w):
"""
>>> test_value_call(5)
(25.0, 25.0)
"""
cdef Square *sqr = new Square(w)
cdef Rectangle *rect = sqr
try:
return get_area(sqr[0]), get_area(rect[0])
finally:
del sqr
from cython.operator cimport dereference as deref
cdef extern from "cpp_templates_helper.h":
cdef cppclass Wrap[T]:
Wrap(T)
void set(T)
T get()
bint operator==(Wrap[T])
cdef cppclass Pair[T1,T2]:
Pair(T1,T2)
T1 first()
T2 second()
bint operator==(Pair[T1,T2])
bint operator!=(Pair[T1,T2])
def test_wrap_pair(int i, double x):
"""
>>> test_wrap_pair(1, 1.5)
(1, 1.5, True)
>>> test_wrap_pair(2, 2.25)
(2, 2.25, True)
"""
try:
wrap = new Wrap[Pair[int, double]](Pair[int, double](i, x))
return wrap.get().first(), wrap.get().second(), deref(wrap) == deref(wrap)
finally:
del wrap
cimport cython.operator
from cython.operator cimport dereference as deref
cdef extern from "cpp_operators_helper.h":
cdef cppclass TestOps:
char* operator+()
char* operator-()
char* operator*()
char* operator~()
char* operator++()
char* operator--()
char* operator++(int)
char* operator--(int)
char* operator+(int)
char* operator-(int)
char* operator*(int)
char* operator/(int)
char* operator%(int)
char* operator|(int)
char* operator&(int)
char* operator^(int)
char* operator<<(int)
char* operator>>(int)
char* operator==(int)
char* operator!=(int)
char* operator>=(int)
char* operator<=(int)
char* operator>(int)
char* operator<(int)
char* operator[](int)
char* operator()(int)
def test_unops():
"""
>>> test_unops()
unary +
unary -
unary ~
unary *
"""
cdef TestOps* t = new TestOps()
print +t[0]
print -t[0]
print ~t[0]
print deref(t[0])
del t
def test_incdec():
"""
>>> test_incdec()
unary ++
unary --
post ++
post --
"""
cdef TestOps* t = new TestOps()
print cython.operator.preincrement(t[0])
print cython.operator.predecrement(t[0])
print cython.operator.postincrement(t[0])
print cython.operator.postdecrement(t[0])
del t
def test_binop():
"""
>>> test_binop()
binary +
binary -
binary *
binary /
binary %
binary &
binary |
binary ^
binary <<
binary >>
"""
cdef TestOps* t = new TestOps()
print t[0] + 1
print t[0] - 1
print t[0] * 1
print t[0] / 1
print t[0] % 1
print t[0] & 1
print t[0] | 1
print t[0] ^ 1
print t[0] << 1
print t[0] >> 1
del t
def test_cmp():
"""
>>> test_cmp()
binary ==
binary !=
binary >=
binary >
binary <=
binary <
"""
cdef TestOps* t = new TestOps()
print t[0] == 1
print t[0] != 1
print t[0] >= 1
print t[0] > 1
print t[0] <= 1
print t[0] < 1
del t
def test_index_call():
"""
>>> test_index_call()
binary []
binary ()
"""
cdef TestOps* t = new TestOps()
print t[0][100]
print t[0](100)
del t
#define UN_OP(op) const char* operator op () { return "unary "#op; }
#define POST_UN_OP(op) const char* operator op (int x) { return "post "#op; }
#define BIN_OP(op) const char* operator op (int x) { return "binary "#op; }
class TestOps {
public:
UN_OP(-);
UN_OP(+);
UN_OP(*);
UN_OP(~);
UN_OP(!);
UN_OP(&);
UN_OP(++);
UN_OP(--);
POST_UN_OP(++);
POST_UN_OP(--);
BIN_OP(+);
BIN_OP(-);
BIN_OP(*);
BIN_OP(/);
BIN_OP(%);
BIN_OP(<<);
BIN_OP(>>);
BIN_OP(|);
BIN_OP(&);
BIN_OP(^);
BIN_OP(==);
BIN_OP(!=);
BIN_OP(<=);
BIN_OP(<);
BIN_OP(>=);
BIN_OP(>);
BIN_OP([]);
BIN_OP(());
};
__doc__ = u"""
>>> test_vector([1,10,100])
1
10
100
"""
cdef extern from "vector" namespace std:
cdef cppclass iterator[T]:
pass
cdef cppclass vector[T]:
#constructors
__init__()
T at(int)
void push_back(T t)
void assign(int, T)
void clear()
iterator end()
iterator begin()
int size()
def test_vector(L):
cdef vector[int] *V = new vector[int]()
for a in L:
V.push_back(a)
cdef int i
for i in range(len(L)):
print V.at(i)
del V
cdef extern from "<vector>" namespace std:
cdef cppclass vector[T]:
void push_back(T)
size_t size()
T operator[](size_t)
def simple_test(double x):
"""
>>> simple_test(55)
3
"""
cdef vector[double] *v
try:
v = new vector[double]()
v.push_back(1.0)
v.push_back(x)
from math import pi
v.push_back(pi)
return v.size()
finally:
del v
def list_test(L):
"""
>>> list_test([1,2,4,8])
(4, 4)
>>> list_test([])
(0, 0)
>>> list_test([-1] * 1000)
(1000, 1000)
"""
cdef vector[int] *v
try:
v = new vector[int]()
for a in L:
v.push_back(a)
return len(L), v.size()
finally:
del v
def index_test(L):
"""
>>> index_test([1,2,4,8])
(1.0, 8.0)
>>> index_test([1.25])
(1.25, 1.25)
"""
cdef vector[double] *v
try:
v = new vector[double]()
for a in L:
v.push_back(a)
return v[0][0], v[0][len(L)-1]
finally:
del v
from cython.operator import dereference as deref
cdef extern from "cpp_templates_helper.h":
cdef cppclass Wrap[T]:
Wrap(T)
void set(T)
T get()
bint operator==(Wrap[T])
cdef cppclass Pair[T1,T2]:
Pair(T1,T2)
T1 first()
T2 second()
bint operator==(Pair[T1,T2])
bint operator!=(Pair[T1,T2])
def test_int(int x, int y):
"""
>>> test_int(3, 4)
(3, 4, False)
>>> test_int(100, 100)
(100, 100, True)
"""
try:
a = new Wrap[int](x)
b = new Wrap[int](0)
b.set(y)
return a.get(), b.get(), a[0] == b[0]
finally:
del a, b
def test_double(double x, double y):
"""
>>> test_double(3, 3.5)
(3.0, 3.5, False)
>>> test_double(100, 100)
(100.0, 100.0, True)
"""
try:
a = new Wrap[double](x)
b = new Wrap[double](-1)
b.set(y)
return a.get(), b.get(), deref(a) == deref(b)
finally:
del a, b
def test_pair(int i, double x):
"""
>>> test_pair(1, 1.5)
(1, 1.5, True, False)
>>> test_pair(2, 2.25)
(2, 2.25, True, False)
"""
try:
pair = new Pair[int, double](i, x)
return pair.first(), pair.second(), deref(pair) == deref(pair), deref(pair) != deref(pair)
finally:
del pair
template <class T>
class Wrap {
T value;
public:
Wrap(T v) : value(v) { }
void set(T v) { value = v; }
T get(void) { return value; }
bool operator==(Wrap<T> other) { return value == other.value; }
};
template <class T1, class T2>
class Pair {
T1 _first;
T2 _second;
public:
Pair(T1 u, T2 v) { _first = u; _second = v; }
T1 first(void) { return _first; }
T2 second(void) { return _second; }
bool operator==(Pair<T1,T2> other) { return _first == other._first && _second == other._second; }
bool operator!=(Pair<T1,T2> other) { return _first != other._first || _second != other._second; }
};
cdef extern from "Python.h": cdef extern from "Python.h":
ctypedef class __builtin__.str [object PyStringObject]:
cdef long ob_shash
ctypedef class __builtin__.list [object PyListObject]: ctypedef class __builtin__.list [object PyListObject]:
cdef Py_ssize_t ob_size
cdef Py_ssize_t allocated cdef Py_ssize_t allocated
ctypedef class __builtin__.dict [object PyDictObject]: ctypedef class __builtin__.dict [object PyDictObject]:
pass pass
cdef str s = "abc" cdef Py_ssize_t Py_SIZE(object o)
cdef list L = [1,2,4] cdef list L = [1,2,4]
cdef dict d = {'A': 'a'} cdef dict d = {'A': 'a'}
...@@ -23,18 +20,7 @@ def test_list(list L): ...@@ -23,18 +20,7 @@ def test_list(list L):
>>> test_list(list_subclass([1,2,3])) >>> test_list(list_subclass([1,2,3]))
True True
""" """
return L.ob_size <= L.allocated return Py_SIZE(L) <= L.allocated
def test_str(str s):
"""
>>> test_str("abc")
True
>>> class str_subclass(str): pass
>>> test_str(str_subclass("xyz"))
True
"""
cdef char* ss = s
return hash(s) == s.ob_shash
def test_tuple(tuple t): def test_tuple(tuple t):
""" """
......
cdef extern from *:
int new(int new)
def new(x):
"""
>>> new(3)
3
"""
cdef int new = x
return new
def x(new):
"""
>>> x(10)
110
>>> x(1)
1
"""
if new*new != new:
return new + new**2
return new
class A:
def new(self, n):
"""
>>> a = A()
>>> a.new(3)
6
>>> a.new(5)
120
"""
if n <= 1:
return 1
else:
return n * self.new(n-1)
#ifndef SHAPES_H
#define SHAPES_H
namespace shapes {
int constructor_count = 0;
int destructor_count = 0;
class Shape
{
public:
virtual float area() = 0;
Shape() { constructor_count++; }
virtual ~Shape() { destructor_count++; }
};
class Rectangle : public Shape
{
public:
Rectangle(int width, int height)
{
this->width = width;
this->height = height;
}
float area() { return width * height; }
int width;
int height;
};
class Square : public Rectangle
{
public:
Square(int side) : Rectangle(side, side) { this->side = side; }
int side;
};
class Circle : public Shape {
public:
Circle(int radius) { this->radius = radius; }
float area() { return 3.1415926535897931f * radius; }
int radius;
};
}
#endif
...@@ -93,13 +93,49 @@ def arithmetic(): ...@@ -93,13 +93,49 @@ def arithmetic():
>>> arithmetic() >>> arithmetic()
""" """
a = 1 + 2 a = 1 + 2
assert typeof(a) == "long" assert typeof(a) == "long", typeof(a)
b = 1 + 1.5 b = 1 + 1.5
assert typeof(b) == "double" assert typeof(b) == "double", typeof(b)
c = 1 + <object>2 c = 1 + <object>2
assert typeof(c) == "Python object" assert typeof(c) == "Python object", typeof(c)
d = "abc %s" % "x" d = 1 * 1.5 ** 2
assert typeof(d) == "Python object" assert typeof(d) == "double", typeof(d)
def builtin_type_operations():
"""
>>> builtin_type_operations()
"""
b1 = b'a' * 10
b1 = 10 * b'a'
b1 = 10 * b'a' * 10
assert typeof(b1) == "bytes object", typeof(b1)
b2 = b'a' + b'b'
assert typeof(b2) == "bytes object", typeof(b2)
u1 = u'a' * 10
u1 = 10 * u'a'
assert typeof(u1) == "unicode object", typeof(u1)
u2 = u'a' + u'b'
assert typeof(u2) == "unicode object", typeof(u2)
u3 = u'a%s' % u'b'
u3 = u'a%s' % 10
assert typeof(u3) == "unicode object", typeof(u3)
s1 = "abc %s" % "x"
s1 = "abc %s" % 10
assert typeof(s1) == "str object", typeof(s1)
s2 = "abc %s" + "x"
assert typeof(s2) == "str object", typeof(s2)
s3 = "abc %s" * 10
s3 = "abc %s" * 10 * 10
s3 = 10 * "abc %s" * 10
assert typeof(s3) == "str object", typeof(s3)
L1 = [] + []
assert typeof(L1) == "list object", typeof(L1)
L2 = [] * 2
assert typeof(L2) == "list object", typeof(L2)
T1 = () + ()
assert typeof(T1) == "tuple object", typeof(T1)
T2 = () * 2
assert typeof(T2) == "tuple object", typeof(T2)
def cascade(): def cascade():
""" """
...@@ -215,10 +251,29 @@ def safe_only(): ...@@ -215,10 +251,29 @@ def safe_only():
""" """
a = 1.0 a = 1.0
assert typeof(a) == "double", typeof(c) assert typeof(a) == "double", typeof(c)
b = 1 b = 1;
assert typeof(b) == "Python object", typeof(b) assert typeof(b) == "long", typeof(b)
c = MyType() c = MyType()
assert typeof(c) == "MyType", typeof(c) assert typeof(c) == "MyType", typeof(c)
for i in range(10): pass
assert typeof(i) == "long", typeof(i)
d = 1
res = ~d
assert typeof(d) == "long", typeof(d)
# potentially overflowing arithmatic
e = 1
e += 1
assert typeof(e) == "Python object", typeof(e)
f = 1
res = f * 10
assert typeof(f) == "Python object", typeof(f)
g = 1
res = 10*(~g)
assert typeof(g) == "Python object", typeof(g)
for j in range(10):
res = -j
assert typeof(j) == "Python object", typeof(j)
@infer_types(None) @infer_types(None)
def args_tuple_keywords(*args, **kwargs): def args_tuple_keywords(*args, **kwargs):
...@@ -249,3 +304,36 @@ def args_tuple_keywords_reassign_pyobjects(*args, **kwargs): ...@@ -249,3 +304,36 @@ def args_tuple_keywords_reassign_pyobjects(*args, **kwargs):
args = [] args = []
kwargs = "test" kwargs = "test"
# / A -> AA -> AAA
# Base0 -> Base -
# \ B -> BB
# C -> CC
cdef class Base0: pass
cdef class Base(Base0): pass
cdef class A(Base): pass
cdef class AA(A): pass
cdef class AAA(AA): pass
cdef class B(Base): pass
cdef class BB(B): pass
cdef class C: pass
cdef class CC(C): pass
@infer_types(None)
def common_extension_type_base():
"""
>>> common_extension_type_base()
"""
x = A()
x = AA()
assert typeof(x) == "A", typeof(x)
y = A()
y = B()
assert typeof(y) == "Base", typeof(y)
z = AAA()
z = BB()
assert typeof(z) == "Base", typeof(z)
w = A()
w = CC()
assert typeof(w) == "Python object", typeof(w)
cimport cython.operator
def test_deref(int x):
"""
>>> test_deref(3)
3
>>> test_deref(5)
5
"""
cdef int* x_ptr = &x
return cython.operator.dereference(x_ptr)
def increment_decrement(int x):
"""
>>> increment_decrement(10)
11 11 12
11 11 10
10
"""
print cython.operator.preincrement(x), cython.operator.postincrement(x), x
print cython.operator.predecrement(x), cython.operator.postdecrement(x), x
return x
cimport cppwrap_lib
cdef class DoubleKeeper:
cdef cppwrap_lib.DoubleKeeper* keeper
def __cinit__(self, number=None):
if number is None:
self.keeper = new cppwrap_lib.DoubleKeeper()
else:
self.keeper = new cppwrap_lib.DoubleKeeper(number)
def __dealloc__(self):
del self.keeper
def set_number(self, number=None):
if number is None:
self.keeper.set_number()
else:
self.keeper.set_number(number)
def get_number(self):
return self.keeper.get_number()
def transmogrify(self, double value):
return self.keeper.transmogrify(value)
def voidfunc():
cppwrap_lib.voidfunc()
def doublefunc(double x, double y, double z):
return cppwrap_lib.doublefunc(x, y, z)
def transmogrify_from_cpp(DoubleKeeper obj not None, double value):
return cppwrap_lib.transmogrify_from_cpp(obj.keeper, value)
#include "cppwrap_lib.h"
void voidfunc (void)
{
}
double doublefunc (double a, double b, double c)
{
return a + b + c;
}
DoubleKeeper::DoubleKeeper ()
: number (1.0)
{
}
DoubleKeeper::DoubleKeeper (double factor)
: number (factor)
{
}
DoubleKeeper::~DoubleKeeper ()
{
}
double DoubleKeeper::get_number () const
{
return number;
}
void DoubleKeeper::set_number (double f)
{
number = f;
}
void DoubleKeeper::set_number ()
{
number = 1.0;
}
double
DoubleKeeper::transmogrify (double value) const
{
return value*number;
}
double
transmogrify_from_cpp (DoubleKeeper const *obj, double value)
{
return obj->transmogrify (value);
}
void voidfunc(void);
double doublefunc (double a, double b, double c);
class DoubleKeeper
{
double number;
public:
DoubleKeeper ();
DoubleKeeper (double number);
virtual ~DoubleKeeper ();
void set_number (double num);
void set_number (void);
double get_number () const;
virtual double transmogrify (double value) const;
};
double transmogrify_from_cpp (DoubleKeeper const *obj, double value);
cdef extern from "testapi.h":
void voidfunc()
double doublefunc(double a, double b, double c)
cdef cppclass DoubleKeeper:
DoubleKeeper()
DoubleKeeper(double factor)
void set_number()
void set_number(double f)
double get_number()
double transmogrify(double value)
double transmogrify_from_cpp (DoubleKeeper *obj, double value)
cimport cppwrap_lib
cdef class DoubleKeeper:
cdef cppwrap_lib.DoubleKeeper* keeper
def __cinit__(self, double number):
self.keeper = new cppwrap_lib.DoubleKeeper(number)
def __dealloc__(self):
del self.keeper
def set_number(self, double number):
self.keeper.set_number(number)
def get_number(self):
return self.keeper.get_number()
def transmogrify(self, double value):
return self.keeper.transmogrify(value)
def voidfunc():
cppwrap_lib.voidfunc()
def doublefunc(double x, double y, double z):
return cppwrap_lib.doublefunc(x, y, z)
def transmogrify_from_cpp(DoubleKeeper obj not None, double value):
return cppwrap_lib.transmogrify_from_cpp(obj.keeper, value)
#include "cppwrap_lib.h"
void voidfunc (void)
{
}
double doublefunc (double a, double b, double c)
{
return a + b + c;
}
DoubleKeeper::DoubleKeeper ()
: number (1.0)
{
}
DoubleKeeper::DoubleKeeper (double factor)
: number (factor)
{
}
DoubleKeeper::~DoubleKeeper ()
{
}
double DoubleKeeper::get_number () const
{
return number;
}
void DoubleKeeper::set_number (double f)
{
number = f;
}
void DoubleKeeper::set_number ()
{
number = 1.0;
}
double
DoubleKeeper::transmogrify (double value) const
{
return value*number;
}
double
transmogrify_from_cpp (DoubleKeeper const *obj, double value)
{
return obj->transmogrify (value);
}
void voidfunc(void);
double doublefunc (double a, double b, double c);
class DoubleKeeper
{
double number;
public:
DoubleKeeper (double number);
virtual ~DoubleKeeper ();
void set_number (double num);
double get_number () const;
virtual double transmogrify (double value) const;
};
double transmogrify_from_cpp (DoubleKeeper const *obj, double value);
cdef extern from "testapi.h":
void voidfunc()
double doublefunc(double a, double b, double c)
cdef cppclass DoubleKeeper:
DoubleKeeper(double factor)
void set_number(double f)
double get_number()
double transmogrify(double value)
double transmogrify_from_cpp (DoubleKeeper *obj, double value)
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