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

branch merge

parents 7ea63e29 17804df1
......@@ -24,3 +24,11 @@ e90c522631ae06f2170a751fb256cdea0e50fb21 0.12.1
5ac2eaefcdc9c3a7a9c29a0bb8c3e4c6c016c64c 0.13.beta0
14957f635a379c97d9966097276313e43491ed96 0.13.beta1
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):
'all_the_rest',
'pystring_table',
'cached_builtins',
'cached_constants',
'init_globals',
'init_module',
'cleanup_globals',
......@@ -462,7 +463,12 @@ class GlobalState(object):
w.enter_cfunc_scope()
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.enter_cfunc_scope()
w.putln("")
......@@ -509,15 +515,27 @@ class GlobalState(object):
if Options.cache_builtins:
w = self.parts['cached_builtins']
w.putln("return 0;")
w.put_label(w.error_label)
w.putln("return -1;")
if w.label_used(w.error_label):
w.put_label(w.error_label)
w.putln("return -1;")
w.putln("}")
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.putln("return 0;")
w.put_label(w.error_label)
w.putln("return -1;")
if w.label_used(w.error_label):
w.put_label(w.error_label)
w.putln("return -1;")
w.putln("}")
w.exit_cfunc_scope()
......@@ -536,6 +554,9 @@ class GlobalState(object):
# 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):
longness = bool(longness)
try:
......@@ -544,9 +565,14 @@ class GlobalState(object):
c = self.new_int_const(str_value, longness)
return c
def get_py_const(self, type):
def get_py_const(self, type, prefix='', cleanup_level=None):
# 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):
# return a C string constant, creating a new one if necessary
......@@ -581,8 +607,8 @@ class GlobalState(object):
self.int_const_index[(value, longness)] = c
return c
def new_py_const(self, type):
cname = self.new_const_cname()
def new_py_const(self, type, prefix=''):
cname = self.new_const_cname(prefix)
c = PyObjectConst(cname, type)
self.py_constants.append(c)
return c
......@@ -946,6 +972,9 @@ class CCodeWriter(object):
def get_py_num(self, str_value, longness):
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):
return self.globalstate.get_string_const(text).cname
......@@ -961,6 +990,9 @@ class CCodeWriter(object):
def intern_identifier(self, text):
return self.get_py_string_const(text, identifier=True)
def get_cached_constants_writer(self):
return self.globalstate.get_cached_constants_writer()
# code generation
def putln(self, code = "", safe=False):
......@@ -1247,11 +1279,13 @@ class CCodeWriter(object):
def put_pymethoddef(self, entry, term, allow_skip=True):
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
# in add_operators() (called by PyType_Ready) with a value
# that's better than ours.
if allow_skip:
elif allow_skip:
return
from TypeSlots import method_coexist
if entry.doc:
......
......@@ -800,9 +800,11 @@ class IntNode(ConstNode):
# unsigned "" or "U"
# longness "" or "L" or "LL"
# is_c_literal True/False/None creator considers this a C integer literal
unsigned = ""
longness = ""
is_c_literal = None # unknown
def __init__(self, pos, **kwds):
ExprNode.__init__(self, pos, **kwds)
......@@ -815,7 +817,10 @@ class IntNode(ConstNode):
self.calculate_constant_result()
except ValueError:
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':
# clearly a C literal
rank = (self.longness == 'LL') and 2 or 1
......@@ -844,17 +849,18 @@ class IntNode(ConstNode):
else:
return FloatNode(self.pos, value=self.value, type=dst_type,
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:
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
elif dst_type.is_pyobject:
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:
# 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,
unsigned=self.unsigned, longness=self.longness)
# We still need to perform normal coerce_to processing on the
......@@ -1495,7 +1501,6 @@ class NameNode(AtomicExprNode):
namespace = Naming.builtins_cname
else: # entry.is_pyglobal
namespace = entry.scope.namespace_cname
code.globalstate.use_utility_code(getitem_dict_utility_code)
code.putln(
'%s = PyObject_GetItem(%s, %s); %s' % (
self.result(),
......@@ -3927,10 +3932,16 @@ class TupleNode(SequenceNode):
self.is_literal = 1
else:
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):
if len(self.args) > 0:
error(self.pos, "Positive length tuples must be constructed.")
return self.result_code
else:
return Naming.empty_tuple
......@@ -3949,6 +3960,13 @@ class TupleNode(SequenceNode):
if len(self.args) == 0:
# result_code is Naming.empty_tuple
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(
"%s = PyTuple_New(%s); %s" % (
self.result(),
......@@ -3965,6 +3983,8 @@ class TupleNode(SequenceNode):
i,
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):
# We call generate_post_assignment_code here instead
......@@ -4135,10 +4155,7 @@ class ComprehensionNode(ScopedExprNode):
def analyse_declarations(self, env):
self.append.target = self # this is used in the PyList_Append of the inner loop
self.init_scope(env)
if self.expr_scope is not None:
self.loop.analyse_declarations(self.expr_scope)
else:
self.loop.analyse_declarations(env)
self.loop.analyse_declarations(self.expr_scope or env)
def init_scope(self, outer_scope, expr_scope=None):
if expr_scope is not None:
......@@ -4523,23 +4540,14 @@ class ClassNode(ExprNode, ModuleNameMixin):
# dict ExprNode Class dict (not owned by this node)
# doc ExprNode or None Doc string
# 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):
self.bases.analyse_types(env)
if self.doc:
self.doc.analyse_types(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.is_temp = 1
env.use_utility_code(create_class_utility_code);
......@@ -4553,18 +4561,6 @@ class ClassNode(ExprNode, ModuleNameMixin):
def generate_result_code(self, code):
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:
code.put_error_if_neg(self.pos,
......@@ -4573,17 +4569,161 @@ class ClassNode(ExprNode, ModuleNameMixin):
self.doc.py_result()))
py_mod_name = self.get_py_mod_name(code)
code.putln(
'%s = __Pyx_CreateClass(%s, %s, %s, %s, %s); %s' % (
'%s = __Pyx_CreateClass(%s, %s, %s, %s); %s' % (
self.result(),
self.bases.py_result(),
self.dict.py_result(),
cname,
py_mod_name,
keyword_code,
code.error_goto_if_null(self.result(), self.pos)))
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):
# Helper class used in the implementation of Python
# class definitions. Constructs an bound method
......@@ -5359,6 +5499,9 @@ class BinopNode(ExprNode):
def analyse_types(self, env):
self.operand1.analyse_types(env)
self.operand2.analyse_types(env)
self.analyse_operation(env)
def analyse_operation(self, env):
if self.is_py_operation():
self.coerce_operands_to_pyobjects(env)
self.type = self.result_type(self.operand1.type,
......@@ -5653,12 +5796,12 @@ class DivNode(NumBinopNode):
except Exception, e:
self.compile_time_value_error(e)
def analyse_types(self, env):
def analyse_operation(self, env):
if self.cdivision or env.directives['cdivision']:
self.ctruedivision = False
else:
self.ctruedivision = self.truedivision
NumBinopNode.analyse_types(self, env)
NumBinopNode.analyse_operation(self, env)
if self.is_cpp_operation():
self.cdivision = True
if not self.type.is_pyobject:
......@@ -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(
proto = """
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
PyObject *modname, PyObject *kwargs); /*proto*/
static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *name,
PyObject *mkw, PyObject *dict); /*proto*/
PyObject *modname); /*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 = """
static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *name,
PyObject *mkw, PyObject *dict) {
PyObject *__Pyx_Py3MetaclassGet(PyObject *bases, PyObject *mkw) {
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 *pargs;
PyObject *ns;
PyObject *str;
prep = PyObject_GetAttrString(metaclass, "__prepare__");
if (prep == NULL) {
if (!prep) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
return NULL;
PyErr_Clear();
return 0;
return PyDict_New();
}
pargs = PyTuple_New(2);
if (!pargs) {
Py_DECREF(prep);
return -1;
return NULL;
}
Py_INCREF(name);
Py_INCREF(bases);
PyTuple_SET_ITEM(pargs, 0, name);
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(pargs);
if (ns == NULL)
return -1;
/* XXX: This is hack, merge namespace back to dict,
__prepare__ should be ran before dict initialization */
if (PyDict_Merge(dict, ns, 0)) {
return NULL;
/* Required here to emulate assignment order */
/* XXX: use consts here */
#if PY_MAJOR_VERSION >= 3
str = PyUnicode_FromString("__module__");
#else
str = PyString_FromString("__module__");
#endif
if (!str) {
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;
/* Python3 metaclasses */
if (kwargs) {
mkw = PyDict_Copy(kwargs); /* Don't modify kwargs passed in! */
if (!mkw)
}
Py_DECREF(str);
if (doc) {
#if PY_MAJOR_VERSION >= 3
str = PyUnicode_FromString("__doc__");
#else
str = PyString_FromString("__doc__");
#endif
if (!str) {
Py_DECREF(ns);
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 (!metaclass) {
/* Python2 __metaclass__ */
metaclass = PyDict_GetItemString(dict, "__metaclass__");
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
if (PyObject_SetItem(ns, str, doc) < 0) {
Py_DECREF(ns);
Py_DECREF(str);
return NULL;
}
Py_INCREF(metaclass);
Py_DECREF(str);
}
if (mkw && PyDict_Size(mkw) > 0) {
PyObject *margs = PyTuple_New(3);
if (!margs)
goto bad;
Py_INCREF(name);
Py_INCREF(bases);
Py_INCREF(dict);
PyTuple_SET_ITEM(margs, 0, name);
PyTuple_SET_ITEM(margs, 1, bases);
PyTuple_SET_ITEM(margs, 2, dict);
result = PyEval_CallObjectWithKeywords(metaclass, margs, mkw);
Py_DECREF(margs);
} else {
result = PyObject_CallFunctionObjArgs(metaclass, name, bases, dict, NULL);
}
bad:
Py_DECREF(metaclass);
Py_XDECREF(mkw);
return ns;
}
PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, PyObject *mkw) {
PyObject *result;
PyObject *margs = PyTuple_New(3);
if (!margs)
return NULL;
Py_INCREF(name);
Py_INCREF(bases);
Py_INCREF(dict);
PyTuple_SET_ITEM(margs, 0, name);
PyTuple_SET_ITEM(margs, 1, bases);
PyTuple_SET_ITEM(margs, 2, dict);
result = PyObject_Call(metaclass, margs, mkw);
Py_DECREF(margs);
return result;
}
""")
""",
requires = [find_py2_metaclass_utility_code])
#------------------------------------------------------------------------------------
......@@ -7498,7 +7697,6 @@ static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) {
getitem_dict_utility_code = UtilityCode(
proto = """
#if PY_MAJOR_VERSION >= 3
static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
PyObject *value;
......
......@@ -1768,8 +1768,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if Options.cache_builtins:
code.putln("/*--- Builtin init code ---*/")
code.putln(code.error_goto_if_neg("__Pyx_InitCachedBuiltins()",
self.pos))
code.putln(code.error_goto_if_neg("__Pyx_InitCachedBuiltins()", self.pos))
code.putln("/*--- Constants init code ---*/")
code.putln(code.error_goto_if_neg("__Pyx_InitCachedConstants()", self.pos))
code.putln("/*--- Global init code ---*/")
self.generate_global_init_code(env, code)
......
......@@ -592,6 +592,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
"Exception value must be a Python exception or cdef function with no arguments.")
exc_val = self.exception_value
else:
self.exception_value = self.exception_value.coerce_to(return_type, env)
if self.exception_value.analyse_const_expression(env):
exc_val = self.exception_value.get_constant_c_result_code()
if exc_val is None:
......@@ -1176,7 +1177,7 @@ class FuncDefNode(StatNode, BlockNode):
def create_local_scope(self, env):
genv = env
while genv.is_py_class_scope or genv.is_c_class_scope:
genv = env.outer_scope
genv = genv.outer_scope
if self.needs_closure:
lenv = ClosureScope(name=self.entry.name,
outer_scope = genv,
......@@ -1254,11 +1255,15 @@ class FuncDefNode(StatNode, BlockNode):
self.generate_function_header(code,
with_pymethdef = with_pymethdef)
# ----- 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:
code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
code.putln(";")
elif env.is_closure_scope:
code.put(env.scope_class.type.declaration_code(Naming.outer_scope_cname))
elif cenv.is_closure_scope:
code.put(cenv.scope_class.type.declaration_code(Naming.outer_scope_cname))
code.putln(";")
self.generate_argument_declarations(lenv, code)
for entry in lenv.var_entries:
......@@ -1309,14 +1314,14 @@ class FuncDefNode(StatNode, BlockNode):
code.putln("}")
code.put_gotref(Naming.cur_scope_cname)
# 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;" % (
outer_scope_cname,
env.scope_class.type.declaration_code(''),
cenv.scope_class.type.declaration_code(''),
Naming.self_cname))
if self.needs_closure:
# 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)
# ----- Trace function call
if profile:
......@@ -2136,7 +2141,7 @@ class DefNode(FuncDefNode):
entry.doc_cname = \
Naming.funcdoc_prefix + prefix + name
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
else:
entry.wrapperbase_cname = Naming.wrapperbase_prefix + prefix + name
......@@ -2210,18 +2215,21 @@ class DefNode(FuncDefNode):
def synthesize_assignment_node(self, env):
import ExprNodes
if env.is_py_class_scope:
rhs = ExprNodes.PyCFunctionNode(self.pos,
pymethdef_cname = self.entry.pymethdef_cname)
if not self.is_staticmethod and not self.is_classmethod:
rhs.binding = True
genv = env
while genv.is_py_class_scope or genv.is_c_class_scope:
genv = genv.outer_scope
elif env.is_closure_scope:
if genv.is_closure_scope:
rhs = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname)
else:
rhs = ExprNodes.PyCFunctionNode(
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,
lhs = ExprNodes.NameNode(self.pos, name = self.name),
rhs = rhs)
......@@ -2933,12 +2941,13 @@ class PyClassDefNode(ClassDefNode):
#
# The following subnodes are constructed internally:
#
# dict DictNode Class dictionary
# dict DictNode Class dictionary or Py3 namespace
# classobj ClassNode Class object
# 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
py3_style_class = False # Python3 style class (bases+kwargs)
def __init__(self, pos, name, bases, doc, body, decorators = None,
keyword_args = None, starstar_arg = None):
......@@ -2948,22 +2957,55 @@ class PyClassDefNode(ClassDefNode):
self.body = body
self.decorators = decorators
import ExprNodes
self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
if self.doc and Options.docstrings:
doc = embed_position(self.pos, self.doc)
# FIXME: correct string node?
doc_node = ExprNodes.StringNode(pos, value = doc)
else:
doc_node = None
self.classobj = ExprNodes.ClassNode(pos, name = name,
bases = bases, dict = self.dict, doc = doc_node,
keyword_args = keyword_args, starstar_arg = starstar_arg)
if keyword_args or starstar_arg:
self.py3_style_class = True
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)
def as_cclass(self):
"""
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
if len(bases) == 0:
base_class_name = None
......@@ -3001,8 +3043,8 @@ class PyClassDefNode(ClassDefNode):
def create_scope(self, env):
genv = env
while env.is_py_class_scope or env.is_c_class_scope:
env = env.outer_scope
while genv.is_py_class_scope or genv.is_c_class_scope:
genv = genv.outer_scope
cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv)
return cenv
......@@ -3014,6 +3056,10 @@ class PyClassDefNode(ClassDefNode):
self.body.analyse_declarations(cenv)
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.classobj.analyse_expressions(env)
genv = env.global_scope()
......@@ -3027,6 +3073,10 @@ class PyClassDefNode(ClassDefNode):
def generate_execution_code(self, code):
code.pyclass_stack.append(self)
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)
cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
self.body.generate_execution_code(code)
......@@ -3035,9 +3085,15 @@ class PyClassDefNode(ClassDefNode):
self.target.generate_assignment_code(self.classobj, code)
self.dict.generate_disposal_code(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()
class CClassDefNode(ClassDefNode):
# An extension type definition.
#
......@@ -4034,7 +4090,6 @@ class IfClauseNode(Node):
self.body.analyse_control_flow(env)
def analyse_declarations(self, env):
self.condition.analyse_declarations(env)
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
......@@ -4104,6 +4159,7 @@ class SwitchStatNode(StatNode):
child_attrs = ['test', 'cases', 'else_clause']
def generate_execution_code(self, code):
self.test.generate_evaluation_code(code)
code.putln("switch (%s) {" % self.test.result())
for case in self.cases:
case.generate_execution_code(code)
......
......@@ -702,28 +702,25 @@ class SwitchTransform(Visitor.VisitorTransform):
break
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 == '==':
not_in = False
elif allow_not_in and cond.operator == '!=':
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:
return self.NO_MATCH
# this looks somewhat silly, but it does the right
......
......@@ -71,6 +71,7 @@ directive_defaults = {
'autotestdict.cdef': False,
'autotestdict.all': False,
'language_level': 2,
'fast_getattr': False, # Undocumented until we come up with a better way to handle this everywhere.
'warn': None,
'warn.undeclared': False,
......@@ -101,8 +102,8 @@ directive_scopes = { # defaults to available everywhere
'autotestdict' : ('module',),
'autotestdict.all' : ('module',),
'autotestdict.cdef' : ('module',),
'test_assert_path_exists' : ('function',),
'test_fail_if_path_exists' : ('function',),
'test_assert_path_exists' : ('function', 'class', 'cclass'),
'test_fail_if_path_exists' : ('function', 'class', 'cclass'),
}
def parse_directive_value(name, value, relaxed_bool=False):
......
......@@ -787,6 +787,13 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
body = StatListNode(node.pos, stats=[node])
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):
if not node.decorators:
return {}
......@@ -1060,21 +1067,17 @@ property NAME:
self.seen_vars_stack.pop()
return node
def visit_ComprehensionNode(self, node):
self.visitchildren(node)
node.analyse_declarations(self.env_stack[-1])
return node
def visit_ScopedExprNode(self, node):
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.env_stack.append(node.expr_scope)
self.visitchildren(node)
self.env_stack.pop()
self.seen_vars_stack.pop()
else:
self.seen_vars_stack.append(set())
self.env_stack.append(node.expr_scope)
self.visitchildren(node)
self.env_stack.pop()
self.seen_vars_stack.pop()
self.visitchildren(node)
return node
def visit_TempResultFromStatNode(self, node):
......@@ -1187,6 +1190,7 @@ class ExpandInplaceOperators(EnvTransform):
# There is code to handle this case.
return node
env = self.current_env()
def side_effect_free_reference(node, setting=False):
if isinstance(node, NameNode):
return node, []
......@@ -1215,12 +1219,18 @@ class ExpandInplaceOperators(EnvTransform):
operand1 = dup,
operand2 = rhs,
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.
let_ref_nodes.reverse()
for t in let_ref_nodes:
node = LetNode(t, node)
node.analyse_expressions(self.current_env())
return node
def visit_ExprNode(self, node):
......@@ -1318,7 +1328,7 @@ class CreateClosureClasses(CythonTransform):
return node
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
entry = target_module_scope.declare_c_class(name = as_name,
......@@ -1327,11 +1337,15 @@ class CreateClosureClasses(CythonTransform):
class_scope = entry.type.scope
class_scope.is_internal = 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,
name=Naming.outer_scope_cname, # this could conflict?
cname=Naming.outer_scope_cname,
type=node.entry.scope.scope_class.type,
type=cscope.scope_class.type,
is_cdef=True)
entries = func_scope.entries.items()
entries.sort()
......
# We declare all of these here to type the first argument.
cimport cython
from Cython.Compiler.Scanning cimport PyrexScanner
# entry points
cpdef p_ident(PyrexScanner s, message =*)
cpdef p_ident_list(PyrexScanner s)
cpdef p_module(PyrexScanner s, pxd, full_module_name)
cpdef p_code(PyrexScanner s, level= *)
# internal parser states
cpdef p_binop_operator(PyrexScanner s)
cpdef p_binop_expr(PyrexScanner s, ops, p_sub_expr)
cdef p_ident(PyrexScanner s, message =*)
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_nocond(PyrexScanner s)
cpdef p_test(PyrexScanner s)
cpdef p_test_nocond(PyrexScanner s)
cpdef p_or_test(PyrexScanner s)
cpdef p_rassoc_binop_expr(PyrexScanner s, ops, p_subexpr)
cdef p_lambdef_nocond(PyrexScanner s)
cdef p_test(PyrexScanner s)
cdef p_test_nocond(PyrexScanner s)
cdef p_or_test(PyrexScanner s)
cdef p_rassoc_binop_expr(PyrexScanner s, ops, p_subexpr)
cpdef p_and_test(PyrexScanner s)
cpdef p_not_test(PyrexScanner s)
cpdef p_comparison(PyrexScanner s)
cpdef p_test_or_starred_expr(PyrexScanner s)
cpdef p_starred_expr(PyrexScanner s)
cpdef p_cascaded_cmp(PyrexScanner s)
cpdef p_cmp_op(PyrexScanner s)
cpdef p_bit_expr(PyrexScanner s)
cdef p_comparison(PyrexScanner s)
cdef p_test_or_starred_expr(PyrexScanner s)
cdef p_starred_expr(PyrexScanner s)
cdef p_cascaded_cmp(PyrexScanner s)
cdef p_cmp_op(PyrexScanner s)
cdef p_bit_expr(PyrexScanner s)
cpdef p_xor_expr(PyrexScanner s)
cpdef p_and_expr(PyrexScanner s)
cpdef p_shift_expr(PyrexScanner s)
cpdef p_arith_expr(PyrexScanner s)
cpdef p_term(PyrexScanner s)
cpdef p_factor(PyrexScanner s)
cpdef p_typecast(PyrexScanner s)
cpdef p_sizeof(PyrexScanner s)
cpdef p_yield_expression(PyrexScanner s)
cpdef p_yield_statement(PyrexScanner s)
cpdef p_power(PyrexScanner s)
cpdef p_new_expr(PyrexScanner s)
cpdef p_trailer(PyrexScanner s, node1)
cdef p_typecast(PyrexScanner s)
cdef p_sizeof(PyrexScanner s)
cdef p_yield_expression(PyrexScanner s)
cdef p_yield_statement(PyrexScanner s)
cdef p_power(PyrexScanner s)
cdef p_new_expr(PyrexScanner s)
cdef p_trailer(PyrexScanner s, node1)
cpdef p_call_parse_args(PyrexScanner s, bint allow_genexp = *)
cpdef p_call_build_packed_args(pos, positional_args, keyword_args, star_arg)
cpdef p_call(PyrexScanner s, function)
cpdef p_index(PyrexScanner s, base)
cpdef p_subscript_list(PyrexScanner s)
cpdef p_subscript(PyrexScanner s)
cpdef p_slice_element(PyrexScanner s, follow_set)
cpdef expect_ellipsis(PyrexScanner s)
cpdef make_slice_nodes(pos, subscripts)
cdef p_call_build_packed_args(pos, positional_args, keyword_args, star_arg)
cdef p_call(PyrexScanner s, function)
cdef p_index(PyrexScanner s, base)
cdef p_subscript_list(PyrexScanner s)
cdef p_subscript(PyrexScanner s)
cdef p_slice_element(PyrexScanner s, follow_set)
cdef expect_ellipsis(PyrexScanner s)
cdef make_slice_nodes(pos, subscripts)
cpdef make_slice_node(pos, start, stop = *, step = *)
cpdef p_atom(PyrexScanner s)
cpdef p_name(PyrexScanner s, name)
cpdef p_cat_string_literal(PyrexScanner s)
cpdef p_opt_string_literal(PyrexScanner s, required_type=*)
cpdef bint check_for_non_ascii_characters(unicode string)
cpdef p_string_literal(PyrexScanner s, kind_override=*)
cpdef p_list_maker(PyrexScanner s)
cpdef p_comp_iter(PyrexScanner s, body)
cpdef p_comp_for(PyrexScanner s, body)
cpdef p_comp_if(PyrexScanner s, body)
cpdef p_dict_or_set_maker(PyrexScanner s)
cpdef p_backquote_expr(PyrexScanner s)
cdef p_atom(PyrexScanner s)
@cython.locals(value=unicode)
cdef p_int_literal(PyrexScanner s)
cdef p_name(PyrexScanner s, name)
cdef p_cat_string_literal(PyrexScanner s)
cdef p_opt_string_literal(PyrexScanner s, required_type=*)
cdef bint check_for_non_ascii_characters(unicode string)
@cython.locals(systr=unicode, is_python3_source=bint)
cdef p_string_literal(PyrexScanner s, kind_override=*)
cdef p_list_maker(PyrexScanner s)
cdef p_comp_iter(PyrexScanner s, body)
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_test_or_starred_expr_list(s, expr=*)
cpdef p_testlist(PyrexScanner s)
cpdef p_testlist_star_expr(PyrexScanner s)
cpdef p_testlist_comp(PyrexScanner s)
cpdef p_genexp(PyrexScanner s, expr)
cdef p_test_or_starred_expr_list(PyrexScanner s, expr=*)
cdef p_testlist(PyrexScanner s)
cdef p_testlist_star_expr(PyrexScanner s)
cdef p_testlist_comp(PyrexScanner s)
cdef p_genexp(PyrexScanner s, expr)
#-------------------------------------------------------
#
......@@ -70,94 +80,93 @@ cpdef p_genexp(PyrexScanner s, expr)
#
#-------------------------------------------------------
cpdef p_global_statement(PyrexScanner s)
cpdef p_expression_or_assignment(PyrexScanner s)
cpdef p_print_statement(PyrexScanner s)
cpdef p_exec_statement(PyrexScanner s)
cpdef p_del_statement(PyrexScanner s)
cdef p_global_statement(PyrexScanner s)
cdef p_expression_or_assignment(PyrexScanner s)
cdef p_print_statement(PyrexScanner s)
cdef p_exec_statement(PyrexScanner s)
cdef p_del_statement(PyrexScanner s)
cpdef p_pass_statement(PyrexScanner s, bint with_newline = *)
cpdef p_break_statement(PyrexScanner s)
cpdef p_continue_statement(PyrexScanner s)
cpdef p_return_statement(PyrexScanner s)
cpdef p_raise_statement(PyrexScanner s)
cpdef p_import_statement(PyrexScanner s)
cdef p_break_statement(PyrexScanner s)
cdef p_continue_statement(PyrexScanner s)
cdef p_return_statement(PyrexScanner s)
cdef p_raise_statement(PyrexScanner s)
cdef p_import_statement(PyrexScanner s)
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_as_name(PyrexScanner s)
cpdef p_assert_statement(PyrexScanner s)
cpdef p_if_statement(PyrexScanner s)
cpdef p_if_clause(PyrexScanner s)
cpdef p_else_clause(PyrexScanner s)
cpdef p_while_statement(PyrexScanner s)
cpdef p_for_statement(PyrexScanner s)
cdef p_as_name(PyrexScanner s)
cdef p_assert_statement(PyrexScanner s)
cdef p_if_statement(PyrexScanner s)
cdef p_if_clause(PyrexScanner s)
cdef p_else_clause(PyrexScanner s)
cdef p_while_statement(PyrexScanner s)
cdef p_for_statement(PyrexScanner s)
cpdef p_for_bounds(PyrexScanner s, bint allow_testlist = *)
cpdef p_for_from_relation(PyrexScanner s)
cpdef p_for_from_step(PyrexScanner s)
cpdef p_target(PyrexScanner s, terminator)
cpdef p_for_target(PyrexScanner s)
cpdef p_for_iterator(PyrexScanner s, bint allow_testlist = *)
cpdef p_try_statement(PyrexScanner s)
cpdef p_except_clause(PyrexScanner s)
cpdef p_include_statement(PyrexScanner s, ctx)
cpdef p_with_statement(PyrexScanner s)
cdef p_for_from_relation(PyrexScanner s)
cdef p_for_from_step(PyrexScanner s)
cdef p_target(PyrexScanner s, terminator)
cdef p_for_target(PyrexScanner s)
cdef p_for_iterator(PyrexScanner s, bint allow_testlist = *)
cdef p_try_statement(PyrexScanner s)
cdef p_except_clause(PyrexScanner s)
cdef p_include_statement(PyrexScanner s, ctx)
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_list(PyrexScanner s, ctx, bint first_statement = *)
cpdef p_compile_time_expr(PyrexScanner s)
cpdef p_DEF_statement(PyrexScanner s)
cpdef p_IF_statement(PyrexScanner s, ctx)
cdef p_compile_time_expr(PyrexScanner s)
cdef p_DEF_statement(PyrexScanner s)
cdef p_IF_statement(PyrexScanner s, ctx)
cpdef p_statement(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_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_calling_convention(PyrexScanner s)
cpdef p_c_complex_base_type(PyrexScanner s)
cdef p_calling_convention(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_buffer_or_template(PyrexScanner s, base_type_node, templates)
cpdef bint looking_at_name(PyrexScanner s) except -2
cpdef bint looking_at_expr(PyrexScanner s) except -2
cpdef bint looking_at_base_type(PyrexScanner s) except -2
cpdef bint looking_at_dotted_name(PyrexScanner s) except -2
cpdef p_sign_and_longness(PyrexScanner s)
cpdef p_opt_cname(PyrexScanner s)
cdef p_buffer_or_template(PyrexScanner s, base_type_node, templates)
cdef bint looking_at_name(PyrexScanner s) except -2
cdef bint looking_at_expr(PyrexScanner s) except -2
cdef bint looking_at_base_type(PyrexScanner s) except -2
cdef bint looking_at_dotted_name(PyrexScanner s) except -2
cdef p_sign_and_longness(PyrexScanner s)
cdef p_opt_cname(PyrexScanner s)
cpdef p_c_declarator(PyrexScanner s, ctx = *, bint empty = *, bint is_type = *, bint cmethod_flag = *,
bint assignable = *, bint nonempty = *,
bint calling_convention_allowed = *)
cpdef p_c_array_declarator(PyrexScanner s, base)
cpdef 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_array_declarator(PyrexScanner s, base)
cdef p_c_func_declarator(PyrexScanner s, pos, ctx, base, bint cmethod_flag)
cdef p_c_simple_declarator(PyrexScanner s, ctx, bint empty, bint is_type, bint cmethod_flag,
bint assignable, bint nonempty)
cpdef p_nogil(PyrexScanner s)
cpdef p_with_gil(PyrexScanner s)
cpdef p_exception_value_clause(PyrexScanner s)
cdef p_nogil(PyrexScanner s)
cdef p_with_gil(PyrexScanner s)
cdef p_exception_value_clause(PyrexScanner s)
cpdef p_c_arg_list(PyrexScanner s, ctx = *, bint in_pyfunc = *, bint cmethod_flag = *,
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_api(PyrexScanner s)
cpdef p_cdef_statement(PyrexScanner s, ctx)
cpdef p_cdef_block(PyrexScanner s, ctx)
cpdef p_cdef_extern_block(PyrexScanner s, pos, ctx)
cpdef p_c_enum_definition(PyrexScanner s, pos, ctx)
cpdef p_c_enum_line(PyrexScanner s, ctx, list items)
cpdef p_c_enum_item(PyrexScanner s, ctx, list items)
cpdef p_c_struct_or_union_definition(PyrexScanner s, pos, ctx)
cpdef p_visibility(PyrexScanner s, prev_visibility)
cpdef p_c_modifiers(PyrexScanner s)
cpdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx)
cpdef p_ctypedef_statement(PyrexScanner s, ctx)
cpdef p_decorators(PyrexScanner s)
cpdef p_def_statement(PyrexScanner s, list decorators = *)
cdef p_api(PyrexScanner s)
cdef p_cdef_statement(PyrexScanner s, ctx)
cdef p_cdef_block(PyrexScanner s, ctx)
cdef p_cdef_extern_block(PyrexScanner s, pos, ctx)
cdef p_c_enum_definition(PyrexScanner s, pos, ctx)
cdef p_c_enum_line(PyrexScanner s, ctx, list items)
cdef p_c_enum_item(PyrexScanner s, ctx, list items)
cdef p_c_struct_or_union_definition(PyrexScanner s, pos, ctx)
cdef p_visibility(PyrexScanner s, prev_visibility)
cdef p_c_modifiers(PyrexScanner s)
cdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx)
cdef p_ctypedef_statement(PyrexScanner s, ctx)
cdef p_decorators(PyrexScanner s)
cdef p_def_statement(PyrexScanner s, list decorators = *)
cpdef p_varargslist(PyrexScanner s, terminator=*, bint annotated = *)
cpdef p_py_arg_decl(PyrexScanner s, bint annotated = *)
cpdef p_class_statement(PyrexScanner s, decorators)
cpdef p_c_class_definition(PyrexScanner s, pos, ctx)
cpdef p_c_class_options(PyrexScanner s)
cpdef p_property_decl(PyrexScanner s)
cpdef p_doc_string(PyrexScanner s)
cpdef p_code(PyrexScanner s, level= *)
cpdef p_compiler_directive_comments(PyrexScanner s)
cpdef p_module(PyrexScanner s, pxd, full_module_name)
cpdef p_cpp_class_definition(PyrexScanner s, pos, ctx)
cdef p_class_statement(PyrexScanner s, decorators)
cdef p_c_class_definition(PyrexScanner s, pos, ctx)
cdef p_c_class_options(PyrexScanner s)
cdef p_property_decl(PyrexScanner s)
cdef p_doc_string(PyrexScanner s)
cdef p_compiler_directive_comments(PyrexScanner s)
cdef p_cpp_class_definition(PyrexScanner s, pos, ctx)
......@@ -583,20 +583,7 @@ def p_atom(s):
expect_ellipsis(s)
return ExprNodes.EllipsisNode(pos)
elif sy == 'INT':
value = s.systring
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)
return p_int_literal(s)
elif sy == 'FLOAT':
value = s.systring
s.next()
......@@ -631,6 +618,37 @@ def p_atom(s):
else:
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):
pos = s.position()
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):
s.level = ctx.level
return p_def_statement(s, decorators)
elif s.sy == 'class':
if ctx.level != 'module':
if ctx.level not in ('module', 'function', 'class', 'other'):
s.error("class definition not allowed here")
return p_class_statement(s, decorators)
elif s.sy == 'include':
......@@ -2166,7 +2184,7 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
cname = ctx.namespace + "::" + name
if name == 'operator' and ctx.visibility == 'extern' and nonempty:
op = s.sy
if [c in '+-*/<=>!%&|([^~,' for c in op]:
if [1 for c in op if c in '+-*/<=>!%&|([^~,']:
s.next()
# Handle diphthong operators.
if op == '(':
......
......@@ -2,14 +2,21 @@ import cython
from Cython.Plex.Scanners cimport Scanner
cdef class Method:
cdef object name
cdef object __name__
cdef class CompileTimeScope:
cdef public entries
cdef public outer
cdef public dict entries
cdef public CompileTimeScope outer
cdef declare(self, name, value)
cdef lookup_here(self, name)
cpdef lookup(self, name)
cdef class PyrexScanner(Scanner):
cdef public context
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_expr
cdef public bint parse_comments
......@@ -23,9 +30,23 @@ cdef class PyrexScanner(Scanner):
cdef public systring
cdef long current_level(self)
cpdef begin(self, state)
cpdef next(self)
cpdef bint expect(self, what, message = *) except -2
#cpdef commentline(self, text)
#cpdef open_bracket_action(self, text)
#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)
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):
self.error("Unrecognized character")
if sy == IDENT:
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')
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')
systring = EncodedString(systring)
else:
......
......@@ -1381,9 +1381,6 @@ class ClassScope(Scope):
self.class_name = name
self.doc = None
def add_string_const(self, value, identifier = False):
return self.outer_scope.add_string_const(value, identifier)
def lookup(self, name):
entry = Scope.lookup(self, name)
if entry:
......
cimport cython
cdef class BasicVisitor:
cdef class TreeVisitor:
cdef public list access_path
cdef dict dispatch_table
cpdef visit(self, obj)
cdef _visit(self, obj)
cdef find_handler(self, obj)
cdef class TreeVisitor(BasicVisitor):
cdef public list access_path
cdef _visitchild(self, child, parent, attrname, idx)
@cython.locals(idx=int)
cdef dict _visitchildren(self, parent, attrs)
......
......@@ -11,49 +11,7 @@ import Naming
import Errors
import DebugFlags
class BasicVisitor(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):
class TreeVisitor(object):
"""
Base class for writing visitors for a Cython tree, contains utilities for
recursing such trees using visitors. Each node is
......@@ -96,9 +54,9 @@ class TreeVisitor(BasicVisitor):
out 3
out 0
"""
def __init__(self):
super(TreeVisitor, self).__init__()
self.dispatch_table = {}
self.access_path = []
def dump_node(self, node, indent=0):
......@@ -176,10 +134,43 @@ class TreeVisitor(BasicVisitor):
last_node.pos, self.__class__.__name__,
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):
self.access_path.append((parent, attrname, idx))
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:
raise
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 @@
class Action(object):
def perform(self, token_stream, text):
pass # abstract
def same_as(self, other):
return self is other
......@@ -18,8 +21,6 @@ class Return(Action):
be returned as the value of the associated token
"""
value = None
def __init__(self, value):
self.value = value
......@@ -38,8 +39,6 @@ class Call(Action):
Internal Plex action which causes a function to be called.
"""
function = None
def __init__(self, function):
self.function = function
......@@ -60,8 +59,6 @@ class Begin(Action):
for more information.
"""
state_name = None
def __init__(self, state_name):
self.state_name = state_name
......@@ -88,7 +85,7 @@ class Ignore(Action):
return "IGNORE"
IGNORE = Ignore()
IGNORE.__doc__ = Ignore.__doc__
#IGNORE.__doc__ = Ignore.__doc__
class Text(Action):
"""
......@@ -104,6 +101,6 @@ class Text(Action):
return "TEXT"
TEXT = Text()
TEXT.__doc__ = Text.__doc__
#TEXT.__doc__ = Text.__doc__
import cython
from Cython.Plex.Actions cimport Action
cdef class Scanner:
cdef public lexicon
......@@ -25,10 +27,11 @@ cdef class Scanner:
cdef public level
@cython.locals(input_state=long)
cpdef next_char(self)
cpdef tuple read(self)
cdef next_char(self)
@cython.locals(action=Action)
cdef tuple read(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,
input_state=long, next_pos=long, state=dict,
......@@ -36,5 +39,5 @@ cdef class Scanner:
trace=bint, discard=long, data=unicode, buffer=unicode)
cdef run_machine_inlined(self)
cpdef begin(self, state)
cpdef produce(self, value, text = *)
cdef begin(self, state)
cdef produce(self, value, text = *)
......@@ -8,11 +8,13 @@
#=======================================================================
import cython
cython.declare(BOL=object, EOL=object, EOF=object)
cython.declare(BOL=object, EOL=object, EOF=object, NOT_FOUND=object)
import Errors
from Regexps import BOL, EOL, EOF
NOT_FOUND = object()
class Scanner(object):
"""
A Scanner is used to read tokens from a stream of characters
......@@ -179,8 +181,8 @@ class Scanner(object):
# End inlined self.save_for_backup()
c = cur_char
#new_state = state.new_state(c) #@slow
new_state = state.get(c, -1) #@fast
if new_state == -1: #@fast
new_state = state.get(c, NOT_FOUND) #@fast
if new_state is NOT_FOUND: #@fast
new_state = c and state.get('else') #@fast
if new_state:
if trace: #TRACE#
......
......@@ -10,6 +10,7 @@ import unittest
import doctest
import operator
import tempfile
import traceback
try:
from StringIO import StringIO
except ImportError:
......@@ -20,6 +21,11 @@ try:
except ImportError:
import pickle
try:
import threading
except ImportError: # No threads, no problems
threading = None
WITH_CYTHON = True
......@@ -313,11 +319,10 @@ class CythonCompileTestCase(unittest.TestCase):
if is_related(filename) and os.path.isfile(os.path.join(workdir, filename)) ]
def split_source_and_output(self, test_directory, module, workdir):
source_file = os.path.join(test_directory, module) + '.pyx'
source_and_output = codecs.open(
self.find_module_source_file(source_file), 'rU', 'ISO-8859-1')
source_file = self.find_module_source_file(os.path.join(test_directory, module) + '.pyx')
source_and_output = codecs.open(source_file, 'rU', 'ISO-8859-1')
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')
for line in source_and_output:
last_line = line
......@@ -434,9 +439,12 @@ class CythonRunTestCase(CythonCompileTestCase):
result.startTest(self)
try:
self.setUp()
self.runCompileTest()
if not self.cython_only:
self.run_doctests(self.module, result)
try:
self.runCompileTest()
if not self.cython_only:
self.run_doctests(self.module, result)
finally:
check_thread_termination()
except Exception:
result.addError(self, sys.exc_info())
result.stopTest(self)
......@@ -477,7 +485,6 @@ class CythonRunTestCase(CythonCompileTestCase):
output = open(result_file, 'wb')
pickle.dump(partial_result.data(), output)
except:
import traceback
traceback.print_exc()
finally:
try: output.close()
......@@ -531,6 +538,7 @@ class PureDoctestTestCase(unittest.TestCase):
del m
if loaded_module_name in sys.modules:
del sys.modules[loaded_module_name]
check_thread_termination()
except Exception:
result.addError(self, sys.exc_info())
result.stopTest(self)
......@@ -602,8 +610,11 @@ class CythonUnitTestCase(CythonCompileTestCase):
result.startTest(self)
try:
self.setUp()
self.runCompileTest()
unittest.defaultTestLoader.loadTestsFromName(self.module).run(result)
try:
self.runCompileTest()
unittest.defaultTestLoader.loadTestsFromName(self.module).run(result)
finally:
check_thread_termination()
except Exception:
result.addError(self, sys.exc_info())
result.stopTest(self)
......@@ -842,8 +853,38 @@ def refactor_for_py3(distdir, 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
parser = OptionParser()
parser.add_option("--no-cleanup", dest="cleanup_workdir",
......@@ -955,6 +996,7 @@ if __name__ == '__main__':
coverage.start()
if WITH_CYTHON:
global CompilationOptions, pyrex_default_options, cython_compile
from Cython.Compiler.Main import \
CompilationOptions, \
default_options as pyrex_default_options, \
......@@ -1097,7 +1139,27 @@ if __name__ == '__main__':
import refnanny
sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog]))
print("ALL DONE")
if options.exit_ok:
sys.exit(0)
return_code = 0
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:
def compile_cython_modules(profile=False):
source_root = os.path.abspath(os.path.dirname(__file__))
compiled_modules = ["Cython.Plex.Scanners",
"Cython.Plex.Actions",
"Cython.Compiler.Scanning",
"Cython.Compiler.Parsing",
"Cython.Compiler.Visitor",
......
......@@ -17,11 +17,16 @@ function_as_method_T494
closure_inside_cdef_T554
ipow_crash_T562
pure_mode_cmethod_inheritance_T583
closure_class_T596
# CPython regression tests that don't current work:
pyregr.test_threadsignals
pyregr.test_module
pyregr.test_capi
pyregr.test_socket
pyregr.test_threading
pyregr.test_sys
# CPython regression tests that don't make sense
pyregr.test_gdb
pyregr.test_support
......@@ -7,3 +7,5 @@ cdef int f() except -1:
x = nan
y = inf
z = minf
f()
......@@ -2,5 +2,6 @@ cdef char *spam() except -1:
pass
_ERRORS = u"""
1:26: Cannot assign type 'long' to 'char *'
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):
"""
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():
"""
>>> sorted(set_comp())
......@@ -106,3 +119,16 @@ def dict_iter(dict d):
values = [ value for value in d.values() ]
items = [ item for item in d.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):
RuntimeError
"""
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):
v __setitem__ a 11
"""
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():
"""
result = [[a-1 for a in range(b)] for b in range(4)]
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):
def __new__(cls, name, bases, attrs):
attrs['metaclass_was_here'] = True
return type.__new__(cls, name, bases, attrs)
@cython.test_fail_if_path_exists("//PyClassMetaclassNode", "//Py3ClassNode")
class Foo(object):
"""
>>> obj = Foo()
......@@ -12,26 +15,111 @@ class Foo(object):
"""
__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):
def __new__(cls, name, bases, attrs, foo=None):
attrs['foo'] = foo
def __new__(cls, name, bases, attrs, **kwargs):
for key, value in kwargs.items():
attrs[key] = value
return type.__new__(cls, name, bases, attrs)
def __init__(self, cls, attrs, obj, foo=None):
def __init__(self, cls, attrs, obj, **kwargs):
pass
@staticmethod
def __prepare__(name, bases, **kwargs):
return {'bar': 666, 'dirty': True}
def __prepare__(*args, **kwargs):
return ODict()
@cython.test_fail_if_path_exists("//PyClassMetaclassNode")
@cython.test_assert_path_exists("//Py3ClassNode")
class Py3Foo(object, metaclass=Py3Base, foo=123):
"""
>>> obj = Py3Foo()
>>> obj.foo
123
>>> obj.bar
666
>>> obj.dirty
False
321
>>> obj._order
['__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):
if uchar.islower():
count += 1
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