Commit 8780b4c3 authored by Stefan Behnel's avatar Stefan Behnel

merged with latest cython-devel

parents cd2c1a33 7fd95d1a
...@@ -13,6 +13,8 @@ class AutoTestDictTransform(ScopeTrackingTransform): ...@@ -13,6 +13,8 @@ class AutoTestDictTransform(ScopeTrackingTransform):
blacklist = ['__cinit__', '__dealloc__', '__richcmp__', '__nonzero__'] blacklist = ['__cinit__', '__dealloc__', '__richcmp__', '__nonzero__']
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
if node.is_pxd:
return node
self.scope_type = 'module' self.scope_type = 'module'
self.scope_node = node self.scope_node = node
if self.current_directives['autotestdict']: if self.current_directives['autotestdict']:
......
...@@ -143,7 +143,9 @@ function toggleDiv(id) { ...@@ -143,7 +143,9 @@ function toggleDiv(id) {
code = self.code[k] code = self.code[k]
except KeyError: except KeyError:
code = '' code = ''
code = code.replace('<', '<code><</code>')
code, py_c_api_calls = py_c_api.subn(ur"<span class='py_c_api'>\1</span>(", code) code, py_c_api_calls = py_c_api.subn(ur"<span class='py_c_api'>\1</span>(", code)
code, pyx_c_api_calls = pyx_c_api.subn(ur"<span class='pyx_c_api'>\1</span>(", code) code, pyx_c_api_calls = pyx_c_api.subn(ur"<span class='pyx_c_api'>\1</span>(", code)
code, py_macro_api_calls = py_marco_api.subn(ur"<span class='py_macro_api'>\1</span>(", code) code, py_macro_api_calls = py_marco_api.subn(ur"<span class='py_macro_api'>\1</span>(", code)
......
...@@ -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:
......
...@@ -31,7 +31,7 @@ builtin_function_table = [ ...@@ -31,7 +31,7 @@ builtin_function_table = [
('intern', "O", "O", "__Pyx_Intern"), ('intern', "O", "O", "__Pyx_Intern"),
('isinstance', "OO", "b", "PyObject_IsInstance"), ('isinstance', "OO", "b", "PyObject_IsInstance"),
('issubclass', "OO", "b", "PyObject_IsSubclass"), ('issubclass', "OO", "b", "PyObject_IsSubclass"),
('iter', "O", "O", "PyObject_GetIter"), #('iter', "O", "O", "PyObject_GetIter"), # optimised later on
('len', "O", "Z", "PyObject_Length"), ('len', "O", "Z", "PyObject_Length"),
('locals', "", "O", "__pyx_locals"), ('locals', "", "O", "__pyx_locals"),
#('map', "", "", ""), #('map', "", "", ""),
......
...@@ -1057,20 +1057,17 @@ class NewExprNode(AtomicExprNode): ...@@ -1057,20 +1057,17 @@ class NewExprNode(AtomicExprNode):
# C++ new statement # C++ new statement
# #
# cppclass string c++ class to create # cppclass node c++ class to create
# template_parameters None or [ExprNode] temlate parameters, if any
type = None
def infer_type(self, env): def infer_type(self, env):
entry = env.lookup(self.cppclass) type = self.cppclass.analyse_as_type(env)
if entry is None or not entry.is_cpp_class: if type is None or not type.is_cpp_class:
error(self.pos, "new operator can only be applied to a C++ class") error(self.pos, "new operator can only be applied to a C++ class")
self.type = error_type
return return
self.cpp_check(env) 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>') constructor = type.scope.lookup(u'<init>')
if constructor is None: if constructor is None:
return_type = PyrexTypes.CFuncType(type, []) return_type = PyrexTypes.CFuncType(type, [])
...@@ -1083,7 +1080,8 @@ class NewExprNode(AtomicExprNode): ...@@ -1083,7 +1080,8 @@ class NewExprNode(AtomicExprNode):
return self.type return self.type
def analyse_types(self, env): def analyse_types(self, env):
self.infer_type(env) if self.type is None:
self.infer_type(env)
def generate_result_code(self, code): def generate_result_code(self, code):
pass pass
...@@ -2051,7 +2049,11 @@ class IndexNode(ExprNode): ...@@ -2051,7 +2049,11 @@ class IndexNode(ExprNode):
function = "__Pyx_GetItemInt" function = "__Pyx_GetItemInt"
code.globalstate.use_utility_code(getitem_int_utility_code) code.globalstate.use_utility_code(getitem_int_utility_code)
else: else:
function = "PyObject_GetItem" if self.base.type is dict_type:
function = "__Pyx_PyDict_GetItem"
code.globalstate.use_utility_code(getitem_dict_utility_code)
else:
function = "PyObject_GetItem"
index_code = self.index.py_result() index_code = self.index.py_result()
sign_code = "" sign_code = ""
code.putln( code.putln(
...@@ -2290,7 +2292,7 @@ class SliceIndexNode(ExprNode): ...@@ -2290,7 +2292,7 @@ class SliceIndexNode(ExprNode):
self.base.py_result(), self.base.py_result(),
self.start_code(), self.start_code(),
self.stop_code(), self.stop_code(),
rhs.result())) rhs.py_result()))
else: else:
start_offset = '' start_offset = ''
if self.start: if self.start:
...@@ -2466,6 +2468,15 @@ class CallNode(ExprNode): ...@@ -2466,6 +2468,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()
...@@ -2603,22 +2614,35 @@ class SimpleCallNode(CallNode): ...@@ -2603,22 +2614,35 @@ class SimpleCallNode(CallNode):
return func_type return func_type
def analyse_c_function_call(self, env): def analyse_c_function_call(self, env):
if self.function.type is error_type:
self.type = error_type
return
if self.function.type.is_cpp_class: if self.function.type.is_cpp_class:
function = self.function.type.scope.lookup("operator()") overloaded_entry = self.function.type.scope.lookup("operator()")
if function is None: if overloaded_entry is None:
self.type = PyrexTypes.error_type self.type = PyrexTypes.error_type
self.result_code = "<error>" self.result_code = "<error>"
return return
elif hasattr(self.function, 'entry'):
overloaded_entry = self.function.entry
else: else:
function = self.function.entry overloaded_entry = None
entry = PyrexTypes.best_match(self.args, function.all_alternatives(), self.pos) if overloaded_entry:
if not entry: entry = PyrexTypes.best_match(self.args, overloaded_entry.all_alternatives(), self.pos)
self.type = PyrexTypes.error_type if not entry:
self.result_code = "<error>" self.type = PyrexTypes.error_type
return self.result_code = "<error>"
self.function.entry = entry return
self.function.type = entry.type self.function.entry = entry
func_type = self.function_type() self.function.type = entry.type
func_type = self.function_type()
else:
func_type = self.function_type()
if not func_type.is_cfunction:
error(self.pos, "Calling non-function type '%s'" % func_type)
self.type = PyrexTypes.error_type
self.result_code = "<error>"
return
# 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
...@@ -3055,6 +3079,10 @@ class AttributeNode(ExprNode): ...@@ -3055,6 +3079,10 @@ class AttributeNode(ExprNode):
module_scope = self.obj.analyse_as_module(env) module_scope = self.obj.analyse_as_module(env)
if module_scope: if module_scope:
return module_scope.lookup_type(self.attribute) return module_scope.lookup_type(self.attribute)
if not isinstance(self.obj, (UnicodeNode, StringNode, BytesNode)):
base_type = self.obj.analyse_as_type(env)
if base_type and hasattr(base_type, 'scope'):
return base_type.scope.lookup_type(self.attribute)
return None return None
def analyse_as_extension_type(self, env): def analyse_as_extension_type(self, env):
...@@ -4320,8 +4348,7 @@ class UnopNode(ExprNode): ...@@ -4320,8 +4348,7 @@ class UnopNode(ExprNode):
type = self.operand.type type = self.operand.type
if type.is_ptr or type.is_reference: if type.is_ptr or type.is_reference:
type = type.base_type type = type.base_type
entry = env.lookup(type.name) function = type.scope.lookup("operator%s" % self.operator)
function = entry.type.scope.lookup("operator%s" % self.operator)
if not function: if not function:
error(self.pos, "'%s' operator not defined for %s" error(self.pos, "'%s' operator not defined for %s"
% (self.operator, type)) % (self.operator, type))
...@@ -6546,8 +6573,64 @@ impl = "" ...@@ -6546,8 +6573,64 @@ impl = ""
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# If the is_unsigned flag is set, we need to do some extra work to make raise_noneattr_error_utility_code = UtilityCode(
# sure the index doesn't become negative. proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname) {
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname);
}
''')
raise_noneindex_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is unsubscriptable");
}
''')
raise_none_iter_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
}
''')
#------------------------------------------------------------------------------------
getitem_dict_utility_code = UtilityCode(
proto = """
#if PY_MAJOR_VERSION >= 3
static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
PyObject *value;
if (unlikely(d == Py_None)) {
__Pyx_RaiseNoneIndexingError();
return NULL;
}
value = PyDict_GetItemWithError(d, key);
if (unlikely(!value)) {
if (!PyErr_Occurred())
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
}
Py_INCREF(value);
return value;
}
#else
#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key)
#endif
""",
requires = [raise_noneindex_error_utility_code])
#------------------------------------------------------------------------------------
getitem_int_utility_code = UtilityCode( getitem_int_utility_code = UtilityCode(
proto = """ proto = """
...@@ -6676,36 +6759,6 @@ impl = """ ...@@ -6676,36 +6759,6 @@ impl = """
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
raise_noneattr_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname) {
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname);
}
''')
raise_noneindex_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is unsubscriptable");
}
''')
raise_none_iter_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
}
''')
raise_too_many_values_to_unpack = UtilityCode( raise_too_many_values_to_unpack = UtilityCode(
proto = """ proto = """
static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(void); static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(void);
......
...@@ -663,6 +663,17 @@ class CArgDeclNode(Node): ...@@ -663,6 +663,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
...@@ -770,6 +781,27 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -770,6 +781,27 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
else: else:
return PyrexTypes.error_type return PyrexTypes.error_type
class CNestedBaseTypeNode(CBaseTypeNode):
# For C++ classes that live inside other C++ classes.
# name string
# base_type CBaseTypeNode
child_attrs = ['base_type']
def analyse(self, env, could_be_name = None):
base_type = self.base_type.analyse(env)
if base_type is PyrexTypes.error_type:
return PyrexTypes.error_type
if not base_type.is_cpp_class:
error(self.pos, "'%s' is not a valid type scope" % base_type)
return PyrexTypes.error_type
type_entry = base_type.scope.lookup_here(self.name)
if not type_entry or not type_entry.is_type:
error(self.pos, "'%s.%s' is not a type identifier" % (base_type, self.name))
return PyrexTypes.error_type
return type_entry.type
class TemplatedTypeNode(CBaseTypeNode): class TemplatedTypeNode(CBaseTypeNode):
# After parsing: # After parsing:
# positional_args [ExprNode] List of positional arguments # positional_args [ExprNode] List of positional arguments
...@@ -823,7 +855,7 @@ class TemplatedTypeNode(CBaseTypeNode): ...@@ -823,7 +855,7 @@ class TemplatedTypeNode(CBaseTypeNode):
else: else:
# Array # Array
empty_declarator = CNameDeclaratorNode(self.pos, name="") empty_declarator = CNameDeclaratorNode(self.pos, name="", cname=None)
if len(self.positional_args) > 1 or self.keyword_args.key_value_pairs: if len(self.positional_args) > 1 or self.keyword_args.key_value_pairs:
error(self.pos, "invalid array declaration") error(self.pos, "invalid array declaration")
self.type = PyrexTypes.error_type self.type = PyrexTypes.error_type
...@@ -834,9 +866,10 @@ class TemplatedTypeNode(CBaseTypeNode): ...@@ -834,9 +866,10 @@ class TemplatedTypeNode(CBaseTypeNode):
dimension = None dimension = None
else: else:
dimension = self.positional_args[0] dimension = self.positional_args[0]
self.type = CArrayDeclaratorNode(self.pos, self.array_declarator = CArrayDeclaratorNode(self.pos,
base = empty_declarator, base = empty_declarator,
dimension = dimension).analyse(base_type, env)[1] dimension = dimension)
self.type = self.array_declarator.analyse(base_type, env)[1]
return self.type return self.type
...@@ -5147,6 +5180,8 @@ utility_function_predeclarations = \ ...@@ -5147,6 +5180,8 @@ utility_function_predeclarations = \
#define CYTHON_INLINE __inline__ #define CYTHON_INLINE __inline__
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define CYTHON_INLINE __inline #define CYTHON_INLINE __inline
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define CYTHON_INLINE inline
#else #else
#define CYTHON_INLINE #define CYTHON_INLINE
#endif #endif
......
This diff is collapsed.
...@@ -262,6 +262,145 @@ class PostParse(CythonTransform): ...@@ -262,6 +262,145 @@ class PostParse(CythonTransform):
self.context.nonfatal_error(e) self.context.nonfatal_error(e)
return None return None
# Split parallel assignments (a,b = b,a) into separate partial
# assignments that are executed rhs-first using temps. This
# optimisation is best applied before type analysis so that known
# types on rhs and lhs can be matched directly.
def visit_SingleAssignmentNode(self, node):
self.visitchildren(node)
return self._visit_assignment_node(node, [node.lhs, node.rhs])
def visit_CascadedAssignmentNode(self, node):
self.visitchildren(node)
return self._visit_assignment_node(node, node.lhs_list + [node.rhs])
def _visit_assignment_node(self, node, expr_list):
"""Flatten parallel assignments into separate single
assignments or cascaded assignments.
"""
if sum([ 1 for expr in expr_list if expr.is_sequence_constructor ]) < 2:
# no parallel assignments => nothing to do
return node
expr_list_list = []
flatten_parallel_assignments(expr_list, expr_list_list)
nodes = []
for expr_list in expr_list_list:
lhs_list = expr_list[:-1]
rhs = expr_list[-1]
if len(lhs_list) == 1:
node = Nodes.SingleAssignmentNode(rhs.pos,
lhs = lhs_list[0], rhs = rhs)
else:
node = Nodes.CascadedAssignmentNode(rhs.pos,
lhs_list = lhs_list, rhs = rhs)
nodes.append(node)
if len(nodes) == 1:
return nodes[0]
else:
return Nodes.ParallelAssignmentNode(nodes[0].pos, stats = nodes)
def flatten_parallel_assignments(input, output):
# The input is a list of expression nodes, representing the LHSs
# and RHS of one (possibly cascaded) assignment statement. For
# sequence constructors, rearranges the matching parts of both
# sides into a list of equivalent assignments between the
# individual elements. This transformation is applied
# recursively, so that nested structures get matched as well.
rhs = input[-1]
if not rhs.is_sequence_constructor or not sum([lhs.is_sequence_constructor for lhs in input[:-1]]):
output.append(input)
return
complete_assignments = []
rhs_size = len(rhs.args)
lhs_targets = [ [] for _ in xrange(rhs_size) ]
starred_assignments = []
for lhs in input[:-1]:
if not lhs.is_sequence_constructor:
if lhs.is_starred:
error(lhs.pos, "starred assignment target must be in a list or tuple")
complete_assignments.append(lhs)
continue
lhs_size = len(lhs.args)
starred_targets = sum([1 for expr in lhs.args if expr.is_starred])
if starred_targets > 1:
error(lhs.pos, "more than 1 starred expression in assignment")
output.append([lhs,rhs])
continue
elif lhs_size - starred_targets > rhs_size:
error(lhs.pos, "need more than %d value%s to unpack"
% (rhs_size, (rhs_size != 1) and 's' or ''))
output.append([lhs,rhs])
continue
elif starred_targets == 1:
map_starred_assignment(lhs_targets, starred_assignments,
lhs.args, rhs.args)
elif lhs_size < rhs_size:
error(lhs.pos, "too many values to unpack (expected %d, got %d)"
% (lhs_size, rhs_size))
output.append([lhs,rhs])
continue
else:
for targets, expr in zip(lhs_targets, lhs.args):
targets.append(expr)
if complete_assignments:
complete_assignments.append(rhs)
output.append(complete_assignments)
# recursively flatten partial assignments
for cascade, rhs in zip(lhs_targets, rhs.args):
if cascade:
cascade.append(rhs)
flatten_parallel_assignments(cascade, output)
# recursively flatten starred assignments
for cascade in starred_assignments:
if cascade[0].is_sequence_constructor:
flatten_parallel_assignments(cascade, output)
else:
output.append(cascade)
def map_starred_assignment(lhs_targets, starred_assignments, lhs_args, rhs_args):
# Appends the fixed-position LHS targets to the target list that
# appear left and right of the starred argument.
#
# The starred_assignments list receives a new tuple
# (lhs_target, rhs_values_list) that maps the remaining arguments
# (those that match the starred target) to a list.
# left side of the starred target
for i, (targets, expr) in enumerate(zip(lhs_targets, lhs_args)):
if expr.is_starred:
starred = i
lhs_remaining = len(lhs_args) - i - 1
break
targets.append(expr)
else:
raise InternalError("no starred arg found when splitting starred assignment")
# right side of the starred target
for i, (targets, expr) in enumerate(zip(lhs_targets[-lhs_remaining:],
lhs_args[-lhs_remaining:])):
targets.append(expr)
# the starred target itself, must be assigned a (potentially empty) list
target = lhs_args[starred].target # unpack starred node
starred_rhs = rhs_args[starred:]
if lhs_remaining:
starred_rhs = starred_rhs[:-lhs_remaining]
if starred_rhs:
pos = starred_rhs[0].pos
else:
pos = target.pos
starred_assignments.append([
target, ExprNodes.ListNode(pos=pos, args=starred_rhs)])
class PxdPostParse(CythonTransform, SkipDeclarations): class PxdPostParse(CythonTransform, SkipDeclarations):
""" """
Basic interpretation/validity checking that should only be Basic interpretation/validity checking that should only be
......
...@@ -62,8 +62,6 @@ cpdef p_testlist(PyrexScanner s) ...@@ -62,8 +62,6 @@ cpdef p_testlist(PyrexScanner s)
# #
#------------------------------------------------------- #-------------------------------------------------------
cpdef flatten_parallel_assignments(list input, list output)
cpdef p_global_statement(PyrexScanner s) cpdef p_global_statement(PyrexScanner s)
cpdef p_expression_or_assignment(PyrexScanner s) cpdef p_expression_or_assignment(PyrexScanner s)
cpdef p_print_statement(PyrexScanner s) cpdef p_print_statement(PyrexScanner s)
......
...@@ -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
...@@ -362,14 +371,8 @@ def p_new_expr(s): ...@@ -362,14 +371,8 @@ def p_new_expr(s):
# s.systring == 'new'. # s.systring == 'new'.
pos = s.position() pos = s.position()
s.next() s.next()
name = p_ident(s) cppclass = p_c_base_type(s)
if s.sy == '[': return p_call(s, ExprNodes.NewExprNode(pos, cppclass = cppclass))
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
...@@ -960,129 +963,14 @@ def p_expression_or_assignment(s): ...@@ -960,129 +963,14 @@ def p_expression_or_assignment(s):
return Nodes.PassStatNode(expr.pos) return Nodes.PassStatNode(expr.pos)
else: else:
return Nodes.ExprStatNode(expr.pos, expr = expr) return Nodes.ExprStatNode(expr.pos, expr = expr)
else:
expr_list_list = []
flatten_parallel_assignments(expr_list, expr_list_list)
nodes = []
for expr_list in expr_list_list:
lhs_list = expr_list[:-1]
rhs = expr_list[-1]
if len(lhs_list) == 1:
node = Nodes.SingleAssignmentNode(rhs.pos,
lhs = lhs_list[0], rhs = rhs)
else:
node = Nodes.CascadedAssignmentNode(rhs.pos,
lhs_list = lhs_list, rhs = rhs)
nodes.append(node)
if len(nodes) == 1:
return nodes[0]
else:
return Nodes.ParallelAssignmentNode(nodes[0].pos, stats = nodes)
def flatten_parallel_assignments(input, output):
# The input is a list of expression nodes, representing the LHSs
# and RHS of one (possibly cascaded) assignment statement. For
# sequence constructors, rearranges the matching parts of both
# sides into a list of equivalent assignments between the
# individual elements. This transformation is applied
# recursively, so that nested structures get matched as well.
rhs = input[-1]
if not rhs.is_sequence_constructor or not sum([lhs.is_sequence_constructor for lhs in input[:-1]]):
output.append(input)
return
complete_assignments = []
rhs_size = len(rhs.args)
lhs_targets = [ [] for _ in range(rhs_size) ]
starred_assignments = []
for lhs in input[:-1]:
if not lhs.is_sequence_constructor:
if lhs.is_starred:
error(lhs.pos, "starred assignment target must be in a list or tuple")
complete_assignments.append(lhs)
continue
lhs_size = len(lhs.args)
starred_targets = sum([1 for expr in lhs.args if expr.is_starred])
if starred_targets:
if starred_targets > 1:
error(lhs.pos, "more than 1 starred expression in assignment")
output.append([lhs,rhs])
continue
elif lhs_size - starred_targets > rhs_size:
error(lhs.pos, "need more than %d value%s to unpack"
% (rhs_size, (rhs_size != 1) and 's' or ''))
output.append([lhs,rhs])
continue
map_starred_assignment(lhs_targets, starred_assignments,
lhs.args, rhs.args)
else:
if lhs_size > rhs_size:
error(lhs.pos, "need more than %d value%s to unpack"
% (rhs_size, (rhs_size != 1) and 's' or ''))
output.append([lhs,rhs])
continue
elif lhs_size < rhs_size:
error(lhs.pos, "too many values to unpack (expected %d, got %d)"
% (lhs_size, rhs_size))
output.append([lhs,rhs])
continue
else:
for targets, expr in zip(lhs_targets, lhs.args):
targets.append(expr)
if complete_assignments:
complete_assignments.append(rhs)
output.append(complete_assignments)
# recursively flatten partial assignments
for cascade, rhs in zip(lhs_targets, rhs.args):
if cascade:
cascade.append(rhs)
flatten_parallel_assignments(cascade, output)
# recursively flatten starred assignments
for cascade in starred_assignments:
if cascade[0].is_sequence_constructor:
flatten_parallel_assignments(cascade, output)
else:
output.append(cascade)
def map_starred_assignment(lhs_targets, starred_assignments, lhs_args, rhs_args):
# Appends the fixed-position LHS targets to the target list that
# appear left and right of the starred argument.
#
# The starred_assignments list receives a new tuple
# (lhs_target, rhs_values_list) that maps the remaining arguments
# (those that match the starred target) to a list.
# left side of the starred target
for i, (targets, expr) in enumerate(zip(lhs_targets, lhs_args)):
if expr.is_starred:
starred = i
lhs_remaining = len(lhs_args) - i - 1
break
targets.append(expr)
else:
raise InternalError("no starred arg found when splitting starred assignment")
# right side of the starred target
for i, (targets, expr) in enumerate(zip(lhs_targets[-lhs_remaining:],
lhs_args[-lhs_remaining:])):
targets.append(expr)
# the starred target itself, must be assigned a (potentially empty) list rhs = expr_list[-1]
target = lhs_args[starred].target # unpack starred node if len(expr_list) == 2:
starred_rhs = rhs_args[starred:] return Nodes.SingleAssignmentNode(rhs.pos,
if lhs_remaining: lhs = expr_list[0], rhs = rhs)
starred_rhs = starred_rhs[:-lhs_remaining]
if starred_rhs:
pos = starred_rhs[0].pos
else: else:
pos = target.pos return Nodes.CascadedAssignmentNode(rhs.pos,
starred_assignments.append([ lhs_list = expr_list[:-1], rhs = rhs)
target, ExprNodes.ListNode(pos=pos, args=starred_rhs)])
def p_print_statement(s): def p_print_statement(s):
# s.sy == 'print' # s.sy == 'print'
...@@ -1916,11 +1804,15 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None): ...@@ -1916,11 +1804,15 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
complex = complex, longness = longness, complex = complex, longness = longness,
is_self_arg = self_flag, templates = templates) is_self_arg = self_flag, templates = templates)
if s.sy == '[': if s.sy == '[':
return p_buffer_or_template(s, type_node, templates) type_node = p_buffer_or_template(s, type_node, templates)
else:
return type_node if s.sy == '.':
s.next()
name = p_ident(s)
type_node = Nodes.CNestedBaseTypeNode(pos, base_type = type_node, name = name)
return type_node
def p_buffer_or_template(s, base_type_node, templates): def p_buffer_or_template(s, base_type_node, templates):
# s.sy == '[' # s.sy == '['
...@@ -2332,7 +2224,7 @@ def p_cdef_extern_block(s, pos, ctx): ...@@ -2332,7 +2224,7 @@ def p_cdef_extern_block(s, pos, ctx):
_, include_file = p_string_literal(s) _, include_file = p_string_literal(s)
if s.systring == "namespace": if s.systring == "namespace":
s.next() s.next()
ctx.namespace = p_dotted_name(s, as_allowed=False)[2].replace('.', '::') ctx.namespace = p_string_literal(s)[1]
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
...@@ -2796,7 +2688,10 @@ def p_cpp_class_definition(s, pos, ctx): ...@@ -2796,7 +2688,10 @@ def p_cpp_class_definition(s, pos, ctx):
body_ctx = Ctx(visibility = ctx.visibility) body_ctx = Ctx(visibility = ctx.visibility)
body_ctx.templates = templates body_ctx.templates = templates
while s.sy != 'DEDENT': while s.sy != 'DEDENT':
if s.sy != 'pass': if s.systring == 'cppclass':
attributes.append(
p_cpp_class_definition(s, s.position(), body_ctx))
elif s.sy != 'pass':
attributes.append( attributes.append(
p_c_func_or_var_declaration(s, s.position(), body_ctx)) p_c_func_or_var_declaration(s, s.position(), body_ctx))
else: else:
......
...@@ -1821,6 +1821,7 @@ class CppClassType(CType): ...@@ -1821,6 +1821,7 @@ class CppClassType(CType):
is_cpp_class = 1 is_cpp_class = 1
has_attributes = 1 has_attributes = 1
exception_check = True exception_check = True
namespace = None
def __init__(self, name, scope, cname, base_classes, templates = None, template_type = None): def __init__(self, name, scope, cname, base_classes, templates = None, template_type = None):
self.name = name self.name = name
...@@ -1843,15 +1844,22 @@ class CppClassType(CType): ...@@ -1843,15 +1844,22 @@ class CppClassType(CType):
return self.specialize(dict(zip(self.templates, template_values))) return self.specialize(dict(zip(self.templates, template_values)))
def specialize(self, values): def specialize(self, values):
if not self.templates: if not self.templates and not self.namespace:
return self return self
if self.templates is None:
self.templates = []
key = tuple(values.items()) key = tuple(values.items())
if key in self.specializations: if key in self.specializations:
return self.specializations[key] return self.specializations[key]
template_values = [t.specialize(values) for t in self.templates] template_values = [t.specialize(values) for t in self.templates]
specialized = self.specializations[key] = \ specialized = self.specializations[key] = \
CppClassType(self.name, None, self.cname, self.base_classes, template_values, template_type=self) CppClassType(self.name, None, self.cname, [], template_values, template_type=self)
# Need to do these *after* self.specializations[key] is set
# to avoid infinite recursion on circular references.
specialized.base_classes = [b.specialize(values) for b in self.base_classes]
specialized.scope = self.scope.specialize(values) specialized.scope = self.scope.specialize(values)
if self.namespace is not None:
specialized.namespace = self.namespace.specialize(values)
return specialized return specialized
def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0):
...@@ -1863,7 +1871,10 @@ class CppClassType(CType): ...@@ -1863,7 +1871,10 @@ class CppClassType(CType):
if for_display or pyrex: if for_display or pyrex:
name = self.name name = self.name
else: else:
name = self.cname if self.namespace is not None:
name = "%s::%s" % (self.namespace.declaration_code(''), self.cname)
else:
name = self.cname
return "%s%s %s" % (name, templates, entity_code) return "%s%s %s" % (name, templates, entity_code)
def is_subclass(self, other_type): def is_subclass(self, other_type):
...@@ -1890,6 +1901,8 @@ class CppClassType(CType): ...@@ -1890,6 +1901,8 @@ class CppClassType(CType):
def assignable_from_resolved_type(self, other_type): def assignable_from_resolved_type(self, other_type):
# TODO: handle operator=(...) here? # TODO: handle operator=(...) here?
if other_type is error_type:
return True
return other_type.is_cpp_class and other_type.is_subclass(self) return other_type.is_cpp_class and other_type.is_subclass(self)
def attributes_known(self): def attributes_known(self):
......
...@@ -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)
import __builtin__ as builtins try:
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',
......
...@@ -224,6 +224,7 @@ class Scope(object): ...@@ -224,6 +224,7 @@ class Scope(object):
is_py_class_scope = 0 is_py_class_scope = 0
is_c_class_scope = 0 is_c_class_scope = 0
is_closure_scope = 0 is_closure_scope = 0
is_cpp_class_scope = 0
is_module_scope = 0 is_module_scope = 0
is_internal = 0 is_internal = 0
scope_prefix = "" scope_prefix = ""
...@@ -406,6 +407,44 @@ class Scope(object): ...@@ -406,6 +407,44 @@ class Scope(object):
self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos) self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
return entry return entry
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)
if self.is_cpp_class_scope:
entry.type.namespace = self.outer_scope.lookup(self.name).type
return entry
def check_previous_typedef_flag(self, entry, typedef_flag, pos): def check_previous_typedef_flag(self, entry, typedef_flag, pos):
if typedef_flag != entry.type.typedef_flag: if typedef_flag != entry.type.typedef_flag:
error(pos, "'%s' previously declared using '%s'" % ( error(pos, "'%s' previously declared using '%s'" % (
...@@ -444,7 +483,7 @@ class Scope(object): ...@@ -444,7 +483,7 @@ class Scope(object):
if type.is_cpp_class and visibility != 'extern': if type.is_cpp_class and visibility != 'extern':
constructor = type.scope.lookup(u'<init>') constructor = type.scope.lookup(u'<init>')
if constructor is not None and PyrexTypes.best_match([], constructor.all_alternatives()) is None: if constructor is not None and PyrexTypes.best_match([], constructor.all_alternatives()) is None:
error(pos, "C++ class must have an empty constructor to be stack allocated") 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, 'initialized'), False) self.control_flow.set_state((), (name, 'initialized'), False)
...@@ -1017,42 +1056,6 @@ class ModuleScope(Scope): ...@@ -1017,42 +1056,6 @@ 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.
...@@ -1556,11 +1559,15 @@ class CClassScope(ClassScope): ...@@ -1556,11 +1559,15 @@ class CClassScope(ClassScope):
class CppClassScope(Scope): class CppClassScope(Scope):
# Namespace of a C++ class. # Namespace of a C++ class.
inherited_var_entries = []
is_cpp_class_scope = 1
default_constructor = None
def __init__(self, name, outer_scope): def __init__(self, name, outer_scope):
Scope.__init__(self, name, outer_scope, None) Scope.__init__(self, name, outer_scope, None)
self.directives = outer_scope.directives self.directives = outer_scope.directives
self.inherited_var_entries = []
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'extern', is_cdef = 0, allow_pyobject = 0): cname = None, visibility = 'extern', is_cdef = 0, allow_pyobject = 0):
...@@ -1576,12 +1583,42 @@ class CppClassScope(Scope): ...@@ -1576,12 +1583,42 @@ class CppClassScope(Scope):
error(pos, error(pos,
"C++ class member cannot be a Python object") "C++ class member cannot be a Python object")
return entry return entry
def check_base_default_constructor(self, pos):
# Look for default constructors in all base classes.
if self.default_constructor is None:
entry = self.lookup(self.name)
if len(entry.type.base_classes) == 0:
self.default_constructor = True
return
for base_class in entry.type.base_classes:
temp_entry = base_class.scope.lookup_here("<init>")
found = False
if temp_entry is None:
continue
for alternative in temp_entry.all_alternatives():
type = alternative.type
if type.is_ptr:
type = type.base_type
if len(type.args) == 0:
found = True
break
if not found:
self.default_constructor = temp_entry.scope.name
error(pos, "no matching function for call to " \
"%s::%s()" % (temp_entry.scope.name, temp_entry.scope.name))
elif not self.default_constructor:
print 5
error(pos, "no matching function for call to %s::%s()" %
(self.default_constructor, self.default_constructor))
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'extern', defining = 0, cname = None, visibility = 'extern', defining = 0,
api = 0, in_pxd = 0, modifiers = ()): api = 0, in_pxd = 0, modifiers = ()):
if name == self.name.split('::')[-1] and cname is None: if name == self.name.split('::')[-1] and cname is None:
self.check_base_default_constructor(pos)
name = '<init>' name = '<init>'
type.return_type = self.lookup(self.name).type
prev_entry = self.lookup_here(name) prev_entry = self.lookup_here(name)
entry = self.declare_var(name, type, pos, cname, visibility) entry = self.declare_var(name, type, pos, cname, visibility)
if prev_entry: if prev_entry:
...@@ -1593,6 +1630,12 @@ class CppClassScope(Scope): ...@@ -1593,6 +1630,12 @@ class CppClassScope(Scope):
# to work with this type. # to work with this type.
for base_entry in \ for base_entry in \
base_scope.inherited_var_entries + base_scope.var_entries: base_scope.inherited_var_entries + base_scope.var_entries:
#contructor is not inherited
if base_entry.name == "<init>":
continue
#print base_entry.name, self.entries
if base_entry.name in self.entries:
base_entry.name
entry = self.declare(base_entry.name, base_entry.cname, entry = self.declare(base_entry.name, base_entry.cname,
base_entry.type, None, 'extern') base_entry.type, None, 'extern')
entry.is_variable = 1 entry.is_variable = 1
...@@ -1606,11 +1649,17 @@ class CppClassScope(Scope): ...@@ -1606,11 +1649,17 @@ class CppClassScope(Scope):
def specialize(self, values): def specialize(self, values):
scope = CppClassScope(self.name, self.outer_scope) scope = CppClassScope(self.name, self.outer_scope)
for entry in self.entries.values(): for entry in self.entries.values():
scope.declare_var(entry.name, if entry.is_type:
entry.type.specialize(values), scope.declare_type(entry.name,
entry.pos, entry.type.specialize(values),
entry.cname, entry.pos,
entry.visibility) entry.cname)
else:
scope.declare_var(entry.name,
entry.type.specialize(values),
entry.pos,
entry.cname,
entry.visibility)
return scope return scope
......
...@@ -50,13 +50,13 @@ class TestNormalizeTree(TransformTest): ...@@ -50,13 +50,13 @@ class TestNormalizeTree(TransformTest):
""") """)
self.assertLines(u""" self.assertLines(u"""
(root): StatListNode (root): StatListNode
stats[0]: ParallelAssignmentNode stats[0]: SingleAssignmentNode
stats[0]: SingleAssignmentNode lhs: TupleNode
lhs: NameNode args[0]: NameNode
rhs: NameNode args[1]: NameNode
stats[1]: SingleAssignmentNode rhs: TupleNode
lhs: NameNode args[0]: NameNode
rhs: NameNode args[1]: NameNode
""", self.treetypes(t)) """, self.treetypes(t))
def test_wrap_offagain(self): def test_wrap_offagain(self):
......
...@@ -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 = []
......
This diff is collapsed.
;;;; `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)
...@@ -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']),
...@@ -269,12 +269,18 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -269,12 +269,18 @@ class CythonCompileTestCase(unittest.TestCase):
target = '%s.%s' % (module_name, self.language) target = '%s.%s' % (module_name, self.language)
return target return target
def find_source_files(self, test_directory, module_name): def copy_related_files(self, test_directory, target_directory, module_name):
is_related = re.compile('%s_.*[.].*' % module_name).match
for filename in os.listdir(test_directory):
if is_related(filename):
shutil.copy(os.path.join(test_directory, filename),
target_directory)
def find_source_files(self, workdir, module_name):
is_related = re.compile('%s_.*[.]%s' % (module_name, self.language)).match is_related = re.compile('%s_.*[.]%s' % (module_name, self.language)).match
return [self.build_target_filename(module_name)] + [ return [self.build_target_filename(module_name)] + [
os.path.join(test_directory, filename) filename for filename in os.listdir(workdir)
for filename in os.listdir(test_directory) if is_related(filename) and os.path.isfile(os.path.join(workdir, filename)) ]
if is_related(filename) and os.path.isfile(os.path.join(test_directory, filename)) ]
def split_source_and_output(self, test_directory, module, workdir): def split_source_and_output(self, test_directory, module, workdir):
source_file = os.path.join(test_directory, module) + '.pyx' source_file = os.path.join(test_directory, module) + '.pyx'
...@@ -329,9 +335,10 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -329,9 +335,10 @@ class CythonCompileTestCase(unittest.TestCase):
for match, get_additional_include_dirs in EXT_DEP_INCLUDES: for match, get_additional_include_dirs in EXT_DEP_INCLUDES:
if match(module): if match(module):
ext_include_dirs += get_additional_include_dirs() ext_include_dirs += get_additional_include_dirs()
self.copy_related_files(test_directory, workdir, module)
extension = Extension( extension = Extension(
module, module,
sources = self.find_source_files(test_directory, module), sources = self.find_source_files(workdir, module),
include_dirs = ext_include_dirs, include_dirs = ext_include_dirs,
extra_compile_args = CFLAGS, extra_compile_args = CFLAGS,
) )
...@@ -717,7 +724,12 @@ if __name__ == '__main__': ...@@ -717,7 +724,12 @@ if __name__ == '__main__':
help="display test progress, pass twice to print test names") help="display test progress, pass twice to print test names")
parser.add_option("-T", "--ticket", dest="tickets", parser.add_option("-T", "--ticket", dest="tickets",
action="append", action="append",
help="a bug ticket number to run the respective test in 'tests/bugs'") help="a bug ticket number to run the respective test in 'tests/*'")
parser.add_option("--xml-output", dest="xml_output_dir", metavar="DIR",
help="write test results in XML to directory DIR")
parser.add_option("--exit-ok", dest="exit_ok", default=False,
action="store_true",
help="exit without error code even on test failures")
options, cmd_args = parser.parse_args() options, cmd_args = parser.parse_args()
...@@ -871,7 +883,14 @@ if __name__ == '__main__': ...@@ -871,7 +883,14 @@ if __name__ == '__main__':
os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test'), os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test'),
'pyregr')) 'pyregr'))
result = unittest.TextTestRunner(verbosity=options.verbosity).run(test_suite) if options.xml_output_dir:
from Cython.Tests.xmlrunner import XMLTestRunner
test_runner = XMLTestRunner(output=options.xml_output_dir,
verbose=options.verbosity > 0)
else:
test_runner = unittest.TextTestRunner(verbosity=options.verbosity)
result = test_runner.run(test_suite)
if options.coverage: if options.coverage:
coverage.stop() coverage.stop()
...@@ -891,4 +910,7 @@ if __name__ == '__main__': ...@@ -891,4 +910,7 @@ if __name__ == '__main__':
import refnanny import refnanny
sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog])) sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog]))
sys.exit(not result.wasSuccessful()) if options.exit_ok:
sys.exit(0)
else:
sys.exit(not result.wasSuccessful())
...@@ -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,54 +77,84 @@ else: ...@@ -72,54 +77,84 @@ 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")
except ValueError:
try:
from distutils.command.build_ext import build_ext as build_ext_orig
class build_ext(build_ext_orig):
def build_extension(self, ext, *args, **kargs):
try:
build_ext_orig.build_extension(self, ext, *args, **kargs)
except StandardError:
print("Compilation of '%s' failed" % ext.sources[0])
from Cython.Compiler.Main import compile
from Cython import Utils
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"):
pyx_source_file = source_file + ".py" pyx_source_file = source_file + ".py"
else: else:
pyx_source_file = source_file + ".pyx" pyx_source_file = source_file + ".pyx"
c_source_file = source_file + ".c" extensions.append(
if not os.path.exists(c_source_file) or \ Extension(module, sources = [pyx_source_file])
Utils.file_newer_than(pyx_source_file, )
Utils.modification_time(c_source_file)):
print("Compiling module %s ..." % module) class build_ext(build_ext_orig):
result = compile(pyx_source_file) def build_extensions(self):
c_source_file = result.c_file # add path where 2to3 installed the transformed sources
if c_source_file: # and make sure Python (re-)imports them from there
extensions.append( already_imported = [ module for module in sys.modules
Extension(module, sources = [c_source_file]) if module == 'Cython' or module.startswith('Cython.') ]
) for module in already_imported:
else: del sys.modules[module]
print("Compilation failed") sys.path.insert(0, os.path.join(source_root, self.build_lib))
if extensions:
setup_args['ext_modules'] = extensions build_ext_orig.build_extensions(self)
setup_args['cmdclass'] = {"build_ext" : build_ext}
except Exception: setup_args['ext_modules'] = extensions
print("ERROR: %s" % sys.exc_info()[1]) add_command_class("build_ext", build_ext)
print("Extension module compilation failed, using plain Python implementation")
else: # Python 2.x
from distutils.command.build_ext import build_ext as build_ext_orig
try:
class build_ext(build_ext_orig):
def build_extension(self, ext, *args, **kargs):
try:
build_ext_orig.build_extension(self, ext, *args, **kargs)
except StandardError:
print("Compilation of '%s' failed" % ext.sources[0])
from Cython.Compiler.Main import compile
from Cython import Utils
source_root = os.path.dirname(__file__)
for module in compiled_modules:
source_file = os.path.join(source_root, *module.split('.'))
if os.path.exists(source_file + ".py"):
pyx_source_file = source_file + ".py"
else:
pyx_source_file = source_file + ".pyx"
c_source_file = source_file + ".c"
if not os.path.exists(c_source_file) or \
Utils.file_newer_than(pyx_source_file,
Utils.modification_time(c_source_file)):
print("Compiling module %s ..." % module)
result = compile(pyx_source_file)
c_source_file = result.c_file
if c_source_file:
extensions.append(
Extension(module, sources = [c_source_file])
)
else:
print("Compilation failed")
if extensions:
setup_args['ext_modules'] = extensions
add_command_class("build_ext", build_ext)
except Exception:
print("ERROR: %s" % sys.exc_info()[1])
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)
......
diff -r 8bff3332e34f Cython/Compiler/Code.py
--- a/Cython/Compiler/Code.py Tue Feb 02 02:10:32 2010 -0800
+++ b/Cython/Compiler/Code.py Thu Feb 04 19:33:59 2010 -0800
@@ -667,7 +667,7 @@
decls_writer = self.parts['decls']
for _, cname, c in c_consts:
decls_writer.putln('static char %s[] = "%s";' % (
- cname, c.escaped_value))
+ cname, StringEncoding.split_docstring(c.escaped_value)))
if c.py_strings is not None:
for py_string in c.py_strings.itervalues():
py_strings.append((c.cname, len(py_string.cname), py_string))
...@@ -9,5 +9,6 @@ missing_baseclass_in_predecl_T262 ...@@ -9,5 +9,6 @@ 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 compile.cpp_operators
cppwrap
cpp_overload_wrapper # Pyrex regression tests that don't current work:
test_threadsignals
...@@ -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
......
...@@ -8,7 +8,13 @@ ctypedef struct s: # FIXME: this might be worth an error ... ...@@ -8,7 +8,13 @@ ctypedef struct s: # FIXME: this might be worth an error ...
int x int x
s() s()
cdef int x():
return 0
x()()
_ERRORS = u""" _ERRORS = u"""
2:1: Calling non-function type 'int' 2:1: Calling non-function type 'int'
5:1: Calling non-function type 'float' 5:1: Calling non-function type 'float'
14:3: Calling non-function type 'int'
""" """
# invalid syntax (as handled by the parser)
def syntax():
*a, *b = 1,2,3,4,5
# wrong size RHS (as handled by the parser) # wrong size RHS (as handled by the parser)
def length1(): def length1():
...@@ -27,12 +22,11 @@ def length_recursive(): ...@@ -27,12 +22,11 @@ def length_recursive():
_ERRORS = u""" _ERRORS = u"""
5:4: more than 1 starred expression in assignment 5:4: too many values to unpack (expected 2, got 3)
10:4: too many values to unpack (expected 2, got 3) 8:4: need more than 1 value to unpack
13:4: need more than 1 value to unpack 11:4: need more than 0 values to unpack
16:4: need more than 0 values to unpack 14:4: need more than 0 values to unpack
19:4: need more than 0 values to unpack 17:4: need more than 0 values to unpack
22:4: need more than 0 values to unpack 18:4: need more than 1 value to unpack
23:4: need more than 1 value to unpack 21:6: need more than 1 value to unpack
26:6: need more than 1 value to unpack
""" """
# invalid syntax (as handled by the parser)
def syntax():
*a, *b = 1,2,3,4,5
_ERRORS = u"""
5:4: more than 1 starred expression in assignment
5:8: more than 1 starred expression in assignment
"""
...@@ -3,6 +3,10 @@ __doc__ = """ ...@@ -3,6 +3,10 @@ __doc__ = """
7 7
>>> lentest_char_c() >>> lentest_char_c()
7 7
>>> lentest_char_c_short()
7
>>> lentest_char_c_float()
7.0
>>> lentest_uchar() >>> lentest_uchar()
7 7
...@@ -36,6 +40,20 @@ def lentest_char_c(): ...@@ -36,6 +40,20 @@ def lentest_char_c():
cdef Py_ssize_t l = len(s) cdef Py_ssize_t l = len(s)
return l return l
@cython.test_assert_path_exists(
"//PythonCapiCallNode",
)
def lentest_char_c_short():
cdef short l = len(s)
return l
@cython.test_assert_path_exists(
"//PythonCapiCallNode",
)
def lentest_char_c_float():
cdef float l = len(s)
return l
@cython.test_assert_path_exists( @cython.test_assert_path_exists(
"//PythonCapiCallNode", "//PythonCapiCallNode",
......
...@@ -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):
......
...@@ -7,7 +7,7 @@ __doc__ = u""" ...@@ -7,7 +7,7 @@ __doc__ = u"""
(225.0, 225.0) (225.0, 225.0)
""" """
cdef extern from "shapes.h" namespace shapes: cdef extern from "shapes.h" namespace "shapes":
cdef cppclass Shape: cdef cppclass Shape:
float area() float area()
...@@ -19,6 +19,7 @@ cdef extern from "shapes.h" namespace shapes: ...@@ -19,6 +19,7 @@ cdef extern from "shapes.h" namespace shapes:
cdef cppclass Rectangle(Shape): cdef cppclass Rectangle(Shape):
int width int width
int height int height
Rectangle()
Rectangle(int, int) Rectangle(int, int)
cdef cppclass Square(Rectangle): cdef cppclass Square(Rectangle):
......
...@@ -22,8 +22,7 @@ def test_wrap_pair(int i, double x): ...@@ -22,8 +22,7 @@ def test_wrap_pair(int i, double x):
(2, 2.25, True) (2, 2.25, True)
""" """
try: try:
pair = new Pair[int, double](i, x) wrap = new Wrap[Pair[int, double]](Pair[int, double](i, x))
wrap = new Wrap[Pair[int, double]](deref(pair))
return wrap.get().first(), wrap.get().second(), deref(wrap) == deref(wrap) return wrap.get().first(), wrap.get().second(), deref(wrap) == deref(wrap)
finally: finally:
del pair, wrap del wrap
__doc__ = u""" cdef extern from "vector" namespace "std":
>>> test_vector([1,10,100])
1
10
100
"""
cdef extern from "vector" namespace std:
cdef cppclass iterator[T]:
pass
cdef cppclass vector[T]: cdef cppclass vector[T]:
#constructors
__init__()
T at(int) T at(int)
void push_back(T t) void push_back(T t)
void assign(int, T) void assign(int, T)
void clear() void clear()
int size()
cppclass iterator:
T operator*()
iterator operator++()
bint operator==(iterator)
bint operator!=(iterator)
iterator end() iterator end()
iterator begin() iterator begin()
int size() from cython.operator cimport dereference as deref, preincrement as inc
def test_vector(L): def test_vector(L):
cdef vector[int] *V = new vector[int]() """
>>> test_vector([1,10,100])
1
10
100
"""
v = new vector[int]()
for a in L: for a in L:
V.push_back(a) v.push_back(a)
cdef int i cdef int i
for i in range(len(L)): for i in range(len(L)):
print V.at(i) print v.at(i)
del V del v
def test_vector_iterator(L):
"""
>>> test_vector([11, 37, 389, 5077])
11
37
389
5077
"""
v = new vector[int]()
for a in L:
v.push_back(a)
cdef vector[int].iterator iter = v.begin()
while iter != v.end():
print deref(iter)
inc(iter)
del v
cdef extern from "<vector>" namespace std: cdef extern from "<vector>" namespace "std":
cdef cppclass vector[T]: cdef cppclass vector[T]:
void push_back(T) void push_back(T)
......
...@@ -58,4 +58,31 @@ def test_pair(int i, double x): ...@@ -58,4 +58,31 @@ def test_pair(int i, double x):
finally: finally:
del pair del pair
def test_ptr(int i):
"""
>>> test_ptr(3)
3
>>> test_ptr(5)
5
"""
try:
w = new Wrap[int*](&i)
return deref(w.get())
finally:
del w
cdef double f(double x):
return x*x
def test_func_ptr(double x):
"""
>>> test_func_ptr(3)
9.0
>>> test_func_ptr(-1.5)
2.25
"""
try:
w = new Wrap[double (*)(double)](&f)
return w.get()(x)
finally:
del w
def get(dict d, key):
"""
>>> d = { 1: 10 }
>>> d.get(1)
10
>>> get(d, 1)
10
>>> d.get(2) is None
True
>>> get(d, 2) is None
True
>>> d.get((1,2)) is None
True
>>> get(d, (1,2)) is None
True
>>> class Unhashable:
... def __hash__(self):
... raise ValueError
>>> d.get(Unhashable())
Traceback (most recent call last):
ValueError
>>> get(d, Unhashable())
Traceback (most recent call last):
ValueError
>>> None.get(1)
Traceback (most recent call last):
...
AttributeError: 'NoneType' object has no attribute 'get'
>>> get(None, 1)
Traceback (most recent call last):
...
AttributeError: 'NoneType' object has no attribute 'get'
"""
return d.get(key)
def get_default(dict d, key, default):
"""
>>> d = { 1: 10 }
>>> d.get(1, 2)
10
>>> get_default(d, 1, 2)
10
>>> d.get(2, 2)
2
>>> get_default(d, 2, 2)
2
>>> d.get((1,2), 2)
2
>>> get_default(d, (1,2), 2)
2
>>> class Unhashable:
... def __hash__(self):
... raise ValueError
>>> d.get(Unhashable(), 2)
Traceback (most recent call last):
ValueError
>>> get_default(d, Unhashable(), 2)
Traceback (most recent call last):
ValueError
"""
return d.get(key, default)
def test(dict d, index):
"""
>>> d = { 1: 10 }
>>> test(d, 1)
10
>>> test(d, 2)
Traceback (most recent call last):
...
KeyError: 2
>>> test(d, (1,2))
Traceback (most recent call last):
...
KeyError: (1, 2)
>>> class Unhashable:
... def __hash__(self):
... raise ValueError
>>> test(d, Unhashable())
Traceback (most recent call last):
...
ValueError
>>> test(None, 1)
Traceback (most recent call last):
...
TypeError: 'NoneType' object is unsubscriptable
"""
return d[index]
cdef class Subscriptable:
def __getitem__(self, key):
return key
\ No newline at end of file
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'}
def test_list(list L): def test_list(list L):
""" """
>>> test_list(list(range(10))) >>> test_list(list(range(10)))
...@@ -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):
""" """
......
def call_iter1(x):
"""
>>> [ i for i in iter([1,2,3]) ]
[1, 2, 3]
>>> [ i for i in call_iter1([1,2,3]) ]
[1, 2, 3]
"""
return iter(x)
class Ints(object):
def __init__(self):
self.i = 0
def __call__(self):
self.i += 1
if self.i > 10:
raise ValueError
return self.i
def call_iter2(x, sentinel):
"""
>>> [ i for i in iter(Ints(), 3) ]
[1, 2]
>>> [ i for i in call_iter2(Ints(), 3) ]
[1, 2]
"""
return iter(x, sentinel)
...@@ -107,6 +107,60 @@ def swap_attr_values(A a, A b): ...@@ -107,6 +107,60 @@ def swap_attr_values(A a, A b):
a.x, a.y, b.x, b.y = b.y, b.x, a.y, a.x # reverse a.x, a.y, b.x, b.y = b.y, b.x, a.y, a.x # reverse
cdef class B:
cdef readonly A a1
cdef readonly A a2
def __init__(self, x1, y1, x2, y2):
self.a1, self.a2 = A(x1, y1), A(x2, y2)
@cython.test_assert_path_exists(
"//ParallelAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode/CoerceToTempNode",
"//ParallelAssignmentNode/SingleAssignmentNode/CoerceToTempNode[@use_managed_ref=False]",
"//ParallelAssignmentNode/SingleAssignmentNode//AttributeNode/NameNode",
"//ParallelAssignmentNode/SingleAssignmentNode//AttributeNode[@use_managed_ref=False]/NameNode",
)
@cython.test_fail_if_path_exists(
"//ParallelAssignmentNode/SingleAssignmentNode/CoerceToTempNode[@use_managed_ref=True]",
"//ParallelAssignmentNode/SingleAssignmentNode/AttributeNode[@use_managed_ref=True]",
)
def swap_recursive_attr_values(B a, B b):
"""
>>> a, b = B(1,2,3,4), B(5,6,7,8)
>>> a.a1.x, a.a1.y, a.a2.x, a.a2.y
(1, 2, 3, 4)
>>> b.a1.x, b.a1.y, b.a2.x, b.a2.y
(5, 6, 7, 8)
>>> swap_recursive_attr_values(a,b)
>>> a.a1.x, a.a1.y, a.a2.x, a.a2.y
(2, 1, 4, 4)
>>> b.a1.x, b.a1.y, b.a2.x, b.a2.y
(6, 5, 8, 8)
# compatibility test
>>> class A:
... def __init__(self, x, y):
... self.x, self.y = x, y
>>> class B:
... def __init__(self, x1, y1, x2, y2):
... self.a1, self.a2 = A(x1, y1), A(x2, y2)
>>> a, b = B(1,2,3,4), B(5,6,7,8)
>>> a.a1, a.a2 = a.a2, a.a1
>>> b.a1, b.a2 = b.a2, b.a1
>>> a.a1, a.a1.x, a.a2.y, a.a2, a.a1.y, a.a2.x = a.a2, a.a2.y, a.a1.x, a.a1, a.a2.x, a.a1.y
>>> b.a1, b.a1.x, b.a2.y, b.a2, b.a1.y, b.a2.x = b.a2, b.a2.y, b.a1.x, b.a1, b.a2.x, b.a1.y
>>> a.a1.x, a.a1.y, a.a2.x, a.a2.y
(2, 1, 4, 4)
>>> b.a1.x, b.a1.y, b.a2.x, b.a2.y
(6, 5, 8, 8)
"""
a.a1, a.a2 = a.a2, a.a1
b.a1, b.a2 = b.a2, b.a1
a.a1, a.a1.x, a.a2.y, a.a2, a.a1.y, a.a2.x = a.a2, a.a2.y, a.a1.x, a.a1, a.a2.x, a.a1.y
b.a1, b.a1.x, b.a2.y, b.a2, b.a1.y, b.a2.x = b.a2, b.a2.y, b.a1.x, b.a1, b.a2.x, b.a1.y
@cython.test_assert_path_exists( @cython.test_assert_path_exists(
# "//ParallelAssignmentNode", # "//ParallelAssignmentNode",
# "//ParallelAssignmentNode/SingleAssignmentNode", # "//ParallelAssignmentNode/SingleAssignmentNode",
......
...@@ -17,6 +17,7 @@ namespace shapes { ...@@ -17,6 +17,7 @@ namespace shapes {
class Rectangle : public Shape class Rectangle : public Shape
{ {
public: public:
Rectangle() { }
Rectangle(int width, int height) Rectangle(int width, int height)
{ {
this->width = width; this->width = width;
......
cdef extern from *:
ctypedef class __builtin__.list [ object PyListObject ]:
pass
def slice_of_typed_value():
"""
>>> slice_of_typed_value()
[1, 2, 3]
"""
cdef object a = []
cdef list L = [1, 2, 3]
a[:] = L
return a
cimport cppwrap_lib cimport cpp_overload_wrapper_lib as cppwrap_lib
cdef class DoubleKeeper: cdef class DoubleKeeper:
"""
>>> d = DoubleKeeper()
>>> d.get_number()
1.0
>>> d.set_number(5.5)
>>> d.get_number()
5.5
>>> d.set_number(0)
>>> d.get_number()
0.0
"""
cdef cppwrap_lib.DoubleKeeper* keeper cdef cppwrap_lib.DoubleKeeper* keeper
def __cinit__(self, number=None): def __cinit__(self, number=None):
...@@ -23,14 +34,33 @@ cdef class DoubleKeeper: ...@@ -23,14 +34,33 @@ cdef class DoubleKeeper:
return self.keeper.get_number() return self.keeper.get_number()
def transmogrify(self, double value): def transmogrify(self, double value):
"""
>>> d = DoubleKeeper(5.5)
>>> d.transmogrify(1.0)
5.5
>>> d.transmogrify(2.0)
11.0
"""
return self.keeper.transmogrify(value) return self.keeper.transmogrify(value)
def voidfunc(): def voidfunc():
"""
>>> voidfunc()
"""
cppwrap_lib.voidfunc() cppwrap_lib.voidfunc()
def doublefunc(double x, double y, double z): def doublefunc(double x, double y, double z):
"""
>>> doublefunc(1.0, 2.0, 3.0) == 1.0 + 2.0 + 3.0
True
"""
return cppwrap_lib.doublefunc(x, y, z) return cppwrap_lib.doublefunc(x, y, z)
def transmogrify_from_cpp(DoubleKeeper obj not None, double value): def transmogrify_from_cpp(DoubleKeeper obj not None, double value):
"""
>>> d = DoubleKeeper(2.0)
>>> d.transmogrify(3.0) == 6.0
True
"""
return cppwrap_lib.transmogrify_from_cpp(obj.keeper, value) return cppwrap_lib.transmogrify_from_cpp(obj.keeper, value)
#include "cppwrap_lib.h" #include "cpp_overload_wrapper_lib.h"
void voidfunc (void) void voidfunc (void)
{ {
......
cdef extern from "testapi.h": cdef extern from "cpp_overload_wrapper_lib.h":
void voidfunc() void voidfunc()
double doublefunc(double a, double b, double c) double doublefunc(double a, double b, double c)
......
...@@ -2,6 +2,18 @@ ...@@ -2,6 +2,18 @@
cimport cppwrap_lib cimport cppwrap_lib
cdef class DoubleKeeper: cdef class DoubleKeeper:
"""
>>> d = DoubleKeeper(1.0)
>>> d.get_number() == 1.0
True
>>> d.get_number() == 2.0
False
>>> d.set_number(2.0)
>>> d.get_number() == 2.0
True
>>> d.transmogrify(3.0) == 6.0
True
"""
cdef cppwrap_lib.DoubleKeeper* keeper cdef cppwrap_lib.DoubleKeeper* keeper
def __cinit__(self, double number): def __cinit__(self, double number):
...@@ -21,10 +33,22 @@ cdef class DoubleKeeper: ...@@ -21,10 +33,22 @@ cdef class DoubleKeeper:
def voidfunc(): def voidfunc():
"""
>>> voidfunc()
"""
cppwrap_lib.voidfunc() cppwrap_lib.voidfunc()
def doublefunc(double x, double y, double z): def doublefunc(double x, double y, double z):
"""
>>> doublefunc(1.0, 2.0, 3.0) == 1.0 + 2.0 + 3.0
True
"""
return cppwrap_lib.doublefunc(x, y, z) return cppwrap_lib.doublefunc(x, y, z)
def transmogrify_from_cpp(DoubleKeeper obj not None, double value): def transmogrify_from_cpp(DoubleKeeper obj not None, double value):
"""
>>> d = DoubleKeeper(2.0)
>>> d.transmogrify(3.0) == 6.0
True
"""
return cppwrap_lib.transmogrify_from_cpp(obj.keeper, value) return cppwrap_lib.transmogrify_from_cpp(obj.keeper, value)
...@@ -10,12 +10,6 @@ double doublefunc (double a, double b, double c) ...@@ -10,12 +10,6 @@ double doublefunc (double a, double b, double c)
return a + b + c; return a + b + c;
} }
DoubleKeeper::DoubleKeeper ()
: number (1.0)
{
}
DoubleKeeper::DoubleKeeper (double factor) DoubleKeeper::DoubleKeeper (double factor)
: number (factor) : number (factor)
{ {
...@@ -35,11 +29,6 @@ void DoubleKeeper::set_number (double f) ...@@ -35,11 +29,6 @@ void DoubleKeeper::set_number (double f)
number = f; number = f;
} }
void DoubleKeeper::set_number ()
{
number = 1.0;
}
double double
DoubleKeeper::transmogrify (double value) const DoubleKeeper::transmogrify (double value) const
{ {
......
cdef extern from "testapi.h": cdef extern from "cppwrap_lib.h":
void voidfunc() void voidfunc()
double doublefunc(double a, double b, double c) double doublefunc(double a, double b, double c)
......
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