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):
blacklist = ['__cinit__', '__dealloc__', '__richcmp__', '__nonzero__']
def visit_ModuleNode(self, node):
if node.is_pxd:
return node
self.scope_type = 'module'
self.scope_node = node
if self.current_directives['autotestdict']:
......
......@@ -143,7 +143,9 @@ function toggleDiv(id) {
code = self.code[k]
except KeyError:
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, 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)
......
......@@ -20,7 +20,7 @@ class EmbedSignature(CythonTransform):
try:
denv = self.denv # XXX
ctval = default_val.compile_time_value(self.denv)
repr_val = '%r' % ctval
repr_val = repr(ctval)
if isinstance(default_val, ExprNodes.UnicodeNode):
if repr_val[:1] != 'u':
return u'u%s' % repr_val
......@@ -28,8 +28,8 @@ class EmbedSignature(CythonTransform):
if repr_val[:1] != 'b':
return u'b%s' % repr_val
elif isinstance(default_val, ExprNodes.StringNode):
if repr_val[:1] in ('u', 'b'):
repr_val[1:]
if repr_val[:1] in 'ub':
return repr_val[1:]
return repr_val
except Exception:
try:
......
......@@ -31,7 +31,7 @@ builtin_function_table = [
('intern', "O", "O", "__Pyx_Intern"),
('isinstance', "OO", "b", "PyObject_IsInstance"),
('issubclass', "OO", "b", "PyObject_IsSubclass"),
('iter', "O", "O", "PyObject_GetIter"),
#('iter', "O", "O", "PyObject_GetIter"), # optimised later on
('len', "O", "Z", "PyObject_Length"),
('locals', "", "O", "__pyx_locals"),
#('map', "", "", ""),
......
......@@ -1057,20 +1057,17 @@ class NewExprNode(AtomicExprNode):
# C++ new statement
#
# cppclass string c++ class to create
# template_parameters None or [ExprNode] temlate parameters, if any
# cppclass node c++ class to create
type = None
def infer_type(self, env):
entry = env.lookup(self.cppclass)
if entry is None or not entry.is_cpp_class:
type = self.cppclass.analyse_as_type(env)
if type is None or not type.is_cpp_class:
error(self.pos, "new operator can only be applied to a C++ class")
self.type = error_type
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, [])
......@@ -1083,7 +1080,8 @@ class NewExprNode(AtomicExprNode):
return self.type
def analyse_types(self, env):
self.infer_type(env)
if self.type is None:
self.infer_type(env)
def generate_result_code(self, code):
pass
......@@ -2051,7 +2049,11 @@ class IndexNode(ExprNode):
function = "__Pyx_GetItemInt"
code.globalstate.use_utility_code(getitem_int_utility_code)
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()
sign_code = ""
code.putln(
......@@ -2290,7 +2292,7 @@ class SliceIndexNode(ExprNode):
self.base.py_result(),
self.start_code(),
self.stop_code(),
rhs.result()))
rhs.py_result()))
else:
start_offset = ''
if self.start:
......@@ -2466,6 +2468,15 @@ class CallNode(ExprNode):
self.analyse_types(env)
self.coerce_to(type, env)
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):
func_type = self.function_type()
......@@ -2603,22 +2614,35 @@ class SimpleCallNode(CallNode):
return func_type
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:
function = self.function.type.scope.lookup("operator()")
if function is None:
overloaded_entry = self.function.type.scope.lookup("operator()")
if overloaded_entry is None:
self.type = PyrexTypes.error_type
self.result_code = "<error>"
return
elif hasattr(self.function, 'entry'):
overloaded_entry = self.function.entry
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()
overloaded_entry = None
if overloaded_entry:
entry = PyrexTypes.best_match(self.args, overloaded_entry.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()
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
max_nargs = len(func_type.args)
expected_nargs = max_nargs - func_type.optional_arg_count
......@@ -3055,6 +3079,10 @@ class AttributeNode(ExprNode):
module_scope = self.obj.analyse_as_module(env)
if module_scope:
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
def analyse_as_extension_type(self, env):
......@@ -4320,8 +4348,7 @@ class UnopNode(ExprNode):
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)
function = type.scope.lookup("operator%s" % self.operator)
if not function:
error(self.pos, "'%s' operator not defined for %s"
% (self.operator, type))
......@@ -6546,8 +6573,64 @@ impl = ""
#------------------------------------------------------------------------------------
# If the is_unsigned flag is set, we need to do some extra work to make
# sure the index doesn't become negative.
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");
}
''')
#------------------------------------------------------------------------------------
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(
proto = """
......@@ -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(
proto = """
static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(void);
......
......@@ -663,6 +663,17 @@ class CArgDeclNode(Node):
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:
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)
else:
return self.name_declarator, self.type
......@@ -770,6 +781,27 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
else:
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):
# After parsing:
# positional_args [ExprNode] List of positional arguments
......@@ -823,7 +855,7 @@ class TemplatedTypeNode(CBaseTypeNode):
else:
# 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:
error(self.pos, "invalid array declaration")
self.type = PyrexTypes.error_type
......@@ -834,9 +866,10 @@ class TemplatedTypeNode(CBaseTypeNode):
dimension = None
else:
dimension = self.positional_args[0]
self.type = CArrayDeclaratorNode(self.pos,
self.array_declarator = CArrayDeclaratorNode(self.pos,
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
......@@ -5147,6 +5180,8 @@ utility_function_predeclarations = \
#define CYTHON_INLINE __inline__
#elif defined(_MSC_VER)
#define CYTHON_INLINE __inline
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define CYTHON_INLINE inline
#else
#define CYTHON_INLINE
#endif
......
This diff is collapsed.
......@@ -262,6 +262,145 @@ class PostParse(CythonTransform):
self.context.nonfatal_error(e)
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):
"""
Basic interpretation/validity checking that should only be
......
......@@ -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_expression_or_assignment(PyrexScanner s)
cpdef p_print_statement(PyrexScanner s)
......
......@@ -10,6 +10,15 @@ cython.declare(Nodes=object, ExprNodes=object, EncodedString=object)
import os
import re
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
import Nodes
import ExprNodes
......@@ -362,14 +371,8 @@ 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))
cppclass = p_c_base_type(s)
return p_call(s, ExprNodes.NewExprNode(pos, cppclass = cppclass))
#trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
......@@ -960,129 +963,14 @@ def p_expression_or_assignment(s):
return Nodes.PassStatNode(expr.pos)
else:
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
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
rhs = expr_list[-1]
if len(expr_list) == 2:
return Nodes.SingleAssignmentNode(rhs.pos,
lhs = expr_list[0], rhs = rhs)
else:
pos = target.pos
starred_assignments.append([
target, ExprNodes.ListNode(pos=pos, args=starred_rhs)])
return Nodes.CascadedAssignmentNode(rhs.pos,
lhs_list = expr_list[:-1], rhs = rhs)
def p_print_statement(s):
# s.sy == 'print'
......@@ -1916,11 +1804,15 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
complex = complex, longness = longness,
is_self_arg = self_flag, templates = templates)
if s.sy == '[':
return p_buffer_or_template(s, type_node, templates)
else:
return type_node
type_node = p_buffer_or_template(s, type_node, templates)
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):
# s.sy == '['
......@@ -2332,7 +2224,7 @@ def p_cdef_extern_block(s, pos, ctx):
_, include_file = p_string_literal(s)
if s.systring == "namespace":
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')
if p_nogil(s):
ctx.nogil = 1
......@@ -2796,7 +2688,10 @@ def p_cpp_class_definition(s, pos, ctx):
body_ctx = Ctx(visibility = ctx.visibility)
body_ctx.templates = templates
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(
p_c_func_or_var_declaration(s, s.position(), body_ctx))
else:
......
......@@ -1821,6 +1821,7 @@ class CppClassType(CType):
is_cpp_class = 1
has_attributes = 1
exception_check = True
namespace = None
def __init__(self, name, scope, cname, base_classes, templates = None, template_type = None):
self.name = name
......@@ -1843,15 +1844,22 @@ class CppClassType(CType):
return self.specialize(dict(zip(self.templates, template_values)))
def specialize(self, values):
if not self.templates:
if not self.templates and not self.namespace:
return self
if self.templates is None:
self.templates = []
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)
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)
if self.namespace is not None:
specialized.namespace = self.namespace.specialize(values)
return specialized
def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0):
......@@ -1863,7 +1871,10 @@ class CppClassType(CType):
if for_display or pyrex:
name = self.name
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)
def is_subclass(self, other_type):
......@@ -1890,6 +1901,8 @@ class CppClassType(CType):
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):
......
......@@ -97,7 +97,10 @@ def initial_compile_time_env():
'UNAME_VERSION', 'UNAME_MACHINE')
for name, value in zip(names, platform.uname()):
benv.declare(name, value)
import __builtin__ as builtins
try:
import __builtin__ as builtins
except ImportError:
import builtins
names = ('False', 'True',
'abs', 'bool', 'chr', 'cmp', 'complex', 'dict', 'divmod', 'enumerate',
'float', 'hash', 'hex', 'int', 'len', 'list', 'long', 'map', 'max', 'min',
......
......@@ -224,6 +224,7 @@ class Scope(object):
is_py_class_scope = 0
is_c_class_scope = 0
is_closure_scope = 0
is_cpp_class_scope = 0
is_module_scope = 0
is_internal = 0
scope_prefix = ""
......@@ -406,6 +407,44 @@ class Scope(object):
self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
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):
if typedef_flag != entry.type.typedef_flag:
error(pos, "'%s' previously declared using '%s'" % (
......@@ -444,7 +483,7 @@ class Scope(object):
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 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.is_variable = 1
self.control_flow.set_state((), (name, 'initialized'), False)
......@@ -1017,42 +1056,6 @@ class ModuleScope(Scope):
if typedef_flag and not self.in_cinclude:
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):
# If extension type has a vtable, allocate vtable struct and
# slot names for it.
......@@ -1556,11 +1559,15 @@ class CClassScope(ClassScope):
class CppClassScope(Scope):
# Namespace of a C++ class.
inherited_var_entries = []
is_cpp_class_scope = 1
default_constructor = None
def __init__(self, name, outer_scope):
Scope.__init__(self, name, outer_scope, None)
self.directives = outer_scope.directives
self.inherited_var_entries = []
def declare_var(self, name, type, pos,
cname = None, visibility = 'extern', is_cdef = 0, allow_pyobject = 0):
......@@ -1576,12 +1583,42 @@ class CppClassScope(Scope):
error(pos,
"C++ class member cannot be a Python object")
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,
cname = None, visibility = 'extern', defining = 0,
api = 0, in_pxd = 0, modifiers = ()):
if name == self.name.split('::')[-1] and cname is None:
self.check_base_default_constructor(pos)
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:
......@@ -1593,6 +1630,12 @@ class CppClassScope(Scope):
# to work with this type.
for base_entry in \
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,
base_entry.type, None, 'extern')
entry.is_variable = 1
......@@ -1606,11 +1649,17 @@ class CppClassScope(Scope):
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)
if entry.is_type:
scope.declare_type(entry.name,
entry.type.specialize(values),
entry.pos,
entry.cname)
else:
scope.declare_var(entry.name,
entry.type.specialize(values),
entry.pos,
entry.cname,
entry.visibility)
return scope
......
......@@ -50,13 +50,13 @@ class TestNormalizeTree(TransformTest):
""")
self.assertLines(u"""
(root): StatListNode
stats[0]: ParallelAssignmentNode
stats[0]: SingleAssignmentNode
lhs: NameNode
rhs: NameNode
stats[1]: SingleAssignmentNode
lhs: NameNode
rhs: NameNode
stats[0]: SingleAssignmentNode
lhs: TupleNode
args[0]: NameNode
args[1]: NameNode
rhs: TupleNode
args[0]: NameNode
args[1]: NameNode
""", self.treetypes(t))
def test_wrap_offagain(self):
......
......@@ -7,5 +7,6 @@
# and keep the old one under the module name _build_ext,
# 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
......@@ -15,16 +15,6 @@ from distutils.sysconfig import customize_compiler, get_python_version
from distutils.dep_util import newer, newer_group
from distutils import log
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
extension_name_re = _build_ext.extension_name_re
......@@ -83,18 +73,22 @@ class build_ext(_build_ext.build_ext):
self.build_extension(ext)
def cython_sources(self, sources, extension):
"""
Walk the list of source files in 'sources', looking for Cython
source files (.pyx and .py). Run Cython on all that are
found, and return a modified 'sources' list with Cython source
files replaced by the generated C (or C++) files.
"""
if PyrexError == None:
raise DistutilsPlatformError, \
("Cython does not appear to be installed "
"on platform '%s'") % os.name
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 = sys.exc_info()[1]
print("failed to import Cython: %s" % e)
raise DistutilsPlatformError("Cython does not appear to be installed")
new_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))))
\ No newline at end of file
;; Cython mode
(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 = [
]
VER_DEP_MODULES = {
# such as:
# (2,4) : (operator.le, lambda x: x in ['run.set']),
(2,4) : (operator.le, lambda x: x in ['run.extern_builtins_T258'
]),
(3,): (operator.ge, lambda x: x in ['run.non_future_division',
'compile.extsetslice',
'compile.extdelslice']),
......@@ -269,12 +269,18 @@ class CythonCompileTestCase(unittest.TestCase):
target = '%s.%s' % (module_name, self.language)
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
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)) ]
filename for filename in os.listdir(workdir)
if is_related(filename) and os.path.isfile(os.path.join(workdir, filename)) ]
def split_source_and_output(self, test_directory, module, workdir):
source_file = os.path.join(test_directory, module) + '.pyx'
......@@ -329,9 +335,10 @@ class CythonCompileTestCase(unittest.TestCase):
for match, get_additional_include_dirs in EXT_DEP_INCLUDES:
if match(module):
ext_include_dirs += get_additional_include_dirs()
self.copy_related_files(test_directory, workdir, module)
extension = Extension(
module,
sources = self.find_source_files(test_directory, module),
sources = self.find_source_files(workdir, module),
include_dirs = ext_include_dirs,
extra_compile_args = CFLAGS,
)
......@@ -717,7 +724,12 @@ if __name__ == '__main__':
help="display test progress, pass twice to print test names")
parser.add_option("-T", "--ticket", dest="tickets",
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()
......@@ -871,7 +883,14 @@ if __name__ == '__main__':
os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test'),
'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:
coverage.stop()
......@@ -891,4 +910,7 @@ if __name__ == '__main__':
import refnanny
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":
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:
import lib2to3.refactor
from distutils.command.build_py \
......@@ -34,7 +39,7 @@ if sys.version_info[0] >= 3:
if fix.split('fix_')[-1] not in ('next',)
]
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):
......@@ -72,54 +77,84 @@ else:
else:
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:
raise ValueError
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 = []
from Cython.Distutils import build_ext as build_ext_orig
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
setup_args['cmdclass'] = {"build_ext" : build_ext}
except Exception:
print("ERROR: %s" % sys.exc_info()[1])
print("Extension module compilation failed, using plain Python implementation")
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
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)
......
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
cfunc_call_tuple_args_T408
cascaded_list_unpacking_T467
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]
cdef extern char *(*cpapfn())[5]
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 *p=NULL
global ifnp, cpa
......
......@@ -8,7 +8,13 @@ ctypedef struct s: # FIXME: this might be worth an error ...
int x
s()
cdef int x():
return 0
x()()
_ERRORS = u"""
2:1: Calling non-function type 'int'
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)
def length1():
......@@ -27,12 +22,11 @@ def length_recursive():
_ERRORS = u"""
5:4: more than 1 starred expression in assignment
10:4: too many values to unpack (expected 2, got 3)
13:4: need more than 1 value to unpack
16:4: need more than 0 values to unpack
19:4: need more than 0 values to unpack
22:4: need more than 0 values to unpack
23:4: need more than 1 value to unpack
26:6: need more than 1 value to unpack
5:4: too many values to unpack (expected 2, got 3)
8:4: need more than 1 value to unpack
11:4: need more than 0 values to unpack
14:4: need more than 0 values to unpack
17:4: need more than 0 values to unpack
18:4: need more than 1 value to unpack
21: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__ = """
7
>>> lentest_char_c()
7
>>> lentest_char_c_short()
7
>>> lentest_char_c_float()
7.0
>>> lentest_uchar()
7
......@@ -36,6 +40,20 @@ def lentest_char_c():
cdef Py_ssize_t l = len(s)
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(
"//PythonCapiCallNode",
......
......@@ -21,7 +21,7 @@ def test_arithmetic(double complex z, double complex w):
>>> test_arithmetic(5-10j, 3+4j)
((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)
def test_div_by_zero(double complex z):
......
......@@ -7,7 +7,7 @@ __doc__ = u"""
(225.0, 225.0)
"""
cdef extern from "shapes.h" namespace shapes:
cdef extern from "shapes.h" namespace "shapes":
cdef cppclass Shape:
float area()
......@@ -19,6 +19,7 @@ cdef extern from "shapes.h" namespace shapes:
cdef cppclass Rectangle(Shape):
int width
int height
Rectangle()
Rectangle(int, int)
cdef cppclass Square(Rectangle):
......
......@@ -22,8 +22,7 @@ def test_wrap_pair(int i, double x):
(2, 2.25, True)
"""
try:
pair = new Pair[int, double](i, x)
wrap = new Wrap[Pair[int, double]](deref(pair))
wrap = new Wrap[Pair[int, double]](Pair[int, double](i, x))
return wrap.get().first(), wrap.get().second(), deref(wrap) == deref(wrap)
finally:
del pair, wrap
del wrap
__doc__ = u"""
>>> test_vector([1,10,100])
1
10
100
"""
cdef extern from "vector" namespace std:
cdef cppclass iterator[T]:
pass
cdef extern from "vector" namespace "std":
cdef cppclass vector[T]:
#constructors
__init__()
T at(int)
void push_back(T t)
void assign(int, T)
void clear()
int size()
cppclass iterator:
T operator*()
iterator operator++()
bint operator==(iterator)
bint operator!=(iterator)
iterator end()
iterator begin()
int size()
from cython.operator cimport dereference as deref, preincrement as inc
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:
V.push_back(a)
v.push_back(a)
cdef int i
for i in range(len(L)):
print V.at(i)
del V
print v.at(i)
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]:
void push_back(T)
......
......@@ -58,4 +58,31 @@ def test_pair(int i, double x):
finally:
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":
ctypedef class __builtin__.str [object PyStringObject]:
cdef long ob_shash
ctypedef class __builtin__.list [object PyListObject]:
cdef Py_ssize_t ob_size
cdef Py_ssize_t allocated
ctypedef class __builtin__.dict [object PyDictObject]:
pass
cdef str s = "abc"
cdef Py_ssize_t Py_SIZE(object o)
cdef list L = [1,2,4]
cdef dict d = {'A': 'a'}
def test_list(list L):
"""
>>> test_list(list(range(10)))
......@@ -23,18 +20,7 @@ def test_list(list L):
>>> test_list(list_subclass([1,2,3]))
True
"""
return L.ob_size <= 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
return Py_SIZE(L) <= L.allocated
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):
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(
# "//ParallelAssignmentNode",
# "//ParallelAssignmentNode/SingleAssignmentNode",
......
......@@ -17,6 +17,7 @@ namespace shapes {
class Rectangle : public Shape
{
public:
Rectangle() { }
Rectangle(int width, int height)
{
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:
"""
>>> 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
def __cinit__(self, number=None):
......@@ -23,14 +34,33 @@ cdef class DoubleKeeper:
return self.keeper.get_number()
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)
def voidfunc():
"""
>>> voidfunc()
"""
cppwrap_lib.voidfunc()
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)
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)
#include "cppwrap_lib.h"
#include "cpp_overload_wrapper_lib.h"
void voidfunc (void)
{
......
cdef extern from "testapi.h":
cdef extern from "cpp_overload_wrapper_lib.h":
void voidfunc()
double doublefunc(double a, double b, double c)
......
......@@ -2,6 +2,18 @@
cimport cppwrap_lib
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
def __cinit__(self, double number):
......@@ -21,10 +33,22 @@ cdef class DoubleKeeper:
def voidfunc():
"""
>>> voidfunc()
"""
cppwrap_lib.voidfunc()
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)
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)
......@@ -10,12 +10,6 @@ double doublefunc (double a, double b, double c)
return a + b + c;
}
DoubleKeeper::DoubleKeeper ()
: number (1.0)
{
}
DoubleKeeper::DoubleKeeper (double factor)
: number (factor)
{
......@@ -35,11 +29,6 @@ void DoubleKeeper::set_number (double f)
number = f;
}
void DoubleKeeper::set_number ()
{
number = 1.0;
}
double
DoubleKeeper::transmogrify (double value) const
{
......
cdef extern from "testapi.h":
cdef extern from "cppwrap_lib.h":
void voidfunc()
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