Commit 6bb725cb authored by Mark Florisson's avatar Mark Florisson

branch merge

parents 7ea63e29 17804df1
...@@ -24,3 +24,11 @@ e90c522631ae06f2170a751fb256cdea0e50fb21 0.12.1 ...@@ -24,3 +24,11 @@ e90c522631ae06f2170a751fb256cdea0e50fb21 0.12.1
5ac2eaefcdc9c3a7a9c29a0bb8c3e4c6c016c64c 0.13.beta0 5ac2eaefcdc9c3a7a9c29a0bb8c3e4c6c016c64c 0.13.beta0
14957f635a379c97d9966097276313e43491ed96 0.13.beta1 14957f635a379c97d9966097276313e43491ed96 0.13.beta1
32c957267b3ba3140fba4d1947fa98484d5e956b 0.13 32c957267b3ba3140fba4d1947fa98484d5e956b 0.13
ef9d2c680684d0df7d81f529cda29e9e1741f575 0.10.1
16a746d969e2654112fc0dc081690b891c496977 0.9.8
16a746d969e2654112fc0dc081690b891c496977 Version-0.9.8
0000000000000000000000000000000000000000 Version-0.9.8
ef9d2c680684d0df7d81f529cda29e9e1741f575 cython-0.10.1
0000000000000000000000000000000000000000 cython-0.10.1
59c67af0674bd93c5fd8958e08c76a9dab9aae37 sage-cythonizes
0000000000000000000000000000000000000000 sage-cythonizes
...@@ -421,6 +421,7 @@ class GlobalState(object): ...@@ -421,6 +421,7 @@ class GlobalState(object):
'all_the_rest', 'all_the_rest',
'pystring_table', 'pystring_table',
'cached_builtins', 'cached_builtins',
'cached_constants',
'init_globals', 'init_globals',
'init_module', 'init_module',
'cleanup_globals', 'cleanup_globals',
...@@ -462,7 +463,12 @@ class GlobalState(object): ...@@ -462,7 +463,12 @@ class GlobalState(object):
w.enter_cfunc_scope() w.enter_cfunc_scope()
w.putln("static int __Pyx_InitCachedBuiltins(void) {") w.putln("static int __Pyx_InitCachedBuiltins(void) {")
w = self.parts['cached_constants']
w.enter_cfunc_scope()
w.putln("")
w.putln("static int __Pyx_InitCachedConstants(void) {")
w.put_setup_refcount_context("__Pyx_InitCachedConstants")
w = self.parts['init_globals'] w = self.parts['init_globals']
w.enter_cfunc_scope() w.enter_cfunc_scope()
w.putln("") w.putln("")
...@@ -509,15 +515,27 @@ class GlobalState(object): ...@@ -509,15 +515,27 @@ class GlobalState(object):
if Options.cache_builtins: if Options.cache_builtins:
w = self.parts['cached_builtins'] w = self.parts['cached_builtins']
w.putln("return 0;") w.putln("return 0;")
w.put_label(w.error_label) if w.label_used(w.error_label):
w.putln("return -1;") w.put_label(w.error_label)
w.putln("return -1;")
w.putln("}") w.putln("}")
w.exit_cfunc_scope() w.exit_cfunc_scope()
w = self.parts['cached_constants']
w.put_finish_refcount_context()
w.putln("return 0;")
if w.label_used(w.error_label):
w.put_label(w.error_label)
w.put_finish_refcount_context()
w.putln("return -1;")
w.putln("}")
w.exit_cfunc_scope()
w = self.parts['init_globals'] w = self.parts['init_globals']
w.putln("return 0;") w.putln("return 0;")
w.put_label(w.error_label) if w.label_used(w.error_label):
w.putln("return -1;") w.put_label(w.error_label)
w.putln("return -1;")
w.putln("}") w.putln("}")
w.exit_cfunc_scope() w.exit_cfunc_scope()
...@@ -536,6 +554,9 @@ class GlobalState(object): ...@@ -536,6 +554,9 @@ class GlobalState(object):
# constant handling at code generation time # constant handling at code generation time
def get_cached_constants_writer(self):
return self.parts['cached_constants']
def get_int_const(self, str_value, longness=False): def get_int_const(self, str_value, longness=False):
longness = bool(longness) longness = bool(longness)
try: try:
...@@ -544,9 +565,14 @@ class GlobalState(object): ...@@ -544,9 +565,14 @@ class GlobalState(object):
c = self.new_int_const(str_value, longness) c = self.new_int_const(str_value, longness)
return c return c
def get_py_const(self, type): def get_py_const(self, type, prefix='', cleanup_level=None):
# create a new Python object constant # create a new Python object constant
return self.new_py_const(type) const = self.new_py_const(type, prefix)
if cleanup_level is not None \
and cleanup_level <= Options.generate_cleanup_code:
cleanup_writer = self.parts['cleanup_globals']
cleanup_writer.put_xdecref_clear(const.cname, type, nanny=False)
return const
def get_string_const(self, text): def get_string_const(self, text):
# return a C string constant, creating a new one if necessary # return a C string constant, creating a new one if necessary
...@@ -581,8 +607,8 @@ class GlobalState(object): ...@@ -581,8 +607,8 @@ class GlobalState(object):
self.int_const_index[(value, longness)] = c self.int_const_index[(value, longness)] = c
return c return c
def new_py_const(self, type): def new_py_const(self, type, prefix=''):
cname = self.new_const_cname() cname = self.new_const_cname(prefix)
c = PyObjectConst(cname, type) c = PyObjectConst(cname, type)
self.py_constants.append(c) self.py_constants.append(c)
return c return c
...@@ -946,6 +972,9 @@ class CCodeWriter(object): ...@@ -946,6 +972,9 @@ class CCodeWriter(object):
def get_py_num(self, str_value, longness): def get_py_num(self, str_value, longness):
return self.globalstate.get_int_const(str_value, longness).cname return self.globalstate.get_int_const(str_value, longness).cname
def get_py_const(self, type, prefix='', cleanup_level=None):
return self.globalstate.get_py_const(type, prefix, cleanup_level).cname
def get_string_const(self, text): def get_string_const(self, text):
return self.globalstate.get_string_const(text).cname return self.globalstate.get_string_const(text).cname
...@@ -961,6 +990,9 @@ class CCodeWriter(object): ...@@ -961,6 +990,9 @@ class CCodeWriter(object):
def intern_identifier(self, text): def intern_identifier(self, text):
return self.get_py_string_const(text, identifier=True) return self.get_py_string_const(text, identifier=True)
def get_cached_constants_writer(self):
return self.globalstate.get_cached_constants_writer()
# code generation # code generation
def putln(self, code = "", safe=False): def putln(self, code = "", safe=False):
...@@ -1247,11 +1279,13 @@ class CCodeWriter(object): ...@@ -1247,11 +1279,13 @@ class CCodeWriter(object):
def put_pymethoddef(self, entry, term, allow_skip=True): def put_pymethoddef(self, entry, term, allow_skip=True):
if entry.is_special or entry.name == '__getattribute__': if entry.is_special or entry.name == '__getattribute__':
if entry.name not in ['__cinit__', '__dealloc__', '__richcmp__', '__next__', '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', '__getcharbuffer__', '__getbuffer__', '__releasebuffer__', '__getattr__']: if entry.name not in ['__cinit__', '__dealloc__', '__richcmp__', '__next__', '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', '__getcharbuffer__', '__getbuffer__', '__releasebuffer__']:
if entry.name == '__getattr__' and not self.globalstate.directives['fast_getattr']:
pass
# Python's typeobject.c will automatically fill in our slot # Python's typeobject.c will automatically fill in our slot
# in add_operators() (called by PyType_Ready) with a value # in add_operators() (called by PyType_Ready) with a value
# that's better than ours. # that's better than ours.
if allow_skip: elif allow_skip:
return return
from TypeSlots import method_coexist from TypeSlots import method_coexist
if entry.doc: if entry.doc:
......
...@@ -800,9 +800,11 @@ class IntNode(ConstNode): ...@@ -800,9 +800,11 @@ class IntNode(ConstNode):
# unsigned "" or "U" # unsigned "" or "U"
# longness "" or "L" or "LL" # longness "" or "L" or "LL"
# is_c_literal True/False/None creator considers this a C integer literal
unsigned = "" unsigned = ""
longness = "" longness = ""
is_c_literal = None # unknown
def __init__(self, pos, **kwds): def __init__(self, pos, **kwds):
ExprNode.__init__(self, pos, **kwds) ExprNode.__init__(self, pos, **kwds)
...@@ -815,7 +817,10 @@ class IntNode(ConstNode): ...@@ -815,7 +817,10 @@ class IntNode(ConstNode):
self.calculate_constant_result() self.calculate_constant_result()
except ValueError: except ValueError:
pass pass
if self.constant_result in (constant_value_not_set, not_a_constant) or \ # we ignore 'is_c_literal = True' and instead map signed 32bit
# integers as C long values
if self.is_c_literal or \
self.constant_result in (constant_value_not_set, not_a_constant) or \
self.unsigned or self.longness == 'LL': self.unsigned or self.longness == 'LL':
# clearly a C literal # clearly a C literal
rank = (self.longness == 'LL') and 2 or 1 rank = (self.longness == 'LL') and 2 or 1
...@@ -844,17 +849,18 @@ class IntNode(ConstNode): ...@@ -844,17 +849,18 @@ class IntNode(ConstNode):
else: else:
return FloatNode(self.pos, value=self.value, type=dst_type, return FloatNode(self.pos, value=self.value, type=dst_type,
constant_result=not_a_constant) constant_result=not_a_constant)
node = IntNode(self.pos, value=self.value, constant_result=self.constant_result,
type = dst_type, unsigned=self.unsigned, longness=self.longness)
if dst_type.is_numeric and not dst_type.is_complex: if dst_type.is_numeric and not dst_type.is_complex:
node = IntNode(self.pos, value=self.value, constant_result=self.constant_result, node = IntNode(self.pos, value=self.value, constant_result=self.constant_result,
type = dst_type, unsigned=self.unsigned, longness=self.longness) type = dst_type, is_c_literal = True,
unsigned=self.unsigned, longness=self.longness)
return node return node
elif dst_type.is_pyobject: elif dst_type.is_pyobject:
node = IntNode(self.pos, value=self.value, constant_result=self.constant_result, node = IntNode(self.pos, value=self.value, constant_result=self.constant_result,
type = PyrexTypes.py_object_type, unsigned=self.unsigned, longness=self.longness) type = PyrexTypes.py_object_type, is_c_literal = False,
unsigned=self.unsigned, longness=self.longness)
else: else:
# not setting the type here! # FIXME: not setting the type here to keep it working with
# complex numbers. Should they be special cased?
node = IntNode(self.pos, value=self.value, constant_result=self.constant_result, node = IntNode(self.pos, value=self.value, constant_result=self.constant_result,
unsigned=self.unsigned, longness=self.longness) unsigned=self.unsigned, longness=self.longness)
# We still need to perform normal coerce_to processing on the # We still need to perform normal coerce_to processing on the
...@@ -1495,7 +1501,6 @@ class NameNode(AtomicExprNode): ...@@ -1495,7 +1501,6 @@ class NameNode(AtomicExprNode):
namespace = Naming.builtins_cname namespace = Naming.builtins_cname
else: # entry.is_pyglobal else: # entry.is_pyglobal
namespace = entry.scope.namespace_cname namespace = entry.scope.namespace_cname
code.globalstate.use_utility_code(getitem_dict_utility_code)
code.putln( code.putln(
'%s = PyObject_GetItem(%s, %s); %s' % ( '%s = PyObject_GetItem(%s, %s); %s' % (
self.result(), self.result(),
...@@ -3927,10 +3932,16 @@ class TupleNode(SequenceNode): ...@@ -3927,10 +3932,16 @@ class TupleNode(SequenceNode):
self.is_literal = 1 self.is_literal = 1
else: else:
SequenceNode.analyse_types(self, env, skip_children) SequenceNode.analyse_types(self, env, skip_children)
for child in self.args:
if not child.is_literal:
break
else:
self.is_temp = 0
self.is_literal = 1
def calculate_result_code(self): def calculate_result_code(self):
if len(self.args) > 0: if len(self.args) > 0:
error(self.pos, "Positive length tuples must be constructed.") return self.result_code
else: else:
return Naming.empty_tuple return Naming.empty_tuple
...@@ -3949,6 +3960,13 @@ class TupleNode(SequenceNode): ...@@ -3949,6 +3960,13 @@ class TupleNode(SequenceNode):
if len(self.args) == 0: if len(self.args) == 0:
# result_code is Naming.empty_tuple # result_code is Naming.empty_tuple
return return
if self.is_literal:
# non-empty cached tuple => result is global constant,
# creation code goes into separate code writer
self.result_code = code.get_py_const(py_object_type, 'tuple_', cleanup_level=2)
code = code.get_cached_constants_writer()
code.mark_pos(self.pos)
code.putln( code.putln(
"%s = PyTuple_New(%s); %s" % ( "%s = PyTuple_New(%s); %s" % (
self.result(), self.result(),
...@@ -3965,6 +3983,8 @@ class TupleNode(SequenceNode): ...@@ -3965,6 +3983,8 @@ class TupleNode(SequenceNode):
i, i,
arg.py_result())) arg.py_result()))
code.put_giveref(arg.py_result()) code.put_giveref(arg.py_result())
if self.is_literal:
code.put_giveref(self.py_result())
def generate_subexpr_disposal_code(self, code): def generate_subexpr_disposal_code(self, code):
# We call generate_post_assignment_code here instead # We call generate_post_assignment_code here instead
...@@ -4135,10 +4155,7 @@ class ComprehensionNode(ScopedExprNode): ...@@ -4135,10 +4155,7 @@ class ComprehensionNode(ScopedExprNode):
def analyse_declarations(self, env): def analyse_declarations(self, env):
self.append.target = self # this is used in the PyList_Append of the inner loop self.append.target = self # this is used in the PyList_Append of the inner loop
self.init_scope(env) self.init_scope(env)
if self.expr_scope is not None: self.loop.analyse_declarations(self.expr_scope or env)
self.loop.analyse_declarations(self.expr_scope)
else:
self.loop.analyse_declarations(env)
def init_scope(self, outer_scope, expr_scope=None): def init_scope(self, outer_scope, expr_scope=None):
if expr_scope is not None: if expr_scope is not None:
...@@ -4523,23 +4540,14 @@ class ClassNode(ExprNode, ModuleNameMixin): ...@@ -4523,23 +4540,14 @@ class ClassNode(ExprNode, ModuleNameMixin):
# dict ExprNode Class dict (not owned by this node) # dict ExprNode Class dict (not owned by this node)
# doc ExprNode or None Doc string # doc ExprNode or None Doc string
# module_name EncodedString Name of defining module # module_name EncodedString Name of defining module
# keyword_args ExprNode or None Py3 Dict of keyword arguments, passed to __new__
# starstar_arg ExprNode or None Py3 Dict of extra keyword args, same here
subexprs = ['bases', 'keyword_args', 'starstar_arg', 'doc'] subexprs = ['bases', 'doc']
def analyse_types(self, env): def analyse_types(self, env):
self.bases.analyse_types(env) self.bases.analyse_types(env)
if self.doc: if self.doc:
self.doc.analyse_types(env) self.doc.analyse_types(env)
self.doc = self.doc.coerce_to_pyobject(env) self.doc = self.doc.coerce_to_pyobject(env)
if self.keyword_args:
self.keyword_args.analyse_types(env)
if self.starstar_arg:
self.starstar_arg.analyse_types(env)
# make sure we have a Python object as **kwargs mapping
self.starstar_arg = \
self.starstar_arg.coerce_to_pyobject(env)
self.type = py_object_type self.type = py_object_type
self.is_temp = 1 self.is_temp = 1
env.use_utility_code(create_class_utility_code); env.use_utility_code(create_class_utility_code);
...@@ -4553,18 +4561,6 @@ class ClassNode(ExprNode, ModuleNameMixin): ...@@ -4553,18 +4561,6 @@ class ClassNode(ExprNode, ModuleNameMixin):
def generate_result_code(self, code): def generate_result_code(self, code):
cname = code.intern_identifier(self.name) cname = code.intern_identifier(self.name)
if self.keyword_args and self.starstar_arg:
code.put_error_if_neg(self.pos,
"PyDict_Update(%s, %s)" % (
self.keyword_args.py_result(),
self.starstar_arg.py_result()))
keyword_code = self.keyword_args.py_result()
elif self.keyword_args:
keyword_code = self.keyword_args.py_result()
elif self.starstar_arg:
keyword_code = self.starstar_arg.py_result()
else:
keyword_code = 'NULL'
if self.doc: if self.doc:
code.put_error_if_neg(self.pos, code.put_error_if_neg(self.pos,
...@@ -4573,17 +4569,161 @@ class ClassNode(ExprNode, ModuleNameMixin): ...@@ -4573,17 +4569,161 @@ class ClassNode(ExprNode, ModuleNameMixin):
self.doc.py_result())) self.doc.py_result()))
py_mod_name = self.get_py_mod_name(code) py_mod_name = self.get_py_mod_name(code)
code.putln( code.putln(
'%s = __Pyx_CreateClass(%s, %s, %s, %s, %s); %s' % ( '%s = __Pyx_CreateClass(%s, %s, %s, %s); %s' % (
self.result(), self.result(),
self.bases.py_result(), self.bases.py_result(),
self.dict.py_result(), self.dict.py_result(),
cname, cname,
py_mod_name, py_mod_name,
keyword_code,
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
class Py3ClassNode(ExprNode):
# Helper class used in the implementation of Python3+
# class definitions. Constructs a class object given
# a name, tuple of bases and class dictionary.
#
# name EncodedString Name of the class
# dict ExprNode Class dict (not owned by this node)
# module_name EncodedString Name of defining module
subexprs = []
def analyse_types(self, env):
self.type = py_object_type
self.is_temp = 1
def may_be_none(self):
return True
gil_message = "Constructing Python class"
def generate_result_code(self, code):
code.globalstate.use_utility_code(create_py3class_utility_code)
cname = code.intern_identifier(self.name)
code.putln(
'%s = __Pyx_Py3ClassCreate(%s, %s, %s, %s, %s); %s' % (
self.result(),
self.metaclass.result(),
cname,
self.bases.py_result(),
self.dict.py_result(),
self.mkw.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class KeywordArgsNode(ExprNode):
# Helper class for keyword arguments
#
# keyword_args ExprNode or None Keyword arguments
# starstar_arg ExprNode or None Extra arguments
subexprs = ['keyword_args', 'starstar_arg']
def analyse_types(self, env):
if self.keyword_args:
self.keyword_args.analyse_types(env)
if self.starstar_arg:
self.starstar_arg.analyse_types(env)
# make sure we have a Python object as **kwargs mapping
self.starstar_arg = \
self.starstar_arg.coerce_to_pyobject(env)
self.type = py_object_type
self.is_temp = 1
gil_message = "Constructing Keyword Args"
def generate_result_code(self, code):
if self.keyword_args and self.starstar_arg:
code.put_error_if_neg(self.pos,
"PyDict_Update(%s, %s)" % (
self.keyword_args.py_result(),
self.starstar_arg.py_result()))
if self.keyword_args:
code.putln("%s = %s;" % (self.result(), self.keyword_args.result()))
code.put_incref(self.keyword_args.result(), self.keyword_args.ctype())
elif self.starstar_arg:
code.putln(
"%s = PyDict_Copy(%s); %s" % (
self.result(),
self.starstar_arg.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
else:
code.putln(
"%s = PyDict_New(); %s" % (
self.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class PyClassMetaclassNode(ExprNode):
# Helper class holds Python3 metaclass object
#
# bases ExprNode Base class tuple (not owned by this node)
# mkw ExprNode Class keyword arguments (not owned by this node)
subexprs = []
def analyse_types(self, env):
self.type = py_object_type
self.is_temp = True
def may_be_none(self):
return True
def generate_result_code(self, code):
code.putln(
"%s = __Pyx_Py3MetaclassGet(%s, %s); %s" % (
self.result(),
self.bases.result(),
self.mkw.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class PyClassNamespaceNode(ExprNode, ModuleNameMixin):
# Helper class holds Python3 namespace object
#
# All this are not owned by this node
# metaclass ExprNode Metaclass object
# bases ExprNode Base class tuple
# mkw ExprNode Class keyword arguments
# doc ExprNode or None Doc string (owned)
subexprs = ['doc']
def analyse_types(self, env):
self.bases.analyse_types(env)
if self.doc:
self.doc.analyse_types(env)
self.doc = self.doc.coerce_to_pyobject(env)
self.type = py_object_type
self.is_temp = 1
#TODO(craig,haoyu) This should be moved to a better place
self.set_mod_name(env)
def may_be_none(self):
return True
def generate_result_code(self, code):
cname = code.intern_identifier(self.name)
py_mod_name = self.get_py_mod_name(code)
if self.doc:
doc_code = self.doc.result()
else:
doc_code = '(PyObject *) NULL'
code.putln(
"%s = __Pyx_Py3MetaclassPrepare(%s, %s, %s, %s, %s, %s); %s" % (
self.result(),
self.metaclass.result(),
self.bases.result(),
cname,
self.mkw.result(),
py_mod_name,
doc_code,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class BoundMethodNode(ExprNode): class BoundMethodNode(ExprNode):
# Helper class used in the implementation of Python # Helper class used in the implementation of Python
# class definitions. Constructs an bound method # class definitions. Constructs an bound method
...@@ -5359,6 +5499,9 @@ class BinopNode(ExprNode): ...@@ -5359,6 +5499,9 @@ class BinopNode(ExprNode):
def analyse_types(self, env): def analyse_types(self, env):
self.operand1.analyse_types(env) self.operand1.analyse_types(env)
self.operand2.analyse_types(env) self.operand2.analyse_types(env)
self.analyse_operation(env)
def analyse_operation(self, env):
if self.is_py_operation(): if self.is_py_operation():
self.coerce_operands_to_pyobjects(env) self.coerce_operands_to_pyobjects(env)
self.type = self.result_type(self.operand1.type, self.type = self.result_type(self.operand1.type,
...@@ -5653,12 +5796,12 @@ class DivNode(NumBinopNode): ...@@ -5653,12 +5796,12 @@ class DivNode(NumBinopNode):
except Exception, e: except Exception, e:
self.compile_time_value_error(e) self.compile_time_value_error(e)
def analyse_types(self, env): def analyse_operation(self, env):
if self.cdivision or env.directives['cdivision']: if self.cdivision or env.directives['cdivision']:
self.ctruedivision = False self.ctruedivision = False
else: else:
self.ctruedivision = self.truedivision self.ctruedivision = self.truedivision
NumBinopNode.analyse_types(self, env) NumBinopNode.analyse_operation(self, env)
if self.is_cpp_operation(): if self.is_cpp_operation():
self.cdivision = True self.cdivision = True
if not self.type.is_pyobject: if not self.type.is_pyobject:
...@@ -7296,120 +7439,176 @@ static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { ...@@ -7296,120 +7439,176 @@ static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
find_py2_metaclass_utility_code = UtilityCode(
proto = '''
static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases); /*proto*/
''',
impl = '''
static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases) {
PyObject *metaclass;
/* Default metaclass */
#if PY_MAJOR_VERSION < 3
if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
PyObject *base = PyTuple_GET_ITEM(bases, 0);
metaclass = PyObject_GetAttrString(base, "__class__");
if (!metaclass) {
PyErr_Clear();
metaclass = (PyObject*) Py_TYPE(base);
}
} else {
metaclass = (PyObject *) &PyClass_Type;
}
#else
if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
PyObject *base = PyTuple_GET_ITEM(bases, 0);
metaclass = (PyObject*) Py_TYPE(base);
} else {
metaclass = (PyObject *) &PyType_Type;
}
#endif
Py_INCREF(metaclass);
return metaclass;
}
''')
create_class_utility_code = UtilityCode( create_class_utility_code = UtilityCode(
proto = """ proto = """
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
PyObject *modname, PyObject *kwargs); /*proto*/ PyObject *modname); /*proto*/
static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *name, """,
PyObject *mkw, PyObject *dict); /*proto*/ impl = """
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
PyObject *modname) {
PyObject *result;
PyObject *metaclass;
if (PyDict_SetItemString(dict, "__module__", modname) < 0)
return NULL;
/* Python2 __metaclass__ */
metaclass = PyDict_GetItemString(dict, "__metaclass__");
if (metaclass) {
Py_INCREF(metaclass);
} else {
metaclass = __Pyx_FindPy2Metaclass(bases);
}
result = PyObject_CallFunctionObjArgs(metaclass, name, bases, dict, NULL);
Py_DECREF(metaclass);
return result;
}
""",
requires = [find_py2_metaclass_utility_code])
#------------------------------------------------------------------------------------
create_py3class_utility_code = UtilityCode(
proto = """
static PyObject *__Pyx_Py3MetaclassGet(PyObject *bases, PyObject *mkw); /*proto*/
static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *mkw, PyObject *modname, PyObject *doc); /*proto*/
static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, PyObject *mkw); /*proto*/
""", """,
impl = """ impl = """
static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *__Pyx_Py3MetaclassGet(PyObject *bases, PyObject *mkw) {
PyObject *mkw, PyObject *dict) { PyObject *metaclass = PyDict_GetItemString(mkw, "metaclass");
if (metaclass) {
Py_INCREF(metaclass);
if (PyDict_DelItemString(mkw, "metaclass") < 0) {
Py_DECREF(metaclass);
return NULL;
}
return metaclass;
}
return __Pyx_FindPy2Metaclass(bases);
}
PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *mkw,
PyObject *modname, PyObject *doc) {
PyObject *prep; PyObject *prep;
PyObject *pargs; PyObject *pargs;
PyObject *ns; PyObject *ns;
PyObject *str;
prep = PyObject_GetAttrString(metaclass, "__prepare__"); prep = PyObject_GetAttrString(metaclass, "__prepare__");
if (prep == NULL) { if (!prep) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1; return NULL;
PyErr_Clear(); PyErr_Clear();
return 0; return PyDict_New();
} }
pargs = PyTuple_New(2); pargs = PyTuple_New(2);
if (!pargs) { if (!pargs) {
Py_DECREF(prep); Py_DECREF(prep);
return -1; return NULL;
} }
Py_INCREF(name); Py_INCREF(name);
Py_INCREF(bases); Py_INCREF(bases);
PyTuple_SET_ITEM(pargs, 0, name); PyTuple_SET_ITEM(pargs, 0, name);
PyTuple_SET_ITEM(pargs, 1, bases); PyTuple_SET_ITEM(pargs, 1, bases);
ns = PyEval_CallObjectWithKeywords(prep, pargs, mkw);
Py_DECREF(pargs); ns = PyObject_Call(prep, pargs, mkw);
Py_DECREF(prep); Py_DECREF(prep);
Py_DECREF(pargs);
if (ns == NULL) if (ns == NULL)
return -1; return NULL;
/* XXX: This is hack, merge namespace back to dict,
__prepare__ should be ran before dict initialization */ /* Required here to emulate assignment order */
if (PyDict_Merge(dict, ns, 0)) { /* XXX: use consts here */
#if PY_MAJOR_VERSION >= 3
str = PyUnicode_FromString("__module__");
#else
str = PyString_FromString("__module__");
#endif
if (!str) {
Py_DECREF(ns); Py_DECREF(ns);
return -1; return NULL;
} }
Py_DECREF(ns);
return 0;
}
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
PyObject *modname, PyObject *kwargs) {
PyObject *result = NULL;
PyObject *metaclass = NULL;
PyObject *mkw = NULL;
if (PyDict_SetItemString(dict, "__module__", modname) < 0) if (PyObject_SetItem(ns, str, modname) < 0) {
Py_DECREF(ns);
Py_DECREF(str);
return NULL; return NULL;
}
/* Python3 metaclasses */ Py_DECREF(str);
if (kwargs) { if (doc) {
mkw = PyDict_Copy(kwargs); /* Don't modify kwargs passed in! */ #if PY_MAJOR_VERSION >= 3
if (!mkw) str = PyUnicode_FromString("__doc__");
#else
str = PyString_FromString("__doc__");
#endif
if (!str) {
Py_DECREF(ns);
return NULL; return NULL;
metaclass = PyDict_GetItemString(mkw, "metaclass");
if (metaclass) {
Py_INCREF(metaclass);
if (PyDict_DelItemString(mkw, "metaclass") < 0)
goto bad;
if (__Pyx_PrepareClass(metaclass, bases, name, mkw, dict))
goto bad;
} }
} if (PyObject_SetItem(ns, str, doc) < 0) {
if (!metaclass) { Py_DECREF(ns);
/* Python2 __metaclass__ */ Py_DECREF(str);
metaclass = PyDict_GetItemString(dict, "__metaclass__"); return NULL;
if (!metaclass) {
/* Default metaclass */
#if PY_MAJOR_VERSION < 3
if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
PyObject *base = PyTuple_GET_ITEM(bases, 0);
metaclass = PyObject_GetAttrString(base, "__class__");
if (!metaclass) {
PyErr_Clear();
metaclass = (PyObject *)base->ob_type;
}
} else
metaclass = (PyObject *) &PyClass_Type;
#else
if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
PyObject *base = PyTuple_GET_ITEM(bases, 0);
metaclass = (PyObject *)base->ob_type;
} else
metaclass = (PyObject *) &PyType_Type;
#endif
} }
Py_INCREF(metaclass); Py_DECREF(str);
} }
if (mkw && PyDict_Size(mkw) > 0) { return ns;
PyObject *margs = PyTuple_New(3); }
if (!margs)
goto bad; PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, PyObject *mkw) {
Py_INCREF(name); PyObject *result;
Py_INCREF(bases); PyObject *margs = PyTuple_New(3);
Py_INCREF(dict); if (!margs)
PyTuple_SET_ITEM(margs, 0, name); return NULL;
PyTuple_SET_ITEM(margs, 1, bases); Py_INCREF(name);
PyTuple_SET_ITEM(margs, 2, dict); Py_INCREF(bases);
result = PyEval_CallObjectWithKeywords(metaclass, margs, mkw); Py_INCREF(dict);
Py_DECREF(margs); PyTuple_SET_ITEM(margs, 0, name);
} else { PyTuple_SET_ITEM(margs, 1, bases);
result = PyObject_CallFunctionObjArgs(metaclass, name, bases, dict, NULL); PyTuple_SET_ITEM(margs, 2, dict);
} result = PyObject_Call(metaclass, margs, mkw);
bad: Py_DECREF(margs);
Py_DECREF(metaclass);
Py_XDECREF(mkw);
return result; return result;
} }
""") """,
requires = [find_py2_metaclass_utility_code])
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
...@@ -7498,7 +7697,6 @@ static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { ...@@ -7498,7 +7697,6 @@ static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) {
getitem_dict_utility_code = UtilityCode( getitem_dict_utility_code = UtilityCode(
proto = """ proto = """
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
PyObject *value; PyObject *value;
......
...@@ -1768,8 +1768,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1768,8 +1768,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if Options.cache_builtins: if Options.cache_builtins:
code.putln("/*--- Builtin init code ---*/") code.putln("/*--- Builtin init code ---*/")
code.putln(code.error_goto_if_neg("__Pyx_InitCachedBuiltins()", code.putln(code.error_goto_if_neg("__Pyx_InitCachedBuiltins()", self.pos))
self.pos))
code.putln("/*--- Constants init code ---*/")
code.putln(code.error_goto_if_neg("__Pyx_InitCachedConstants()", self.pos))
code.putln("/*--- Global init code ---*/") code.putln("/*--- Global init code ---*/")
self.generate_global_init_code(env, code) self.generate_global_init_code(env, code)
......
...@@ -592,6 +592,7 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -592,6 +592,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
"Exception value must be a Python exception or cdef function with no arguments.") "Exception value must be a Python exception or cdef function with no arguments.")
exc_val = self.exception_value exc_val = self.exception_value
else: else:
self.exception_value = self.exception_value.coerce_to(return_type, env)
if self.exception_value.analyse_const_expression(env): if self.exception_value.analyse_const_expression(env):
exc_val = self.exception_value.get_constant_c_result_code() exc_val = self.exception_value.get_constant_c_result_code()
if exc_val is None: if exc_val is None:
...@@ -1176,7 +1177,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1176,7 +1177,7 @@ class FuncDefNode(StatNode, BlockNode):
def create_local_scope(self, env): def create_local_scope(self, env):
genv = env genv = env
while genv.is_py_class_scope or genv.is_c_class_scope: while genv.is_py_class_scope or genv.is_c_class_scope:
genv = env.outer_scope genv = genv.outer_scope
if self.needs_closure: if self.needs_closure:
lenv = ClosureScope(name=self.entry.name, lenv = ClosureScope(name=self.entry.name,
outer_scope = genv, outer_scope = genv,
...@@ -1254,11 +1255,15 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1254,11 +1255,15 @@ class FuncDefNode(StatNode, BlockNode):
self.generate_function_header(code, self.generate_function_header(code,
with_pymethdef = with_pymethdef) with_pymethdef = with_pymethdef)
# ----- Local variable declarations # ----- Local variable declarations
# Find function scope
cenv = env
while cenv.is_py_class_scope or cenv.is_c_class_scope:
cenv = cenv.outer_scope
if lenv.is_closure_scope: if lenv.is_closure_scope:
code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname)) code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
code.putln(";") code.putln(";")
elif env.is_closure_scope: elif cenv.is_closure_scope:
code.put(env.scope_class.type.declaration_code(Naming.outer_scope_cname)) code.put(cenv.scope_class.type.declaration_code(Naming.outer_scope_cname))
code.putln(";") code.putln(";")
self.generate_argument_declarations(lenv, code) self.generate_argument_declarations(lenv, code)
for entry in lenv.var_entries: for entry in lenv.var_entries:
...@@ -1309,14 +1314,14 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1309,14 +1314,14 @@ class FuncDefNode(StatNode, BlockNode):
code.putln("}") code.putln("}")
code.put_gotref(Naming.cur_scope_cname) code.put_gotref(Naming.cur_scope_cname)
# Note that it is unsafe to decref the scope at this point. # Note that it is unsafe to decref the scope at this point.
if env.is_closure_scope: if cenv.is_closure_scope:
code.putln("%s = (%s)%s;" % ( code.putln("%s = (%s)%s;" % (
outer_scope_cname, outer_scope_cname,
env.scope_class.type.declaration_code(''), cenv.scope_class.type.declaration_code(''),
Naming.self_cname)) Naming.self_cname))
if self.needs_closure: if self.needs_closure:
# inner closures own a reference to their outer parent # inner closures own a reference to their outer parent
code.put_incref(outer_scope_cname, env.scope_class.type) code.put_incref(outer_scope_cname, cenv.scope_class.type)
code.put_giveref(outer_scope_cname) code.put_giveref(outer_scope_cname)
# ----- Trace function call # ----- Trace function call
if profile: if profile:
...@@ -2136,7 +2141,7 @@ class DefNode(FuncDefNode): ...@@ -2136,7 +2141,7 @@ class DefNode(FuncDefNode):
entry.doc_cname = \ entry.doc_cname = \
Naming.funcdoc_prefix + prefix + name Naming.funcdoc_prefix + prefix + name
if entry.is_special: if entry.is_special:
if entry.name in TypeSlots.invisible or not entry.doc: if entry.name in TypeSlots.invisible or not entry.doc or (entry.name in '__getattr__' and env.directives['fast_getattr']):
entry.wrapperbase_cname = None entry.wrapperbase_cname = None
else: else:
entry.wrapperbase_cname = Naming.wrapperbase_prefix + prefix + name entry.wrapperbase_cname = Naming.wrapperbase_prefix + prefix + name
...@@ -2210,18 +2215,21 @@ class DefNode(FuncDefNode): ...@@ -2210,18 +2215,21 @@ class DefNode(FuncDefNode):
def synthesize_assignment_node(self, env): def synthesize_assignment_node(self, env):
import ExprNodes import ExprNodes
if env.is_py_class_scope: genv = env
rhs = ExprNodes.PyCFunctionNode(self.pos, while genv.is_py_class_scope or genv.is_c_class_scope:
pymethdef_cname = self.entry.pymethdef_cname) genv = genv.outer_scope
if not self.is_staticmethod and not self.is_classmethod:
rhs.binding = True
elif env.is_closure_scope: if genv.is_closure_scope:
rhs = ExprNodes.InnerFunctionNode( rhs = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname) self.pos, pymethdef_cname = self.entry.pymethdef_cname)
else: else:
rhs = ExprNodes.PyCFunctionNode( rhs = ExprNodes.PyCFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname, binding = env.directives['binding']) self.pos, pymethdef_cname = self.entry.pymethdef_cname, binding = env.directives['binding'])
if env.is_py_class_scope:
if not self.is_staticmethod and not self.is_classmethod:
rhs.binding = True
self.assmt = SingleAssignmentNode(self.pos, self.assmt = SingleAssignmentNode(self.pos,
lhs = ExprNodes.NameNode(self.pos, name = self.name), lhs = ExprNodes.NameNode(self.pos, name = self.name),
rhs = rhs) rhs = rhs)
...@@ -2933,12 +2941,13 @@ class PyClassDefNode(ClassDefNode): ...@@ -2933,12 +2941,13 @@ class PyClassDefNode(ClassDefNode):
# #
# The following subnodes are constructed internally: # The following subnodes are constructed internally:
# #
# dict DictNode Class dictionary # dict DictNode Class dictionary or Py3 namespace
# classobj ClassNode Class object # classobj ClassNode Class object
# target NameNode Variable to assign class object to # target NameNode Variable to assign class object to
child_attrs = ["body", "dict", "classobj", "target"] child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "classobj", "target"]
decorators = None decorators = None
py3_style_class = False # Python3 style class (bases+kwargs)
def __init__(self, pos, name, bases, doc, body, decorators = None, def __init__(self, pos, name, bases, doc, body, decorators = None,
keyword_args = None, starstar_arg = None): keyword_args = None, starstar_arg = None):
...@@ -2948,22 +2957,55 @@ class PyClassDefNode(ClassDefNode): ...@@ -2948,22 +2957,55 @@ class PyClassDefNode(ClassDefNode):
self.body = body self.body = body
self.decorators = decorators self.decorators = decorators
import ExprNodes import ExprNodes
self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
if self.doc and Options.docstrings: if self.doc and Options.docstrings:
doc = embed_position(self.pos, self.doc) doc = embed_position(self.pos, self.doc)
# FIXME: correct string node?
doc_node = ExprNodes.StringNode(pos, value = doc) doc_node = ExprNodes.StringNode(pos, value = doc)
else: else:
doc_node = None doc_node = None
self.classobj = ExprNodes.ClassNode(pos, name = name, if keyword_args or starstar_arg:
bases = bases, dict = self.dict, doc = doc_node, self.py3_style_class = True
keyword_args = keyword_args, starstar_arg = starstar_arg) self.bases = bases
self.metaclass = None
if keyword_args and not starstar_arg:
for i, item in list(enumerate(keyword_args.key_value_pairs))[::-1]:
if item.key.value == 'metaclass':
if self.metaclass is not None:
error(item.pos, "keyword argument 'metaclass' passed multiple times")
# special case: we already know the metaclass,
# so we don't need to do the "build kwargs,
# find metaclass" dance at runtime
self.metaclass = item.value
del keyword_args.key_value_pairs[i]
if starstar_arg or (keyword_args and keyword_args.key_value_pairs):
self.mkw = ExprNodes.KeywordArgsNode(
pos, keyword_args = keyword_args, starstar_arg = starstar_arg)
else:
self.mkw = ExprNodes.NullNode(pos)
if self.metaclass is None:
self.metaclass = ExprNodes.PyClassMetaclassNode(
pos, mkw = self.mkw, bases = self.bases)
self.dict = ExprNodes.PyClassNamespaceNode(pos, name = name,
doc = doc_node, metaclass = self.metaclass, bases = self.bases,
mkw = self.mkw)
self.classobj = ExprNodes.Py3ClassNode(pos, name = name,
bases = self.bases, dict = self.dict, doc = doc_node,
metaclass = self.metaclass, mkw = self.mkw)
else:
self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
self.metaclass = None
self.mkw = None
self.bases = None
self.classobj = ExprNodes.ClassNode(pos, name = name,
bases = bases, dict = self.dict, doc = doc_node)
self.target = ExprNodes.NameNode(pos, name = name) self.target = ExprNodes.NameNode(pos, name = name)
def as_cclass(self): def as_cclass(self):
""" """
Return this node as if it were declared as an extension class Return this node as if it were declared as an extension class
""" """
if self.py3_style_class:
error(self.classobj.pos, "Python3 style class could not be represented as C class")
return
bases = self.classobj.bases.args bases = self.classobj.bases.args
if len(bases) == 0: if len(bases) == 0:
base_class_name = None base_class_name = None
...@@ -3001,8 +3043,8 @@ class PyClassDefNode(ClassDefNode): ...@@ -3001,8 +3043,8 @@ class PyClassDefNode(ClassDefNode):
def create_scope(self, env): def create_scope(self, env):
genv = env genv = env
while env.is_py_class_scope or env.is_c_class_scope: while genv.is_py_class_scope or genv.is_c_class_scope:
env = env.outer_scope genv = genv.outer_scope
cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv) cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv)
return cenv return cenv
...@@ -3014,6 +3056,10 @@ class PyClassDefNode(ClassDefNode): ...@@ -3014,6 +3056,10 @@ class PyClassDefNode(ClassDefNode):
self.body.analyse_declarations(cenv) self.body.analyse_declarations(cenv)
def analyse_expressions(self, env): def analyse_expressions(self, env):
if self.py3_style_class:
self.bases.analyse_expressions(env)
self.metaclass.analyse_expressions(env)
self.mkw.analyse_expressions(env)
self.dict.analyse_expressions(env) self.dict.analyse_expressions(env)
self.classobj.analyse_expressions(env) self.classobj.analyse_expressions(env)
genv = env.global_scope() genv = env.global_scope()
...@@ -3027,6 +3073,10 @@ class PyClassDefNode(ClassDefNode): ...@@ -3027,6 +3073,10 @@ class PyClassDefNode(ClassDefNode):
def generate_execution_code(self, code): def generate_execution_code(self, code):
code.pyclass_stack.append(self) code.pyclass_stack.append(self)
cenv = self.scope cenv = self.scope
if self.py3_style_class:
self.bases.generate_evaluation_code(code)
self.mkw.generate_evaluation_code(code)
self.metaclass.generate_evaluation_code(code)
self.dict.generate_evaluation_code(code) self.dict.generate_evaluation_code(code)
cenv.namespace_cname = cenv.class_obj_cname = self.dict.result() cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
...@@ -3035,9 +3085,15 @@ class PyClassDefNode(ClassDefNode): ...@@ -3035,9 +3085,15 @@ class PyClassDefNode(ClassDefNode):
self.target.generate_assignment_code(self.classobj, code) self.target.generate_assignment_code(self.classobj, code)
self.dict.generate_disposal_code(code) self.dict.generate_disposal_code(code)
self.dict.free_temps(code) self.dict.free_temps(code)
if self.py3_style_class:
self.mkw.generate_disposal_code(code)
self.mkw.free_temps(code)
self.metaclass.generate_disposal_code(code)
self.metaclass.free_temps(code)
self.bases.generate_disposal_code(code)
self.bases.free_temps(code)
code.pyclass_stack.pop() code.pyclass_stack.pop()
class CClassDefNode(ClassDefNode): class CClassDefNode(ClassDefNode):
# An extension type definition. # An extension type definition.
# #
...@@ -4034,7 +4090,6 @@ class IfClauseNode(Node): ...@@ -4034,7 +4090,6 @@ class IfClauseNode(Node):
self.body.analyse_control_flow(env) self.body.analyse_control_flow(env)
def analyse_declarations(self, env): def analyse_declarations(self, env):
self.condition.analyse_declarations(env)
self.body.analyse_declarations(env) self.body.analyse_declarations(env)
def analyse_expressions(self, env): def analyse_expressions(self, env):
...@@ -4104,6 +4159,7 @@ class SwitchStatNode(StatNode): ...@@ -4104,6 +4159,7 @@ class SwitchStatNode(StatNode):
child_attrs = ['test', 'cases', 'else_clause'] child_attrs = ['test', 'cases', 'else_clause']
def generate_execution_code(self, code): def generate_execution_code(self, code):
self.test.generate_evaluation_code(code)
code.putln("switch (%s) {" % self.test.result()) code.putln("switch (%s) {" % self.test.result())
for case in self.cases: for case in self.cases:
case.generate_execution_code(code) case.generate_execution_code(code)
......
...@@ -702,28 +702,25 @@ class SwitchTransform(Visitor.VisitorTransform): ...@@ -702,28 +702,25 @@ class SwitchTransform(Visitor.VisitorTransform):
break break
if isinstance(cond, ExprNodes.PrimaryCmpNode): if isinstance(cond, ExprNodes.PrimaryCmpNode):
if cond.cascade is None and not cond.is_python_comparison(): if cond.cascade is not None:
return self.NO_MATCH
elif cond.is_c_string_contains() and \
isinstance(cond.operand2, (ExprNodes.UnicodeNode, ExprNodes.BytesNode)):
not_in = cond.operator == 'not_in'
if not_in and not allow_not_in:
return self.NO_MATCH
if isinstance(cond.operand2, ExprNodes.UnicodeNode) and \
cond.operand2.contains_surrogates():
# dealing with surrogates leads to different
# behaviour on wide and narrow Unicode
# platforms => refuse to optimise this case
return self.NO_MATCH
return not_in, cond.operand1, self.extract_in_string_conditions(cond.operand2)
elif not cond.is_python_comparison():
if cond.operator == '==': if cond.operator == '==':
not_in = False not_in = False
elif allow_not_in and cond.operator == '!=': elif allow_not_in and cond.operator == '!=':
not_in = True not_in = True
elif cond.is_c_string_contains() and \
isinstance(cond.operand2, (ExprNodes.UnicodeNode, ExprNodes.BytesNode)):
not_in = cond.operator == 'not_in'
if not_in and not allow_not_in:
return self.NO_MATCH
if isinstance(cond.operand2, ExprNodes.UnicodeNode) and \
cond.operand2.contains_surrogates():
# dealing with surrogates leads to different
# behaviour on wide and narrow Unicode
# platforms => refuse to optimise this case
return self.NO_MATCH
# this looks somewhat silly, but it does the right
# checks for NameNode and AttributeNode
if is_common_value(cond.operand1, cond.operand1):
return not_in, cond.operand1, self.extract_in_string_conditions(cond.operand2)
else:
return self.NO_MATCH
else: else:
return self.NO_MATCH return self.NO_MATCH
# this looks somewhat silly, but it does the right # this looks somewhat silly, but it does the right
......
...@@ -71,6 +71,7 @@ directive_defaults = { ...@@ -71,6 +71,7 @@ directive_defaults = {
'autotestdict.cdef': False, 'autotestdict.cdef': False,
'autotestdict.all': False, 'autotestdict.all': False,
'language_level': 2, 'language_level': 2,
'fast_getattr': False, # Undocumented until we come up with a better way to handle this everywhere.
'warn': None, 'warn': None,
'warn.undeclared': False, 'warn.undeclared': False,
...@@ -101,8 +102,8 @@ directive_scopes = { # defaults to available everywhere ...@@ -101,8 +102,8 @@ directive_scopes = { # defaults to available everywhere
'autotestdict' : ('module',), 'autotestdict' : ('module',),
'autotestdict.all' : ('module',), 'autotestdict.all' : ('module',),
'autotestdict.cdef' : ('module',), 'autotestdict.cdef' : ('module',),
'test_assert_path_exists' : ('function',), 'test_assert_path_exists' : ('function', 'class', 'cclass'),
'test_fail_if_path_exists' : ('function',), 'test_fail_if_path_exists' : ('function', 'class', 'cclass'),
} }
def parse_directive_value(name, value, relaxed_bool=False): def parse_directive_value(name, value, relaxed_bool=False):
......
...@@ -787,6 +787,13 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -787,6 +787,13 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
body = StatListNode(node.pos, stats=[node]) body = StatListNode(node.pos, stats=[node])
return self.visit_with_directives(body, directives) return self.visit_with_directives(body, directives)
def visit_PyClassDefNode(self, node):
directives = self._extract_directives(node, 'class')
if not directives:
return self.visit_Node(node)
body = StatListNode(node.pos, stats=[node])
return self.visit_with_directives(body, directives)
def _extract_directives(self, node, scope_name): def _extract_directives(self, node, scope_name):
if not node.decorators: if not node.decorators:
return {} return {}
...@@ -1060,21 +1067,17 @@ property NAME: ...@@ -1060,21 +1067,17 @@ property NAME:
self.seen_vars_stack.pop() self.seen_vars_stack.pop()
return node return node
def visit_ComprehensionNode(self, node):
self.visitchildren(node)
node.analyse_declarations(self.env_stack[-1])
return node
def visit_ScopedExprNode(self, node): def visit_ScopedExprNode(self, node):
node.analyse_declarations(self.env_stack[-1]) node.analyse_declarations(self.env_stack[-1])
if self.seen_vars_stack: # the node may or may not have a local scope
if node.expr_scope:
self.seen_vars_stack.append(set(self.seen_vars_stack[-1])) self.seen_vars_stack.append(set(self.seen_vars_stack[-1]))
self.env_stack.append(node.expr_scope)
self.visitchildren(node)
self.env_stack.pop()
self.seen_vars_stack.pop()
else: else:
self.seen_vars_stack.append(set()) self.visitchildren(node)
self.env_stack.append(node.expr_scope)
self.visitchildren(node)
self.env_stack.pop()
self.seen_vars_stack.pop()
return node return node
def visit_TempResultFromStatNode(self, node): def visit_TempResultFromStatNode(self, node):
...@@ -1187,6 +1190,7 @@ class ExpandInplaceOperators(EnvTransform): ...@@ -1187,6 +1190,7 @@ class ExpandInplaceOperators(EnvTransform):
# There is code to handle this case. # There is code to handle this case.
return node return node
env = self.current_env()
def side_effect_free_reference(node, setting=False): def side_effect_free_reference(node, setting=False):
if isinstance(node, NameNode): if isinstance(node, NameNode):
return node, [] return node, []
...@@ -1215,12 +1219,18 @@ class ExpandInplaceOperators(EnvTransform): ...@@ -1215,12 +1219,18 @@ class ExpandInplaceOperators(EnvTransform):
operand1 = dup, operand1 = dup,
operand2 = rhs, operand2 = rhs,
inplace=True) inplace=True)
node = SingleAssignmentNode(node.pos, lhs=lhs, rhs=binop) # Manually analyse types for new node.
lhs.analyse_target_types(env)
dup.analyse_types(env)
binop.analyse_operation(env)
node = SingleAssignmentNode(
node.pos,
lhs = lhs,
rhs=binop.coerce_to(lhs.type, env))
# Use LetRefNode to avoid side effects. # Use LetRefNode to avoid side effects.
let_ref_nodes.reverse() let_ref_nodes.reverse()
for t in let_ref_nodes: for t in let_ref_nodes:
node = LetNode(t, node) node = LetNode(t, node)
node.analyse_expressions(self.current_env())
return node return node
def visit_ExprNode(self, node): def visit_ExprNode(self, node):
...@@ -1318,7 +1328,7 @@ class CreateClosureClasses(CythonTransform): ...@@ -1318,7 +1328,7 @@ class CreateClosureClasses(CythonTransform):
return node return node
def create_class_from_scope(self, node, target_module_scope): def create_class_from_scope(self, node, target_module_scope):
as_name = "%s%s" % (Naming.closure_class_prefix, node.entry.cname) as_name = '%s_%s' % (target_module_scope.next_id(Naming.closure_class_prefix), node.entry.cname)
func_scope = node.local_scope func_scope = node.local_scope
entry = target_module_scope.declare_c_class(name = as_name, entry = target_module_scope.declare_c_class(name = as_name,
...@@ -1327,11 +1337,15 @@ class CreateClosureClasses(CythonTransform): ...@@ -1327,11 +1337,15 @@ class CreateClosureClasses(CythonTransform):
class_scope = entry.type.scope class_scope = entry.type.scope
class_scope.is_internal = True class_scope.is_internal = True
class_scope.directives = {'final': True} class_scope.directives = {'final': True}
if node.entry.scope.is_closure_scope:
cscope = node.entry.scope
while cscope.is_py_class_scope or cscope.is_c_class_scope:
cscope = cscope.outer_scope
if cscope.is_closure_scope:
class_scope.declare_var(pos=node.pos, class_scope.declare_var(pos=node.pos,
name=Naming.outer_scope_cname, # this could conflict? name=Naming.outer_scope_cname, # this could conflict?
cname=Naming.outer_scope_cname, cname=Naming.outer_scope_cname,
type=node.entry.scope.scope_class.type, type=cscope.scope_class.type,
is_cdef=True) is_cdef=True)
entries = func_scope.entries.items() entries = func_scope.entries.items()
entries.sort() entries.sort()
......
# We declare all of these here to type the first argument. # We declare all of these here to type the first argument.
cimport cython
from Cython.Compiler.Scanning cimport PyrexScanner from Cython.Compiler.Scanning cimport PyrexScanner
# entry points
cpdef p_ident(PyrexScanner s, message =*) cpdef p_module(PyrexScanner s, pxd, full_module_name)
cpdef p_ident_list(PyrexScanner s) cpdef p_code(PyrexScanner s, level= *)
# internal parser states
cpdef p_binop_operator(PyrexScanner s) cdef p_ident(PyrexScanner s, message =*)
cpdef p_binop_expr(PyrexScanner s, ops, p_sub_expr) cdef p_ident_list(PyrexScanner s)
cdef p_binop_operator(PyrexScanner s)
cdef p_binop_expr(PyrexScanner s, ops, p_sub_expr)
cpdef p_lambdef(PyrexScanner s, bint allow_conditional=*) cpdef p_lambdef(PyrexScanner s, bint allow_conditional=*)
cpdef p_lambdef_nocond(PyrexScanner s) cdef p_lambdef_nocond(PyrexScanner s)
cpdef p_test(PyrexScanner s) cdef p_test(PyrexScanner s)
cpdef p_test_nocond(PyrexScanner s) cdef p_test_nocond(PyrexScanner s)
cpdef p_or_test(PyrexScanner s) cdef p_or_test(PyrexScanner s)
cpdef p_rassoc_binop_expr(PyrexScanner s, ops, p_subexpr) cdef p_rassoc_binop_expr(PyrexScanner s, ops, p_subexpr)
cpdef p_and_test(PyrexScanner s) cpdef p_and_test(PyrexScanner s)
cpdef p_not_test(PyrexScanner s) cpdef p_not_test(PyrexScanner s)
cpdef p_comparison(PyrexScanner s) cdef p_comparison(PyrexScanner s)
cpdef p_test_or_starred_expr(PyrexScanner s) cdef p_test_or_starred_expr(PyrexScanner s)
cpdef p_starred_expr(PyrexScanner s) cdef p_starred_expr(PyrexScanner s)
cpdef p_cascaded_cmp(PyrexScanner s) cdef p_cascaded_cmp(PyrexScanner s)
cpdef p_cmp_op(PyrexScanner s) cdef p_cmp_op(PyrexScanner s)
cpdef p_bit_expr(PyrexScanner s) cdef p_bit_expr(PyrexScanner s)
cpdef p_xor_expr(PyrexScanner s) cpdef p_xor_expr(PyrexScanner s)
cpdef p_and_expr(PyrexScanner s) cpdef p_and_expr(PyrexScanner s)
cpdef p_shift_expr(PyrexScanner s) cpdef p_shift_expr(PyrexScanner s)
cpdef p_arith_expr(PyrexScanner s) cpdef p_arith_expr(PyrexScanner s)
cpdef p_term(PyrexScanner s) cpdef p_term(PyrexScanner s)
cpdef p_factor(PyrexScanner s) cpdef p_factor(PyrexScanner s)
cpdef p_typecast(PyrexScanner s) cdef p_typecast(PyrexScanner s)
cpdef p_sizeof(PyrexScanner s) cdef p_sizeof(PyrexScanner s)
cpdef p_yield_expression(PyrexScanner s) cdef p_yield_expression(PyrexScanner s)
cpdef p_yield_statement(PyrexScanner s) cdef p_yield_statement(PyrexScanner s)
cpdef p_power(PyrexScanner s) cdef p_power(PyrexScanner s)
cpdef p_new_expr(PyrexScanner s) cdef p_new_expr(PyrexScanner s)
cpdef p_trailer(PyrexScanner s, node1) cdef p_trailer(PyrexScanner s, node1)
cpdef p_call_parse_args(PyrexScanner s, bint allow_genexp = *) cpdef p_call_parse_args(PyrexScanner s, bint allow_genexp = *)
cpdef p_call_build_packed_args(pos, positional_args, keyword_args, star_arg) cdef p_call_build_packed_args(pos, positional_args, keyword_args, star_arg)
cpdef p_call(PyrexScanner s, function) cdef p_call(PyrexScanner s, function)
cpdef p_index(PyrexScanner s, base) cdef p_index(PyrexScanner s, base)
cpdef p_subscript_list(PyrexScanner s) cdef p_subscript_list(PyrexScanner s)
cpdef p_subscript(PyrexScanner s) cdef p_subscript(PyrexScanner s)
cpdef p_slice_element(PyrexScanner s, follow_set) cdef p_slice_element(PyrexScanner s, follow_set)
cpdef expect_ellipsis(PyrexScanner s) cdef expect_ellipsis(PyrexScanner s)
cpdef make_slice_nodes(pos, subscripts) cdef make_slice_nodes(pos, subscripts)
cpdef make_slice_node(pos, start, stop = *, step = *) cpdef make_slice_node(pos, start, stop = *, step = *)
cpdef p_atom(PyrexScanner s) cdef p_atom(PyrexScanner s)
cpdef p_name(PyrexScanner s, name) @cython.locals(value=unicode)
cpdef p_cat_string_literal(PyrexScanner s) cdef p_int_literal(PyrexScanner s)
cpdef p_opt_string_literal(PyrexScanner s, required_type=*) cdef p_name(PyrexScanner s, name)
cpdef bint check_for_non_ascii_characters(unicode string) cdef p_cat_string_literal(PyrexScanner s)
cpdef p_string_literal(PyrexScanner s, kind_override=*) cdef p_opt_string_literal(PyrexScanner s, required_type=*)
cpdef p_list_maker(PyrexScanner s) cdef bint check_for_non_ascii_characters(unicode string)
cpdef p_comp_iter(PyrexScanner s, body) @cython.locals(systr=unicode, is_python3_source=bint)
cpdef p_comp_for(PyrexScanner s, body) cdef p_string_literal(PyrexScanner s, kind_override=*)
cpdef p_comp_if(PyrexScanner s, body) cdef p_list_maker(PyrexScanner s)
cpdef p_dict_or_set_maker(PyrexScanner s) cdef p_comp_iter(PyrexScanner s, body)
cpdef p_backquote_expr(PyrexScanner s) cdef p_comp_for(PyrexScanner s, body)
cdef p_comp_if(PyrexScanner s, body)
cdef p_dict_or_set_maker(PyrexScanner s)
cdef p_backquote_expr(PyrexScanner s)
cpdef p_simple_expr_list(PyrexScanner s, expr=*) cpdef p_simple_expr_list(PyrexScanner s, expr=*)
cpdef p_test_or_starred_expr_list(s, expr=*) cdef p_test_or_starred_expr_list(PyrexScanner s, expr=*)
cpdef p_testlist(PyrexScanner s) cdef p_testlist(PyrexScanner s)
cpdef p_testlist_star_expr(PyrexScanner s) cdef p_testlist_star_expr(PyrexScanner s)
cpdef p_testlist_comp(PyrexScanner s) cdef p_testlist_comp(PyrexScanner s)
cpdef p_genexp(PyrexScanner s, expr) cdef p_genexp(PyrexScanner s, expr)
#------------------------------------------------------- #-------------------------------------------------------
# #
...@@ -70,94 +80,93 @@ cpdef p_genexp(PyrexScanner s, expr) ...@@ -70,94 +80,93 @@ cpdef p_genexp(PyrexScanner s, expr)
# #
#------------------------------------------------------- #-------------------------------------------------------
cpdef p_global_statement(PyrexScanner s) cdef p_global_statement(PyrexScanner s)
cpdef p_expression_or_assignment(PyrexScanner s) cdef p_expression_or_assignment(PyrexScanner s)
cpdef p_print_statement(PyrexScanner s) cdef p_print_statement(PyrexScanner s)
cpdef p_exec_statement(PyrexScanner s) cdef p_exec_statement(PyrexScanner s)
cpdef p_del_statement(PyrexScanner s) cdef p_del_statement(PyrexScanner s)
cpdef p_pass_statement(PyrexScanner s, bint with_newline = *) cpdef p_pass_statement(PyrexScanner s, bint with_newline = *)
cpdef p_break_statement(PyrexScanner s) cdef p_break_statement(PyrexScanner s)
cpdef p_continue_statement(PyrexScanner s) cdef p_continue_statement(PyrexScanner s)
cpdef p_return_statement(PyrexScanner s) cdef p_return_statement(PyrexScanner s)
cpdef p_raise_statement(PyrexScanner s) cdef p_raise_statement(PyrexScanner s)
cpdef p_import_statement(PyrexScanner s) cdef p_import_statement(PyrexScanner s)
cpdef p_from_import_statement(PyrexScanner s, bint first_statement = *) cpdef p_from_import_statement(PyrexScanner s, bint first_statement = *)
cpdef p_imported_name(PyrexScanner s, bint is_cimport) cdef p_imported_name(PyrexScanner s, bint is_cimport)
cpdef p_dotted_name(PyrexScanner s, bint as_allowed) cpdef p_dotted_name(PyrexScanner s, bint as_allowed)
cpdef p_as_name(PyrexScanner s) cdef p_as_name(PyrexScanner s)
cpdef p_assert_statement(PyrexScanner s) cdef p_assert_statement(PyrexScanner s)
cpdef p_if_statement(PyrexScanner s) cdef p_if_statement(PyrexScanner s)
cpdef p_if_clause(PyrexScanner s) cdef p_if_clause(PyrexScanner s)
cpdef p_else_clause(PyrexScanner s) cdef p_else_clause(PyrexScanner s)
cpdef p_while_statement(PyrexScanner s) cdef p_while_statement(PyrexScanner s)
cpdef p_for_statement(PyrexScanner s) cdef p_for_statement(PyrexScanner s)
cpdef p_for_bounds(PyrexScanner s, bint allow_testlist = *) cpdef p_for_bounds(PyrexScanner s, bint allow_testlist = *)
cpdef p_for_from_relation(PyrexScanner s) cdef p_for_from_relation(PyrexScanner s)
cpdef p_for_from_step(PyrexScanner s) cdef p_for_from_step(PyrexScanner s)
cpdef p_target(PyrexScanner s, terminator) cdef p_target(PyrexScanner s, terminator)
cpdef p_for_target(PyrexScanner s) cdef p_for_target(PyrexScanner s)
cpdef p_for_iterator(PyrexScanner s, bint allow_testlist = *) cdef p_for_iterator(PyrexScanner s, bint allow_testlist = *)
cpdef p_try_statement(PyrexScanner s) cdef p_try_statement(PyrexScanner s)
cpdef p_except_clause(PyrexScanner s) cdef p_except_clause(PyrexScanner s)
cpdef p_include_statement(PyrexScanner s, ctx) cdef p_include_statement(PyrexScanner s, ctx)
cpdef p_with_statement(PyrexScanner s) cdef p_with_statement(PyrexScanner s)
cdef p_with_items(PyrexScanner s)
cpdef p_simple_statement(PyrexScanner s, bint first_statement = *) cpdef p_simple_statement(PyrexScanner s, bint first_statement = *)
cpdef p_simple_statement_list(PyrexScanner s, ctx, bint first_statement = *) cpdef p_simple_statement_list(PyrexScanner s, ctx, bint first_statement = *)
cpdef p_compile_time_expr(PyrexScanner s) cdef p_compile_time_expr(PyrexScanner s)
cpdef p_DEF_statement(PyrexScanner s) cdef p_DEF_statement(PyrexScanner s)
cpdef p_IF_statement(PyrexScanner s, ctx) cdef p_IF_statement(PyrexScanner s, ctx)
cpdef p_statement(PyrexScanner s, ctx, bint first_statement = *) cpdef p_statement(PyrexScanner s, ctx, bint first_statement = *)
cpdef p_statement_list(PyrexScanner s, ctx, bint first_statement = *) cpdef p_statement_list(PyrexScanner s, ctx, bint first_statement = *)
cpdef p_suite(PyrexScanner s, ctx = *, bint with_doc = *, bint with_pseudo_doc = *) cpdef p_suite(PyrexScanner s, ctx = *, bint with_doc = *, bint with_pseudo_doc = *)
cpdef p_positional_and_keyword_args(PyrexScanner s, end_sy_set, templates = *) cdef p_positional_and_keyword_args(PyrexScanner s, end_sy_set, templates = *)
cpdef p_c_base_type(PyrexScanner s, bint self_flag = *, bint nonempty = *, templates = *) cpdef p_c_base_type(PyrexScanner s, bint self_flag = *, bint nonempty = *, templates = *)
cpdef p_calling_convention(PyrexScanner s) cdef p_calling_convention(PyrexScanner s)
cpdef p_c_complex_base_type(PyrexScanner s) cdef p_c_complex_base_type(PyrexScanner s)
cpdef p_c_simple_base_type(PyrexScanner s, bint self_flag, bint nonempty, templates = *) cpdef p_c_simple_base_type(PyrexScanner s, bint self_flag, bint nonempty, templates = *)
cpdef p_buffer_or_template(PyrexScanner s, base_type_node, templates) cdef p_buffer_or_template(PyrexScanner s, base_type_node, templates)
cpdef bint looking_at_name(PyrexScanner s) except -2 cdef bint looking_at_name(PyrexScanner s) except -2
cpdef bint looking_at_expr(PyrexScanner s) except -2 cdef bint looking_at_expr(PyrexScanner s) except -2
cpdef bint looking_at_base_type(PyrexScanner s) except -2 cdef bint looking_at_base_type(PyrexScanner s) except -2
cpdef bint looking_at_dotted_name(PyrexScanner s) except -2 cdef bint looking_at_dotted_name(PyrexScanner s) except -2
cpdef p_sign_and_longness(PyrexScanner s) cdef p_sign_and_longness(PyrexScanner s)
cpdef p_opt_cname(PyrexScanner s) cdef p_opt_cname(PyrexScanner s)
cpdef p_c_declarator(PyrexScanner s, ctx = *, bint empty = *, bint is_type = *, bint cmethod_flag = *, cpdef p_c_declarator(PyrexScanner s, ctx = *, bint empty = *, bint is_type = *, bint cmethod_flag = *,
bint assignable = *, bint nonempty = *, bint assignable = *, bint nonempty = *,
bint calling_convention_allowed = *) bint calling_convention_allowed = *)
cpdef p_c_array_declarator(PyrexScanner s, base) cdef p_c_array_declarator(PyrexScanner s, base)
cpdef p_c_func_declarator(PyrexScanner s, pos, ctx, base, bint cmethod_flag) cdef p_c_func_declarator(PyrexScanner s, pos, ctx, base, bint cmethod_flag)
cpdef p_c_simple_declarator(PyrexScanner s, ctx, bint empty, bint is_type, bint cmethod_flag, cdef p_c_simple_declarator(PyrexScanner s, ctx, bint empty, bint is_type, bint cmethod_flag,
bint assignable, bint nonempty) bint assignable, bint nonempty)
cpdef p_nogil(PyrexScanner s) cdef p_nogil(PyrexScanner s)
cpdef p_with_gil(PyrexScanner s) cdef p_with_gil(PyrexScanner s)
cpdef p_exception_value_clause(PyrexScanner s) cdef p_exception_value_clause(PyrexScanner s)
cpdef p_c_arg_list(PyrexScanner s, ctx = *, bint in_pyfunc = *, bint cmethod_flag = *, cpdef p_c_arg_list(PyrexScanner s, ctx = *, bint in_pyfunc = *, bint cmethod_flag = *,
bint nonempty_declarators = *, bint kw_only = *, bint annotated = *) bint nonempty_declarators = *, bint kw_only = *, bint annotated = *)
cpdef p_optional_ellipsis(PyrexScanner s) cdef p_optional_ellipsis(PyrexScanner s)
cpdef p_c_arg_decl(PyrexScanner s, ctx, in_pyfunc, bint cmethod_flag = *, bint nonempty = *, bint kw_only = *, bint annotated = *) cpdef p_c_arg_decl(PyrexScanner s, ctx, in_pyfunc, bint cmethod_flag = *, bint nonempty = *, bint kw_only = *, bint annotated = *)
cpdef p_api(PyrexScanner s) cdef p_api(PyrexScanner s)
cpdef p_cdef_statement(PyrexScanner s, ctx) cdef p_cdef_statement(PyrexScanner s, ctx)
cpdef p_cdef_block(PyrexScanner s, ctx) cdef p_cdef_block(PyrexScanner s, ctx)
cpdef p_cdef_extern_block(PyrexScanner s, pos, ctx) cdef p_cdef_extern_block(PyrexScanner s, pos, ctx)
cpdef p_c_enum_definition(PyrexScanner s, pos, ctx) cdef p_c_enum_definition(PyrexScanner s, pos, ctx)
cpdef p_c_enum_line(PyrexScanner s, ctx, list items) cdef p_c_enum_line(PyrexScanner s, ctx, list items)
cpdef p_c_enum_item(PyrexScanner s, ctx, list items) cdef p_c_enum_item(PyrexScanner s, ctx, list items)
cpdef p_c_struct_or_union_definition(PyrexScanner s, pos, ctx) cdef p_c_struct_or_union_definition(PyrexScanner s, pos, ctx)
cpdef p_visibility(PyrexScanner s, prev_visibility) cdef p_visibility(PyrexScanner s, prev_visibility)
cpdef p_c_modifiers(PyrexScanner s) cdef p_c_modifiers(PyrexScanner s)
cpdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx) cdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx)
cpdef p_ctypedef_statement(PyrexScanner s, ctx) cdef p_ctypedef_statement(PyrexScanner s, ctx)
cpdef p_decorators(PyrexScanner s) cdef p_decorators(PyrexScanner s)
cpdef p_def_statement(PyrexScanner s, list decorators = *) cdef p_def_statement(PyrexScanner s, list decorators = *)
cpdef p_varargslist(PyrexScanner s, terminator=*, bint annotated = *) cpdef p_varargslist(PyrexScanner s, terminator=*, bint annotated = *)
cpdef p_py_arg_decl(PyrexScanner s, bint annotated = *) cpdef p_py_arg_decl(PyrexScanner s, bint annotated = *)
cpdef p_class_statement(PyrexScanner s, decorators) cdef p_class_statement(PyrexScanner s, decorators)
cpdef p_c_class_definition(PyrexScanner s, pos, ctx) cdef p_c_class_definition(PyrexScanner s, pos, ctx)
cpdef p_c_class_options(PyrexScanner s) cdef p_c_class_options(PyrexScanner s)
cpdef p_property_decl(PyrexScanner s) cdef p_property_decl(PyrexScanner s)
cpdef p_doc_string(PyrexScanner s) cdef p_doc_string(PyrexScanner s)
cpdef p_code(PyrexScanner s, level= *) cdef p_compiler_directive_comments(PyrexScanner s)
cpdef p_compiler_directive_comments(PyrexScanner s) cdef p_cpp_class_definition(PyrexScanner s, pos, ctx)
cpdef p_module(PyrexScanner s, pxd, full_module_name)
cpdef p_cpp_class_definition(PyrexScanner s, pos, ctx)
...@@ -583,20 +583,7 @@ def p_atom(s): ...@@ -583,20 +583,7 @@ def p_atom(s):
expect_ellipsis(s) expect_ellipsis(s)
return ExprNodes.EllipsisNode(pos) return ExprNodes.EllipsisNode(pos)
elif sy == 'INT': elif sy == 'INT':
value = s.systring return p_int_literal(s)
s.next()
unsigned = ""
longness = ""
while value[-1] in "UuLl":
if value[-1] in "Ll":
longness += "L"
else:
unsigned += "U"
value = value[:-1]
return ExprNodes.IntNode(pos,
value = value,
unsigned = unsigned,
longness = longness)
elif sy == 'FLOAT': elif sy == 'FLOAT':
value = s.systring value = s.systring
s.next() s.next()
...@@ -631,6 +618,37 @@ def p_atom(s): ...@@ -631,6 +618,37 @@ def p_atom(s):
else: else:
s.error("Expected an identifier or literal") s.error("Expected an identifier or literal")
def p_int_literal(s):
pos = s.position()
value = s.systring
s.next()
unsigned = ""
longness = ""
while value[-1] in u"UuLl":
if value[-1] in u"Ll":
longness += "L"
else:
unsigned += "U"
value = value[:-1]
# '3L' is ambiguous in Py2 but not in Py3. '3U' and '3LL' are
# illegal in Py2 Python files. All suffixes are illegal in Py3
# Python files.
is_c_literal = None
if unsigned:
is_c_literal = True
elif longness:
if longness == 'LL' or s.context.language_level >= 3:
is_c_literal = True
if s.in_python_file:
if is_c_literal:
error(pos, "illegal integer literal syntax in Python source file")
is_c_literal = False
return ExprNodes.IntNode(pos,
is_c_literal = is_c_literal,
value = value,
unsigned = unsigned,
longness = longness)
def p_name(s, name): def p_name(s, name):
pos = s.position() pos = s.position()
if not s.compile_time_expr and name in s.compile_time_env: if not s.compile_time_expr and name in s.compile_time_env:
...@@ -1722,7 +1740,7 @@ def p_statement(s, ctx, first_statement = 0): ...@@ -1722,7 +1740,7 @@ def p_statement(s, ctx, first_statement = 0):
s.level = ctx.level s.level = ctx.level
return p_def_statement(s, decorators) return p_def_statement(s, decorators)
elif s.sy == 'class': elif s.sy == 'class':
if ctx.level != 'module': if ctx.level not in ('module', 'function', 'class', 'other'):
s.error("class definition not allowed here") s.error("class definition not allowed here")
return p_class_statement(s, decorators) return p_class_statement(s, decorators)
elif s.sy == 'include': elif s.sy == 'include':
...@@ -2166,7 +2184,7 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag, ...@@ -2166,7 +2184,7 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
cname = ctx.namespace + "::" + name cname = ctx.namespace + "::" + name
if name == 'operator' and ctx.visibility == 'extern' and nonempty: if name == 'operator' and ctx.visibility == 'extern' and nonempty:
op = s.sy op = s.sy
if [c in '+-*/<=>!%&|([^~,' for c in op]: if [1 for c in op if c in '+-*/<=>!%&|([^~,']:
s.next() s.next()
# Handle diphthong operators. # Handle diphthong operators.
if op == '(': if op == '(':
......
...@@ -2,14 +2,21 @@ import cython ...@@ -2,14 +2,21 @@ import cython
from Cython.Plex.Scanners cimport Scanner from Cython.Plex.Scanners cimport Scanner
cdef class Method:
cdef object name
cdef object __name__
cdef class CompileTimeScope: cdef class CompileTimeScope:
cdef public entries cdef public dict entries
cdef public outer cdef public CompileTimeScope outer
cdef declare(self, name, value)
cdef lookup_here(self, name)
cpdef lookup(self, name)
cdef class PyrexScanner(Scanner): cdef class PyrexScanner(Scanner):
cdef public context cdef public context
cdef public list included_files cdef public list included_files
cdef public compile_time_env cdef public CompileTimeScope compile_time_env
cdef public bint compile_time_eval cdef public bint compile_time_eval
cdef public bint compile_time_expr cdef public bint compile_time_expr
cdef public bint parse_comments cdef public bint parse_comments
...@@ -23,9 +30,23 @@ cdef class PyrexScanner(Scanner): ...@@ -23,9 +30,23 @@ cdef class PyrexScanner(Scanner):
cdef public systring cdef public systring
cdef long current_level(self) cdef long current_level(self)
cpdef begin(self, state) #cpdef commentline(self, text)
cpdef next(self) #cpdef open_bracket_action(self, text)
cpdef bint expect(self, what, message = *) except -2 #cpdef close_bracket_action(self, text)
#cpdef newline_action(self, text)
#cpdef begin_string_action(self, text)
#cpdef end_string_action(self, text)
#cpdef unclosed_string_action(self, text)
@cython.locals(current_level=cython.long, new_level=cython.long) @cython.locals(current_level=cython.long, new_level=cython.long)
cpdef indentation_action(self, text) cpdef indentation_action(self, text)
#cpdef eof_action(self, text)
cdef next(self)
cdef peek(self)
#cpdef put_back(self, sy, systring)
#cdef unread(self, token, value)
cdef bint expect(self, what, message = *) except -2
cdef expect_keyword(self, what, message = *)
cdef expected(self, what, message = *)
cdef expect_indent(self)
cdef expect_dedent(self)
cdef expect_newline(self, message = *)
...@@ -358,10 +358,10 @@ class PyrexScanner(Scanner): ...@@ -358,10 +358,10 @@ class PyrexScanner(Scanner):
self.error("Unrecognized character") self.error("Unrecognized character")
if sy == IDENT: if sy == IDENT:
if systring in self.keywords: if systring in self.keywords:
if systring == 'print' and print_function in self.context.future_directives: if systring == u'print' and print_function in self.context.future_directives:
self.keywords.remove('print') self.keywords.remove('print')
systring = EncodedString(systring) systring = EncodedString(systring)
elif systring == 'exec' and self.context.language_level >= 3: elif systring == u'exec' and self.context.language_level >= 3:
self.keywords.remove('exec') self.keywords.remove('exec')
systring = EncodedString(systring) systring = EncodedString(systring)
else: else:
......
...@@ -1381,9 +1381,6 @@ class ClassScope(Scope): ...@@ -1381,9 +1381,6 @@ class ClassScope(Scope):
self.class_name = name self.class_name = name
self.doc = None self.doc = None
def add_string_const(self, value, identifier = False):
return self.outer_scope.add_string_const(value, identifier)
def lookup(self, name): def lookup(self, name):
entry = Scope.lookup(self, name) entry = Scope.lookup(self, name)
if entry: if entry:
......
cimport cython cimport cython
cdef class BasicVisitor: cdef class TreeVisitor:
cdef public list access_path
cdef dict dispatch_table cdef dict dispatch_table
cpdef visit(self, obj) cpdef visit(self, obj)
cdef _visit(self, obj) cdef _visit(self, obj)
cdef find_handler(self, obj) cdef find_handler(self, obj)
cdef class TreeVisitor(BasicVisitor):
cdef public list access_path
cdef _visitchild(self, child, parent, attrname, idx) cdef _visitchild(self, child, parent, attrname, idx)
@cython.locals(idx=int) @cython.locals(idx=int)
cdef dict _visitchildren(self, parent, attrs) cdef dict _visitchildren(self, parent, attrs)
......
...@@ -11,49 +11,7 @@ import Naming ...@@ -11,49 +11,7 @@ import Naming
import Errors import Errors
import DebugFlags import DebugFlags
class BasicVisitor(object): class TreeVisitor(object):
"""A generic visitor base class which can be used for visiting any kind of object."""
# Note: If needed, this can be replaced with a more efficient metaclass
# approach, resolving the jump table at module load time rather than per visitor
# instance.
def __init__(self):
self.dispatch_table = {}
def visit(self, obj):
return self._visit(obj)
def _visit(self, obj):
try:
handler_method = self.dispatch_table[type(obj)]
except KeyError:
handler_method = self.find_handler(obj)
self.dispatch_table[type(obj)] = handler_method
return handler_method(obj)
def find_handler(self, obj):
cls = type(obj)
#print "Cache miss for class %s in visitor %s" % (
# cls.__name__, type(self).__name__)
# Must resolve, try entire hierarchy
pattern = "visit_%s"
mro = inspect.getmro(cls)
handler_method = None
for mro_cls in mro:
if hasattr(self, pattern % mro_cls.__name__):
handler_method = getattr(self, pattern % mro_cls.__name__)
break
if handler_method is None:
print type(self), cls
if hasattr(self, 'access_path') and self.access_path:
print self.access_path
if self.access_path:
print self.access_path[-1][0].pos
print self.access_path[-1][0].__dict__
raise RuntimeError("Visitor %r does not accept object: %s" % (self, obj))
#print "Caching " + cls.__name__
return handler_method
class TreeVisitor(BasicVisitor):
""" """
Base class for writing visitors for a Cython tree, contains utilities for Base class for writing visitors for a Cython tree, contains utilities for
recursing such trees using visitors. Each node is recursing such trees using visitors. Each node is
...@@ -96,9 +54,9 @@ class TreeVisitor(BasicVisitor): ...@@ -96,9 +54,9 @@ class TreeVisitor(BasicVisitor):
out 3 out 3
out 0 out 0
""" """
def __init__(self): def __init__(self):
super(TreeVisitor, self).__init__() super(TreeVisitor, self).__init__()
self.dispatch_table = {}
self.access_path = [] self.access_path = []
def dump_node(self, node, indent=0): def dump_node(self, node, indent=0):
...@@ -176,10 +134,43 @@ class TreeVisitor(BasicVisitor): ...@@ -176,10 +134,43 @@ class TreeVisitor(BasicVisitor):
last_node.pos, self.__class__.__name__, last_node.pos, self.__class__.__name__,
u'\n'.join(trace), e, stacktrace) u'\n'.join(trace), e, stacktrace)
def find_handler(self, obj):
# to resolve, try entire hierarchy
cls = type(obj)
pattern = "visit_%s"
mro = inspect.getmro(cls)
handler_method = None
for mro_cls in mro:
handler_method = getattr(self, pattern % mro_cls.__name__, None)
if handler_method is not None:
return handler_method
print type(self), cls
if self.access_path:
print self.access_path
print self.access_path[-1][0].pos
print self.access_path[-1][0].__dict__
raise RuntimeError("Visitor %r does not accept object: %s" % (self, obj))
def visit(self, obj):
return self._visit(obj)
def _visit(self, obj):
try:
handler_method = self.dispatch_table[type(obj)]
except KeyError:
handler_method = self.find_handler(obj)
self.dispatch_table[type(obj)] = handler_method
return handler_method(obj)
def _visitchild(self, child, parent, attrname, idx): def _visitchild(self, child, parent, attrname, idx):
self.access_path.append((parent, attrname, idx)) self.access_path.append((parent, attrname, idx))
try: try:
result = self._visit(child) try:
handler_method = self.dispatch_table[type(child)]
except KeyError:
handler_method = self.find_handler(child)
self.dispatch_table[type(child)] = handler_method
result = handler_method(child)
except Errors.CompileError: except Errors.CompileError:
raise raise
except Exception, e: except Exception, e:
......
cdef class Action:
cdef perform(self, token_stream, text)
cpdef same_as(self, other)
cdef class Return(Action):
cdef object value
cdef perform(self, token_stream, text)
cpdef same_as(self, other)
cdef class Call(Action):
cdef object function
cdef perform(self, token_stream, text)
cpdef same_as(self, other)
cdef class Begin(Action):
cdef object state_name
cdef perform(self, token_stream, text)
cpdef same_as(self, other)
cdef class Ignore(Action):
cdef perform(self, token_stream, text)
cdef class Text(Action):
cdef perform(self, token_stream, text)
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
class Action(object): class Action(object):
def perform(self, token_stream, text):
pass # abstract
def same_as(self, other): def same_as(self, other):
return self is other return self is other
...@@ -18,8 +21,6 @@ class Return(Action): ...@@ -18,8 +21,6 @@ class Return(Action):
be returned as the value of the associated token be returned as the value of the associated token
""" """
value = None
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
...@@ -38,8 +39,6 @@ class Call(Action): ...@@ -38,8 +39,6 @@ class Call(Action):
Internal Plex action which causes a function to be called. Internal Plex action which causes a function to be called.
""" """
function = None
def __init__(self, function): def __init__(self, function):
self.function = function self.function = function
...@@ -60,8 +59,6 @@ class Begin(Action): ...@@ -60,8 +59,6 @@ class Begin(Action):
for more information. for more information.
""" """
state_name = None
def __init__(self, state_name): def __init__(self, state_name):
self.state_name = state_name self.state_name = state_name
...@@ -88,7 +85,7 @@ class Ignore(Action): ...@@ -88,7 +85,7 @@ class Ignore(Action):
return "IGNORE" return "IGNORE"
IGNORE = Ignore() IGNORE = Ignore()
IGNORE.__doc__ = Ignore.__doc__ #IGNORE.__doc__ = Ignore.__doc__
class Text(Action): class Text(Action):
""" """
...@@ -104,6 +101,6 @@ class Text(Action): ...@@ -104,6 +101,6 @@ class Text(Action):
return "TEXT" return "TEXT"
TEXT = Text() TEXT = Text()
TEXT.__doc__ = Text.__doc__ #TEXT.__doc__ = Text.__doc__
import cython import cython
from Cython.Plex.Actions cimport Action
cdef class Scanner: cdef class Scanner:
cdef public lexicon cdef public lexicon
...@@ -25,10 +27,11 @@ cdef class Scanner: ...@@ -25,10 +27,11 @@ cdef class Scanner:
cdef public level cdef public level
@cython.locals(input_state=long) @cython.locals(input_state=long)
cpdef next_char(self) cdef next_char(self)
cpdef tuple read(self) @cython.locals(action=Action)
cdef tuple read(self)
cdef tuple scan_a_token(self) cdef tuple scan_a_token(self)
cpdef tuple position(self) cdef tuple position(self)
@cython.locals(cur_pos=long, cur_line=long, cur_line_start=long, @cython.locals(cur_pos=long, cur_line=long, cur_line_start=long,
input_state=long, next_pos=long, state=dict, input_state=long, next_pos=long, state=dict,
...@@ -36,5 +39,5 @@ cdef class Scanner: ...@@ -36,5 +39,5 @@ cdef class Scanner:
trace=bint, discard=long, data=unicode, buffer=unicode) trace=bint, discard=long, data=unicode, buffer=unicode)
cdef run_machine_inlined(self) cdef run_machine_inlined(self)
cpdef begin(self, state) cdef begin(self, state)
cpdef produce(self, value, text = *) cdef produce(self, value, text = *)
...@@ -8,11 +8,13 @@ ...@@ -8,11 +8,13 @@
#======================================================================= #=======================================================================
import cython import cython
cython.declare(BOL=object, EOL=object, EOF=object) cython.declare(BOL=object, EOL=object, EOF=object, NOT_FOUND=object)
import Errors import Errors
from Regexps import BOL, EOL, EOF from Regexps import BOL, EOL, EOF
NOT_FOUND = object()
class Scanner(object): class Scanner(object):
""" """
A Scanner is used to read tokens from a stream of characters A Scanner is used to read tokens from a stream of characters
...@@ -179,8 +181,8 @@ class Scanner(object): ...@@ -179,8 +181,8 @@ class Scanner(object):
# End inlined self.save_for_backup() # End inlined self.save_for_backup()
c = cur_char c = cur_char
#new_state = state.new_state(c) #@slow #new_state = state.new_state(c) #@slow
new_state = state.get(c, -1) #@fast new_state = state.get(c, NOT_FOUND) #@fast
if new_state == -1: #@fast if new_state is NOT_FOUND: #@fast
new_state = c and state.get('else') #@fast new_state = c and state.get('else') #@fast
if new_state: if new_state:
if trace: #TRACE# if trace: #TRACE#
......
...@@ -10,6 +10,7 @@ import unittest ...@@ -10,6 +10,7 @@ import unittest
import doctest import doctest
import operator import operator
import tempfile import tempfile
import traceback
try: try:
from StringIO import StringIO from StringIO import StringIO
except ImportError: except ImportError:
...@@ -20,6 +21,11 @@ try: ...@@ -20,6 +21,11 @@ try:
except ImportError: except ImportError:
import pickle import pickle
try:
import threading
except ImportError: # No threads, no problems
threading = None
WITH_CYTHON = True WITH_CYTHON = True
...@@ -313,11 +319,10 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -313,11 +319,10 @@ class CythonCompileTestCase(unittest.TestCase):
if is_related(filename) and os.path.isfile(os.path.join(workdir, filename)) ] if is_related(filename) and os.path.isfile(os.path.join(workdir, 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 = self.find_module_source_file(os.path.join(test_directory, module) + '.pyx')
source_and_output = codecs.open( source_and_output = codecs.open(source_file, 'rU', 'ISO-8859-1')
self.find_module_source_file(source_file), 'rU', 'ISO-8859-1')
try: try:
out = codecs.open(os.path.join(workdir, module + '.pyx'), out = codecs.open(os.path.join(workdir, module + os.path.splitext(source_file)[1]),
'w', 'ISO-8859-1') 'w', 'ISO-8859-1')
for line in source_and_output: for line in source_and_output:
last_line = line last_line = line
...@@ -434,9 +439,12 @@ class CythonRunTestCase(CythonCompileTestCase): ...@@ -434,9 +439,12 @@ class CythonRunTestCase(CythonCompileTestCase):
result.startTest(self) result.startTest(self)
try: try:
self.setUp() self.setUp()
self.runCompileTest() try:
if not self.cython_only: self.runCompileTest()
self.run_doctests(self.module, result) if not self.cython_only:
self.run_doctests(self.module, result)
finally:
check_thread_termination()
except Exception: except Exception:
result.addError(self, sys.exc_info()) result.addError(self, sys.exc_info())
result.stopTest(self) result.stopTest(self)
...@@ -477,7 +485,6 @@ class CythonRunTestCase(CythonCompileTestCase): ...@@ -477,7 +485,6 @@ class CythonRunTestCase(CythonCompileTestCase):
output = open(result_file, 'wb') output = open(result_file, 'wb')
pickle.dump(partial_result.data(), output) pickle.dump(partial_result.data(), output)
except: except:
import traceback
traceback.print_exc() traceback.print_exc()
finally: finally:
try: output.close() try: output.close()
...@@ -531,6 +538,7 @@ class PureDoctestTestCase(unittest.TestCase): ...@@ -531,6 +538,7 @@ class PureDoctestTestCase(unittest.TestCase):
del m del m
if loaded_module_name in sys.modules: if loaded_module_name in sys.modules:
del sys.modules[loaded_module_name] del sys.modules[loaded_module_name]
check_thread_termination()
except Exception: except Exception:
result.addError(self, sys.exc_info()) result.addError(self, sys.exc_info())
result.stopTest(self) result.stopTest(self)
...@@ -602,8 +610,11 @@ class CythonUnitTestCase(CythonCompileTestCase): ...@@ -602,8 +610,11 @@ class CythonUnitTestCase(CythonCompileTestCase):
result.startTest(self) result.startTest(self)
try: try:
self.setUp() self.setUp()
self.runCompileTest() try:
unittest.defaultTestLoader.loadTestsFromName(self.module).run(result) self.runCompileTest()
unittest.defaultTestLoader.loadTestsFromName(self.module).run(result)
finally:
check_thread_termination()
except Exception: except Exception:
result.addError(self, sys.exc_info()) result.addError(self, sys.exc_info())
result.stopTest(self) result.stopTest(self)
...@@ -842,8 +853,38 @@ def refactor_for_py3(distdir, cy3_dir): ...@@ -842,8 +853,38 @@ def refactor_for_py3(distdir, cy3_dir):
''') ''')
sys.path.insert(0, cy3_dir) sys.path.insert(0, cy3_dir)
class PendingThreadsError(RuntimeError):
pass
if __name__ == '__main__': threads_seen = []
def check_thread_termination(ignore_seen=True):
if threading is None: # no threading enabled in CPython
return
current = threading.currentThread()
blocking_threads = []
for t in threading.enumerate():
if not t.isAlive() or t == current:
continue
t.join(timeout=2)
if t.isAlive():
if not ignore_seen:
blocking_threads.append(t)
continue
for seen in threads_seen:
if t is seen:
break
else:
threads_seen.append(t)
blocking_threads.append(t)
if not blocking_threads:
return
sys.stderr.write("warning: left-over threads found after running test:\n")
for t in blocking_threads:
sys.stderr.write('...%s\n' % repr(t))
raise PendingThreadsError("left-over threads found after running test")
def main():
from optparse import OptionParser from optparse import OptionParser
parser = OptionParser() parser = OptionParser()
parser.add_option("--no-cleanup", dest="cleanup_workdir", parser.add_option("--no-cleanup", dest="cleanup_workdir",
...@@ -955,6 +996,7 @@ if __name__ == '__main__': ...@@ -955,6 +996,7 @@ if __name__ == '__main__':
coverage.start() coverage.start()
if WITH_CYTHON: if WITH_CYTHON:
global CompilationOptions, pyrex_default_options, cython_compile
from Cython.Compiler.Main import \ from Cython.Compiler.Main import \
CompilationOptions, \ CompilationOptions, \
default_options as pyrex_default_options, \ default_options as pyrex_default_options, \
...@@ -1097,7 +1139,27 @@ if __name__ == '__main__': ...@@ -1097,7 +1139,27 @@ 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]))
print("ALL DONE")
if options.exit_ok: if options.exit_ok:
sys.exit(0) return_code = 0
else: else:
sys.exit(not result.wasSuccessful()) return_code = not result.wasSuccessful()
try:
check_thread_termination(ignore_seen=False)
sys.exit(return_code)
except PendingThreadsError:
# normal program exit won't kill the threads, do it the hard way here
os._exit(return_code)
if __name__ == '__main__':
try:
main()
except Exception:
traceback.print_exc()
try:
check_thread_termination(ignore_seen=False)
except PendingThreadsError:
# normal program exit won't kill the threads, do it the hard way here
os._exit(1)
...@@ -87,6 +87,7 @@ else: ...@@ -87,6 +87,7 @@ else:
def compile_cython_modules(profile=False): def compile_cython_modules(profile=False):
source_root = os.path.abspath(os.path.dirname(__file__)) source_root = os.path.abspath(os.path.dirname(__file__))
compiled_modules = ["Cython.Plex.Scanners", compiled_modules = ["Cython.Plex.Scanners",
"Cython.Plex.Actions",
"Cython.Compiler.Scanning", "Cython.Compiler.Scanning",
"Cython.Compiler.Parsing", "Cython.Compiler.Parsing",
"Cython.Compiler.Visitor", "Cython.Compiler.Visitor",
......
...@@ -17,11 +17,16 @@ function_as_method_T494 ...@@ -17,11 +17,16 @@ function_as_method_T494
closure_inside_cdef_T554 closure_inside_cdef_T554
ipow_crash_T562 ipow_crash_T562
pure_mode_cmethod_inheritance_T583 pure_mode_cmethod_inheritance_T583
closure_class_T596
# CPython regression tests that don't current work: # CPython regression tests that don't current work:
pyregr.test_threadsignals pyregr.test_threadsignals
pyregr.test_module pyregr.test_module
pyregr.test_capi
pyregr.test_socket
pyregr.test_threading
pyregr.test_sys
# CPython regression tests that don't make sense # CPython regression tests that don't make sense
pyregr.test_gdb pyregr.test_gdb
pyregr.test_support
...@@ -7,3 +7,5 @@ cdef int f() except -1: ...@@ -7,3 +7,5 @@ cdef int f() except -1:
x = nan x = nan
y = inf y = inf
z = minf z = minf
f()
...@@ -2,5 +2,6 @@ cdef char *spam() except -1: ...@@ -2,5 +2,6 @@ cdef char *spam() except -1:
pass pass
_ERRORS = u""" _ERRORS = u"""
1:26: Cannot assign type 'long' to 'char *'
1:26: Exception value incompatible with function return type 1:26: Exception value incompatible with function return type
""" """
# cython: language_level=2
def int_literals():
a = 1L # ok
b = 10000000000000L # ok
c = 1UL
d = 10000000000000UL
e = 10000000000000LL
_ERRORS = """
6:8: illegal integer literal syntax in Python source file
7:8: illegal integer literal syntax in Python source file
8:8: illegal integer literal syntax in Python source file
"""
# cython: language_level=3
def int_literals():
a = 1L
b = 10000000000000L
c = 1UL
d = 10000000000000UL
e = 10000000000000LL
_ERRORS = """
4:8: illegal integer literal syntax in Python source file
5:8: illegal integer literal syntax in Python source file
6:8: illegal integer literal syntax in Python source file
7:8: illegal integer literal syntax in Python source file
8:8: illegal integer literal syntax in Python source file
"""
def simple(a, b):
"""
>>> kls = simple(1, 2)
>>> kls().result()
3
"""
class Foo:
def result(self):
return a + b
return Foo
def nested_classes(a, b):
"""
>>> kls = nested_classes(1, 2)
>>> kls().result(-3)
0
"""
class Foo:
class Bar:
def result(self, c):
return a + b + c
return Foo.Bar
def staff(a, b):
"""
>>> kls = staff(1, 2)
>>> kls.static()
(1, 2)
>>> kls.klass()
('Foo', 1, 2)
>>> obj = kls()
>>> obj.member()
(1, 2)
"""
class Foo:
def member(self):
return a, b
@staticmethod
def static():
return a, b
@classmethod
def klass(cls):
return cls.__name__, a, b
return Foo
def nested2(a):
"""
>>> obj = nested2(1)
>>> f = obj.run(2)
>>> f()
3
"""
class Foo:
def run(self, b):
def calc():
return a + b
return calc
return Foo()
__doc__ = u"""
>>> f1 = nested1()
>>> f2 = nested2()
>>> f1 == f2 # inner functions (f)
False
>>> f1() == f2() # inner-inner functions (g)
False
"""
def nested1():
def f():
def g():
pass
return g
return f
def nested2():
def f():
def g():
pass
return g
return f
...@@ -64,6 +64,19 @@ def list_comp_unknown_type(l): ...@@ -64,6 +64,19 @@ def list_comp_unknown_type(l):
""" """
return [x*2 for x in l if x % 2 == 0] return [x*2 for x in l if x % 2 == 0]
def listcomp_as_condition(sequence):
"""
>>> listcomp_as_condition(['a', 'b', '+'])
True
>>> listcomp_as_condition('ab+')
True
>>> listcomp_as_condition('abc')
False
"""
if [1 for c in sequence if c in '+-*/<=>!%&|([^~,']:
return True
return False
def set_comp(): def set_comp():
""" """
>>> sorted(set_comp()) >>> sorted(set_comp())
...@@ -106,3 +119,16 @@ def dict_iter(dict d): ...@@ -106,3 +119,16 @@ def dict_iter(dict d):
values = [ value for value in d.values() ] values = [ value for value in d.values() ]
items = [ item for item in d.items() ] items = [ item for item in d.items() ]
return keys, values, items return keys, values, items
def int_literals():
"""
>>> int_literals()
long
long
unsigned long
unsigned long
"""
print(cython.typeof(1L))
print(cython.typeof(10000000000000L))
print(cython.typeof(1UL))
print(cython.typeof(10000000000000UL))
...@@ -28,3 +28,17 @@ def test_except_expr(bint fire): ...@@ -28,3 +28,17 @@ def test_except_expr(bint fire):
RuntimeError RuntimeError
""" """
except_expr(fire) except_expr(fire)
cdef double except_big_result(bint fire) except 100000000000000000000000000000000:
if fire:
raise RuntimeError
def test_except_big_result(bint fire):
"""
>>> test_except_big_result(False)
>>> test_except_big_result(True)
Traceback (most recent call last):
...
RuntimeError
"""
except_big_result(fire)
...@@ -244,3 +244,13 @@ def double_deref_and_increment(o, key1, key2): ...@@ -244,3 +244,13 @@ def double_deref_and_increment(o, key1, key2):
v __setitem__ a 11 v __setitem__ a 11
""" """
o[side_effect(key1)][side_effect(key2)] += 1 o[side_effect(key1)][side_effect(key2)] += 1
def conditional_inplace(value, a, condition, b):
"""
>>> conditional_inplace([1, 2, 3], [100], True, [200])
[1, 2, 3, 100]
>>> conditional_inplace([1, 2, 3], [100], False, [200])
[1, 2, 3, 200]
"""
value += a if condition else b
return value
...@@ -63,3 +63,16 @@ def nested_result(): ...@@ -63,3 +63,16 @@ def nested_result():
""" """
result = [[a-1 for a in range(b)] for b in range(4)] result = [[a-1 for a in range(b)] for b in range(4)]
return result return result
def listcomp_as_condition(sequence):
"""
>>> listcomp_as_condition(['a', 'b', '+'])
True
>>> listcomp_as_condition('ab+')
True
>>> listcomp_as_condition('abc')
False
"""
if [1 for c in sequence if c in '+-*/<=>!%&|([^~,']:
return True
return False
cimport cython
class Base(type): class Base(type):
def __new__(cls, name, bases, attrs): def __new__(cls, name, bases, attrs):
attrs['metaclass_was_here'] = True attrs['metaclass_was_here'] = True
return type.__new__(cls, name, bases, attrs) return type.__new__(cls, name, bases, attrs)
@cython.test_fail_if_path_exists("//PyClassMetaclassNode", "//Py3ClassNode")
class Foo(object): class Foo(object):
""" """
>>> obj = Foo() >>> obj = Foo()
...@@ -12,26 +15,111 @@ class Foo(object): ...@@ -12,26 +15,111 @@ class Foo(object):
""" """
__metaclass__ = Base __metaclass__ = Base
class ODict(dict):
def __init__(self):
dict.__init__(self)
self._order = []
dict.__setitem__(self, '_order', self._order)
def __setitem__(self, key, value):
dict.__setitem__(self, key, value)
self._order.append(key)
class Py3MetaclassPlusAttr(type):
def __new__(cls, name, bases, attrs, **kwargs):
for key, value in kwargs.items():
attrs[key] = value
attrs['metaclass_was_here'] = True
return type.__new__(cls, name, bases, attrs)
def __init__(self, cls, attrs, obj, **kwargs):
pass
@staticmethod
def __prepare__(*args, **kwargs):
return ODict()
@cython.test_fail_if_path_exists("//PyClassMetaclassNode")
@cython.test_assert_path_exists("//Py3ClassNode")
class Py3ClassMCOnly(object, metaclass=Py3MetaclassPlusAttr):
"""
>>> obj = Py3ClassMCOnly()
>>> obj.bar
321
>>> obj.metaclass_was_here
True
>>> obj._order
['__module__', '__doc__', 'bar', 'metaclass_was_here']
"""
bar = 321
class Py3Base(type): class Py3Base(type):
def __new__(cls, name, bases, attrs, foo=None): def __new__(cls, name, bases, attrs, **kwargs):
attrs['foo'] = foo for key, value in kwargs.items():
attrs[key] = value
return type.__new__(cls, name, bases, attrs) return type.__new__(cls, name, bases, attrs)
def __init__(self, cls, attrs, obj, foo=None): def __init__(self, cls, attrs, obj, **kwargs):
pass pass
@staticmethod @staticmethod
def __prepare__(name, bases, **kwargs): def __prepare__(*args, **kwargs):
return {'bar': 666, 'dirty': True} return ODict()
@cython.test_fail_if_path_exists("//PyClassMetaclassNode")
@cython.test_assert_path_exists("//Py3ClassNode")
class Py3Foo(object, metaclass=Py3Base, foo=123): class Py3Foo(object, metaclass=Py3Base, foo=123):
""" """
>>> obj = Py3Foo() >>> obj = Py3Foo()
>>> obj.foo >>> obj.foo
123 123
>>> obj.bar >>> obj.bar
666 321
>>> obj.dirty >>> obj._order
False ['__module__', '__doc__', 'bar', 'foo']
"""
bar = 321
kwargs = {'foo': 123, 'bar': 456}
@cython.test_assert_path_exists("//PyClassMetaclassNode", "//Py3ClassNode")
class Py3Mixed(metaclass=Py3Base, **kwargs):
"""
>>> Py3Mixed.foo
123
>>> Py3Mixed.bar
456
"""
kwargs['metaclass'] = Py3Base
@cython.test_assert_path_exists("//PyClassMetaclassNode")
class Py3Kwargs(**kwargs):
"""
>>> Py3Kwargs.foo
123
>>> Py3Kwargs.bar
456
"""
class Base3(type):
def __new__(cls, name, bases, attrs, **kwargs):
kwargs['b'] = 2
return type.__new__(cls, name, bases, attrs)
def __init__(self, *args, **kwargs):
self.kwargs = kwargs
@staticmethod
def __prepare__(*args, **kwargs):
kwargs['a'] = 1
return {}
kwargs = {'c': 0}
@cython.test_assert_path_exists("//PyClassMetaclassNode", "//Py3ClassNode")
class Foo3(metaclass=Base3, a=0, b=0, **kwargs):
"""
>>> Foo3.kwargs
{'a': 0, 'c': 0, 'b': 0}
""" """
dirty = False
...@@ -162,3 +162,36 @@ def count_lower_case_characters(unicode ustring): ...@@ -162,3 +162,36 @@ def count_lower_case_characters(unicode ustring):
if uchar.islower(): if uchar.islower():
count += 1 count += 1
return count return count
@cython.test_assert_path_exists('//SwitchStatNode',
'//ForFromStatNode')
@cython.test_fail_if_path_exists('//ForInStatNode')
def iter_and_in():
"""
>>> iter_and_in()
a
b
e
f
h
"""
for c in u'abcdefgh':
if c in u'abCDefGh':
print c
@cython.test_assert_path_exists('//SwitchStatNode',
'//ForFromStatNode')
@cython.test_fail_if_path_exists('//ForInStatNode')
def index_and_in():
"""
>>> index_and_in()
1
3
4
7
8
"""
cdef int i
for i in range(1,9):
if u'abcdefgh'[-i] in u'abCDefGh':
print i
cimport cython
module_level_tuple = (1,2,3)
def return_module_level_tuple():
"""
>>> return_module_level_tuple()
(1, 2, 3)
"""
return module_level_tuple
@cython.test_assert_path_exists("//TupleNode",
"//TupleNode[@is_literal = true]")
@cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]")
def return_empty_tuple():
"""
>>> return_empty_tuple()
()
"""
return ()
@cython.test_assert_path_exists("//TupleNode",
"//TupleNode[@is_literal = true]")
@cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]")
def return_constant_tuple1():
"""
>>> return_constant_tuple1()
(1,)
"""
return (1,)
@cython.test_assert_path_exists("//TupleNode",
"//TupleNode[@is_literal = true]")
@cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]")
def return_folded_tuple():
"""
>>> return_folded_tuple()
(1, 2, 3)
"""
return (1, 1+1, 1+1+1)
@cython.test_assert_path_exists("//TupleNode",
"//TupleNode[@is_literal = true]")
@cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]")
def return_nested_tuple():
"""
>>> return_nested_tuple()
(1, (2, 3), (3, (4, 5)))
"""
return (1, (2, 3), (3, (4, 5)))
@cython.test_assert_path_exists("//TupleNode",
"//TupleNode[@is_literal = true]")
@cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]")
def constant_tuple1():
"""
>>> constant_tuple1()
(1,)
"""
tuple1 = (1,)
return tuple1
@cython.test_assert_path_exists("//TupleNode",
"//TupleNode[@is_literal = true]")
@cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]")
def return_constant_tuple2():
"""
>>> return_constant_tuple2()
(1, 2)
"""
return (1,2)
@cython.test_assert_path_exists("//TupleNode",
"//TupleNode[@is_literal = true]")
@cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]")
def return_constant_tuple_strings():
"""
>>> return_constant_tuple_strings()
('tuple_1', 'bc', 'tuple_2')
"""
return ('tuple_1', 'bc', 'tuple_2')
@cython.test_assert_path_exists("//TupleNode",
"//TupleNode[@is_literal = true]")
@cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]")
def return_constant_tuples_string_types():
"""
>>> a,b,c = return_constant_tuples_string_types()
>>> a is b
False
>>> a is c
False
>>> b is c
False
"""
return ('a', 'bc'), (u'a', u'bc'), (b'a', b'bc')
@cython.test_assert_path_exists("//ReturnStatNode//TupleNode",
"//ReturnStatNode//TupleNode[@is_literal = false]")
@cython.test_fail_if_path_exists("//ReturnStatNode//TupleNode[@is_literal = true]")
def return_nonconstant_tuple():
"""
>>> return_nonconstant_tuple()
('a', 1, 'd')
"""
a = eval("1")
return ('a', a, 'd')
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