# Pyrex - Parse tree nodes
#
-import sys, os, time, copy
+import cython
+from cython import set
+cython.declare(sys=object, os=object, time=object, copy=object,
+ Builtin=object, error=object, warning=object, Naming=object, PyrexTypes=object,
+ py_object_type=object, ModuleScope=object, LocalScope=object, ClosureScope=object, \
+ StructOrUnionScope=object, PyClassScope=object, CClassScope=object,
+ CppClassScope=object, UtilityCode=object, EncodedString=object,
+ absolute_path_length=cython.Py_ssize_t)
-try:
- set
-except NameError:
- # Python 2.3
- from sets import Set as set
+import sys, os, time, copy
-import Code
import Builtin
from Errors import error, warning, InternalError
import Naming
if encountered is None:
encountered = set()
if id(self) in encountered:
- return "<%s (%d) -- already output>" % (self.__class__.__name__, id(self))
+ return "<%s (0x%x) -- already output>" % (self.__class__.__name__, id(self))
encountered.add(id(self))
def dump_child(x, level):
return repr(x)
- attrs = [(key, value) for key, value in self.__dict__.iteritems() if key not in filter_out]
+ attrs = [(key, value) for key, value in self.__dict__.items() if key not in filter_out]
if len(attrs) == 0:
- return "<%s (%d)>" % (self.__class__.__name__, id(self))
+ return "<%s (0x%x)>" % (self.__class__.__name__, id(self))
else:
indent = " " * level
- res = "<%s (%d)\n" % (self.__class__.__name__, id(self))
+ res = "<%s (0x%x)\n" % (self.__class__.__name__, id(self))
for key, value in attrs:
res += "%s %s: %s\n" % (indent, key, dump_child(value, level + 1))
res += "%s>" % indent
if nonempty:
nonempty -= 1
func_type_args = []
- for arg_node in self.args:
- name_declarator, type = arg_node.analyse(env, nonempty = nonempty)
+ for i, arg_node in enumerate(self.args):
+ name_declarator, type = arg_node.analyse(env, nonempty = nonempty,
+ is_self_arg = (i == 0 and env.is_c_class_scope))
name = name_declarator.name
if name_declarator.cname:
error(self.pos,
"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:
default_value = None
annotation = None
- def analyse(self, env, nonempty = 0):
- #print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
+ def analyse(self, env, nonempty = 0, is_self_arg = False):
+ if is_self_arg:
+ self.base_type.is_self_arg = self.is_self_arg = True
if self.type is None:
# The parser may missinterpret names as types...
# We fix that here.
else:
template_types = []
for template_node in self.positional_args:
- template_types.append(template_node.analyse_as_type(env))
+ type = template_node.analyse_as_type(env)
+ if type is None:
+ error(template_node.pos, "unknown type in template argument")
+ return error_type
+ template_types.append(type)
self.type = base_type.specialize_here(self.pos, template_types)
elif base_type.is_pyobject:
if sys.version_info[0] < 3:
# Py 2.x enforces byte strings as keyword arguments ...
options = dict([ (name.encode('ASCII'), value)
- for name, value in options.iteritems() ])
+ for name, value in options.items() ])
self.type = PyrexTypes.BufferType(base_type, **options)
# declarators [CDeclaratorNode]
# in_pxd boolean
# api boolean
- # properties [entry]
# decorators [cython.locals(...)] or None
# directive_locals { string : NameNode } locals defined by cython.locals(...)
child_attrs = ["base_type", "declarators"]
- properties = ()
decorators = None
directive_locals = {}
# a property; made in AnalyseDeclarationsTransform).
if (dest_scope.is_c_class_scope
and self.visibility in ('public', 'readonly')):
- self.properties = []
need_property = True
else:
need_property = False
entry.directive_locals = self.directive_locals
else:
if self.directive_locals:
- s.error("Decorators can only be followed by functions")
+ error(self.pos, "Decorators can only be followed by functions")
if self.in_pxd and self.visibility != 'extern':
error(self.pos,
"Only 'extern' C variable declaration allowed in .pxd file")
entry = dest_scope.declare_var(name, type, declarator.pos,
cname = cname, visibility = visibility, is_cdef = 1)
- if need_property:
- self.properties.append(entry)
+ entry.needs_property = need_property
class CStructOrUnionDefNode(StatNode):
# #filename string C name of filename string const
# entry Symtab.Entry
# needs_closure boolean Whether or not this function has inner functions/classes/yield
+ # needs_outer_scope boolean Whether or not this function requires outer scope
# directive_locals { string : NameNode } locals defined by cython.locals(...)
py_func = None
assmt = None
needs_closure = False
+ needs_outer_scope = False
modifiers = []
def analyse_default_values(self, env):
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,
import Buffer
lenv = self.local_scope
- if lenv.is_closure_scope:
+ if lenv.is_closure_scope and not lenv.is_passthrough:
outer_scope_cname = "%s->%s" % (Naming.cur_scope_cname,
Naming.outer_scope_cname)
else:
if is_buffer_slot:
if 'cython_unused' not in self.modifiers:
self.modifiers = self.modifiers + ['cython_unused']
+
+ preprocessor_guard = None
+ if self.entry.is_special and not is_buffer_slot:
+ slot = TypeSlots.method_name_to_slot.get(self.entry.name)
+ if slot:
+ preprocessor_guard = slot.preprocessor_guard_code()
+ if (self.entry.name == '__long__' and
+ not self.entry.scope.lookup_here('__int__')):
+ preprocessor_guard = None
profile = code.globalstate.directives['profile']
if profile:
self.generate_cached_builtins_decls(lenv, code)
# ----- Function header
code.putln("")
+
+ if preprocessor_guard:
+ code.putln(preprocessor_guard)
+
with_pymethdef = self.needs_assignment_synthesis(env, code)
if self.py_func:
self.py_func.generate_function_header(code,
self.generate_function_header(code,
with_pymethdef = with_pymethdef)
# ----- Local variable declarations
- if lenv.is_closure_scope:
+ # Find function scope
+ cenv = env
+ while cenv.is_py_class_scope or cenv.is_c_class_scope:
+ cenv = cenv.outer_scope
+ if self.needs_closure:
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 self.needs_outer_scope:
+ if lenv.is_passthrough:
+ code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
+ code.putln(";")
+ 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:
acquire_gil = self.acquire_gil
if acquire_gil:
env.use_utility_code(force_init_threads_utility_code)
+ code.putln("#ifdef WITH_THREAD")
code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
+ code.putln("#endif")
# ----- set up refnanny
if not lenv.nogil:
code.put_setup_refcount_context(self.entry.name)
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 self.needs_outer_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:
+ if lenv.is_passthrough:
+ code.putln("%s = %s;" % (Naming.cur_scope_cname, outer_scope_cname));
+ elif 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:
code.put_finish_refcount_context()
if acquire_gil:
+ code.putln("#ifdef WITH_THREAD")
code.putln("PyGILState_Release(_save);")
+ code.putln("#endif")
if not self.return_type.is_void:
code.putln("return %s;" % Naming.retval_cname)
code.putln("}")
+
+ if preprocessor_guard:
+ code.putln("#endif /*!(%s)*/" % preprocessor_guard)
+
# ----- Go back and insert temp variable declarations
tempvardecl_code.put_temp_declarations(code.funcstate)
# ----- Python version
def analyse_declarations(self, env):
self.directive_locals.update(env.directives['locals'])
base_type = self.base_type.analyse(env)
- # The 2 here is because we need both function and argument names.
+ # The 2 here is because we need both function and argument names.
name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
if not type.is_cfunction:
error(self.pos,
is_overridable = True)
cfunc = CVarDefNode(self.pos, type=cfunc_type)
else:
+ if scope is None:
+ scope = cfunc.scope
cfunc_type = cfunc.type
if len(self.args) != len(cfunc_type.args) or cfunc_type.has_varargs:
error(self.pos, "wrong number of arguments")
error(cfunc.pos, "previous declaration here")
- for formal_arg, type_arg in zip(self.args, cfunc_type.args):
- name_declarator, type = formal_arg.analyse(cfunc.scope, nonempty=1)
- if type is None or type is PyrexTypes.py_object_type or formal_arg.is_self:
+ for i, (formal_arg, type_arg) in enumerate(zip(self.args, cfunc_type.args)):
+ name_declarator, type = formal_arg.analyse(scope, nonempty=1,
+ is_self_arg = (i == 0 and scope.is_c_class_scope))
+ if type is None or type is PyrexTypes.py_object_type:
formal_arg.type = type_arg.type
formal_arg.name_declarator = name_declarator
import ExprNodes
# staticmethod() was overridden - not much we can do here ...
self.is_staticmethod = False
+ if self.name == '__new__':
+ self.is_staticmethod = 1
+
self.analyse_argument_types(env)
if self.name == '<lambda>':
self.declare_lambda_function(env)
entry.doc = embed_position(self.pos, self.doc)
entry.doc_cname = \
Naming.funcdoc_prefix + prefix + name
+ if entry.is_special:
+ 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
else:
entry.doc = None
def synthesize_assignment_node(self, env):
import ExprNodes
- if env.is_py_class_scope:
- rhs = ExprNodes.UnboundMethodNode(self.pos,
- function = ExprNodes.PyCFunctionNode(self.pos,
- pymethdef_cname = self.entry.pymethdef_cname))
- elif env.is_closure_scope:
+ genv = env
+ while genv.is_py_class_scope or genv.is_c_class_scope:
+ genv = genv.outer_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)
if proto_only:
return
if (Options.docstrings and self.entry.doc and
- (not self.entry.is_special or
- self.entry.signature.method_flags()) and
- not self.entry.scope.is_property_scope
- ):
+ not self.entry.scope.is_property_scope and
+ (not self.entry.is_special or self.entry.wrapperbase_cname)):
docstr = self.entry.doc
if docstr.is_unicode:
docstr = docstr.utf8encode()
'static char %s[] = "%s";' % (
self.entry.doc_cname,
split_string_literal(escape_byte_string(docstr))))
+ if self.entry.is_special:
+ code.putln(
+ "struct wrapperbase %s;" % self.entry.wrapperbase_cname)
if with_pymethdef:
code.put(
"static PyMethodDef %s = " %
self.entry.pymethdef_cname)
- code.put_pymethoddef(self.entry, ";")
+ code.put_pymethoddef(self.entry, ";", allow_skip=False)
code.putln("%s {" % header)
def generate_argument_declarations(self, env, code):
all_args = tuple(positional_args) + tuple(kw_only_args)
max_args = len(all_args)
- default_args = []
- for i, arg in enumerate(all_args):
- if arg.default and arg.type.is_pyobject:
- default_value = arg.calculate_default_value_code(code)
- if arg.type is not PyrexTypes.py_object_type:
- default_value = "(PyObject*)"+default_value
- default_args.append((i, default_value))
-
code.putln("Py_ssize_t kw_args = PyDict_Size(%s);" %
Naming.kwds_cname)
- # it looks funny to separate the init-to-0 from setting the
- # default value, but C89 needs this
+ # the 'values' array collects borrowed references to arguments
+ # before doing any type coercion etc.
code.putln("PyObject* values[%d] = {%s};" % (
max_args, ','.join('0'*max_args)))
- for i, default_value in default_args:
- code.putln('values[%d] = %s;' % (i, default_value))
- # parse the tuple and check that it's not too long
+ # assign borrowed Python default values to the values array,
+ # so that they can be overwritten by received arguments below
+ for i, arg in enumerate(all_args):
+ if arg.default and arg.type.is_pyobject:
+ default_value = arg.calculate_default_value_code(code)
+ code.putln('values[%d] = %s;' % (i, arg.type.as_pyobject(default_value)))
+
+ # parse the args tuple and check that it's not too long
code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
if self.star_arg:
code.putln('default:')
if arg.kw_only:
# handled separately below
continue
- code.putln('if (kw_args > %d) {' % num_required_args)
+ code.putln('if (kw_args > 0) {')
code.putln('PyObject* value = PyDict_GetItem(%s, %s);' % (
Naming.kwds_cname, pystring_cname))
- code.putln('if (unlikely(value)) { values[%d] = value; kw_args--; }' % i)
+ code.putln('if (value) { values[%d] = value; kw_args--; }' % i)
code.putln('}')
else:
num_required_args -= 1
#
# 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):
+ def __init__(self, pos, name, bases, doc, body, decorators = None,
+ keyword_args = None, starstar_arg = None):
StatNode.__init__(self, pos)
self.name = name
self.doc = doc
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)
+ 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
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
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()
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)
self.classobj.generate_evaluation_code(code)
cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
- self.body.generate_execution_code(code)
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.
#
elif not base_class_entry.type.is_extension_type:
error(self.pos, "'%s' is not an extension type" % self.base_class_name)
elif not base_class_entry.type.is_complete():
- error(self.pos, "Base class '%s' is incomplete" % self.base_class_name)
+ error(self.pos, "Base class '%s' of type '%s' is incomplete" % (
+ self.base_class_name, self.class_name))
+ elif base_class_entry.type.scope and base_class_entry.type.scope.directives and \
+ base_class_entry.type.scope.directives['final']:
+ error(self.pos, "Base class '%s' of type '%s' is final" % (
+ self.base_class_name, self.class_name))
else:
self.base_type = base_class_entry.type
has_body = self.body is not None
api = self.api,
buffer_defaults = buffer_defaults)
if home_scope is not env and self.visibility == 'extern':
- env.add_imported_entry(self.class_name, self.entry, pos)
+ env.add_imported_entry(self.class_name, self.entry, self.pos)
self.scope = scope = self.entry.type.scope
if scope is not None:
scope.directives = env.directives
if func_name in ['declare', 'typedef']:
if len(args) > 2 or kwds is not None:
- error(rhs.pos, "Can only declare one type at a time.")
+ error(self.rhs.pos, "Can only declare one type at a time.")
return
type = args[0].analyse_as_type(env)
if type is None:
elif func_name in ['struct', 'union']:
self.declaration_only = True
if len(args) > 0 or kwds is None:
- error(rhs.pos, "Struct or union members must be given by name.")
+ error(self.rhs.pos, "Struct or union members must be given by name.")
return
members = []
for member, type_node in kwds.key_value_pairs:
# (it must be a NameNode, AttributeNode, or IndexNode).
child_attrs = ["lhs", "rhs"]
- dup = None
def analyse_declarations(self, env):
self.lhs.analyse_target_declaration(env)
def analyse_types(self, env):
- self.dup = self.create_dup_node(env) # re-assigns lhs to a shallow copy
self.rhs.analyse_types(env)
self.lhs.analyse_target_types(env)
- import ExprNodes
- if self.lhs.type.is_pyobject:
- self.rhs = self.rhs.coerce_to_pyobject(env)
- elif self.rhs.type.is_pyobject:
- self.rhs = self.rhs.coerce_to(self.lhs.type, env)
- if self.lhs.type.is_pyobject:
- self.result_value_temp = ExprNodes.PyTempNode(self.pos, env)
- self.result_value = self.result_value_temp.coerce_to(self.lhs.type, env)
-
+
def generate_execution_code(self, code):
import ExprNodes
self.rhs.generate_evaluation_code(code)
- self.dup.generate_subexpr_evaluation_code(code)
- if self.dup.is_temp:
- self.dup.allocate_temp_result(code)
- # self.dup.generate_result_code is run only if it is not buffer access
- if self.operator == "**":
- extra = ", Py_None"
- else:
- extra = ""
- if self.lhs.type.is_pyobject:
- if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
+ self.lhs.generate_subexpr_evaluation_code(code)
+ c_op = self.operator
+ if c_op == "//":
+ c_op = "/"
+ elif c_op == "**":
+ error(self.pos, "No C inplace power operator")
+ if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
+ if self.lhs.type.is_pyobject:
error(self.pos, "In-place operators not allowed on object buffers in this release.")
- self.dup.generate_result_code(code)
- self.result_value_temp.allocate(code)
- code.putln(
- "%s = %s(%s, %s%s); %s" % (
- self.result_value.result(),
- self.py_operation_function(),
- self.dup.py_result(),
- self.rhs.py_result(),
- extra,
- code.error_goto_if_null(self.result_value.py_result(), self.pos)))
- code.put_gotref(self.result_value.py_result())
- self.result_value.generate_evaluation_code(code) # May be a type check...
- self.rhs.generate_disposal_code(code)
- self.rhs.free_temps(code)
- self.dup.generate_disposal_code(code)
- self.dup.free_temps(code)
- self.lhs.generate_assignment_code(self.result_value, code)
- self.result_value_temp.release(code)
- else:
- c_op = self.operator
- if c_op == "//":
- c_op = "/"
- elif c_op == "**":
- error(self.pos, "No C inplace power operator")
- elif self.lhs.type.is_complex:
- error(self.pos, "Inplace operators not implemented for complex types.")
-
- # have to do assignment directly to avoid side-effects
- if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
- self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op)
- else:
- self.dup.generate_result_code(code)
- code.putln("%s %s= %s;" % (self.lhs.result(), c_op, self.rhs.result()) )
- self.rhs.generate_disposal_code(code)
- self.rhs.free_temps(code)
- if self.dup.is_temp:
- self.dup.generate_subexpr_disposal_code(code)
- self.dup.free_subexpr_temps(code)
-
- def create_dup_node(self, env):
- import ExprNodes
- self.dup = self.lhs
- self.dup.analyse_types(env)
- if isinstance(self.lhs, ExprNodes.NameNode):
- target_lhs = ExprNodes.NameNode(self.dup.pos,
- name = self.dup.name,
- is_temp = self.dup.is_temp,
- entry = self.dup.entry)
- elif isinstance(self.lhs, ExprNodes.AttributeNode):
- target_lhs = ExprNodes.AttributeNode(self.dup.pos,
- obj = ExprNodes.CloneNode(self.lhs.obj),
- attribute = self.dup.attribute,
- is_temp = self.dup.is_temp)
- elif isinstance(self.lhs, ExprNodes.IndexNode):
- if self.lhs.index:
- index = ExprNodes.CloneNode(self.lhs.index)
- else:
- index = None
- if self.lhs.indices:
- indices = [ExprNodes.CloneNode(x) for x in self.lhs.indices]
- else:
- indices = []
- target_lhs = ExprNodes.IndexNode(self.dup.pos,
- base = ExprNodes.CloneNode(self.dup.base),
- index = index,
- indices = indices,
- is_temp = self.dup.is_temp)
+ if c_op in ('/', '%') and self.lhs.type.is_int and not code.directives['cdivision']:
+ error(self.pos, "In-place non-c divide operators not allowed on int buffers.")
+ self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op)
else:
- assert False, "Unsupported node: %s" % type(self.lhs)
- self.lhs = target_lhs
- return self.dup
-
- def py_operation_function(self):
- return self.py_functions[self.operator]
-
- py_functions = {
- "|": "PyNumber_InPlaceOr",
- "^": "PyNumber_InPlaceXor",
- "&": "PyNumber_InPlaceAnd",
- "+": "PyNumber_InPlaceAdd",
- "-": "PyNumber_InPlaceSubtract",
- "*": "PyNumber_InPlaceMultiply",
- "/": "__Pyx_PyNumber_InPlaceDivide",
- "%": "PyNumber_InPlaceRemainder",
- "<<": "PyNumber_InPlaceLshift",
- ">>": "PyNumber_InPlaceRshift",
- "**": "PyNumber_InPlacePower",
- "//": "PyNumber_InPlaceFloorDivide",
- }
+ # C++
+ # TODO: make sure overload is declared
+ code.putln("%s %s= %s;" % (self.lhs.result(), c_op, self.rhs.result()))
+ self.lhs.generate_subexpr_disposal_code(code)
+ self.lhs.free_subexpr_temps(code)
+ self.rhs.generate_disposal_code(code)
+ self.rhs.free_temps(code)
def annotate(self, code):
self.lhs.annotate(code)
self.rhs.annotate(code)
- self.dup.annotate(code)
def create_binop_node(self):
import ExprNodes
gil_message = "Raising exception"
def generate_execution_code(self, code):
- code.putln("#ifndef PYREX_WITHOUT_ASSERTIONS")
+ code.putln("#ifndef CYTHON_WITHOUT_ASSERTIONS")
self.cond.generate_evaluation_code(code)
code.putln(
"if (unlikely(!%s)) {" %
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):
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)
class ExceptClauseNode(Node):
# Part of try ... except statement.
#
- # pattern ExprNode
+ # pattern [ExprNode]
# target ExprNode or None
# body StatNode
# excinfo_target NameNode or None optional target for exception info
genv = env.global_scope()
self.function_name = env.qualified_name
if self.pattern:
- self.pattern.analyse_expressions(env)
- self.pattern = self.pattern.coerce_to_pyobject(env)
+ # normalise/unpack self.pattern into a list
+ for i, pattern in enumerate(self.pattern):
+ pattern.analyse_expressions(env)
+ self.pattern[i] = pattern.coerce_to_pyobject(env)
if self.target:
self.exc_value = ExprNodes.ExcValueNode(self.pos, env)
def generate_handling_code(self, code, end_label):
code.mark_pos(self.pos)
if self.pattern:
- self.pattern.generate_evaluation_code(code)
-
+ exc_tests = []
+ for pattern in self.pattern:
+ pattern.generate_evaluation_code(code)
+ exc_tests.append("PyErr_ExceptionMatches(%s)" % pattern.py_result())
+
match_flag = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
code.putln(
- "%s = PyErr_ExceptionMatches(%s);" % (
- match_flag,
- self.pattern.py_result()))
- self.pattern.generate_disposal_code(code)
- self.pattern.free_temps(code)
+ "%s = %s;" % (match_flag, ' || '.join(exc_tests)))
+ for pattern in self.pattern:
+ pattern.generate_disposal_code(code)
+ pattern.free_temps(code)
code.putln(
"if (%s) {" %
match_flag)
def annotate(self, code):
if self.pattern:
- self.pattern.annotate(code)
+ for pattern in self.pattern:
+ pattern.annotate(code)
if self.target:
self.target.annotate(code)
self.body.annotate(code)
code.putln(
"}")
temps_to_clean_up = code.funcstate.all_free_managed_temps()
+ code.mark_pos(self.finally_clause.pos)
code.putln(
"/*finally:*/ {")
cases_used = []
def generate_execution_code(self, code):
code.mark_pos(self.pos)
+ code.putln("{")
if self.state == 'gil':
- code.putln("{ PyGILState_STATE _save = PyGILState_Ensure();")
+ code.putln("#ifdef WITH_THREAD")
+ code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
+ code.putln("#endif")
else:
- code.putln("{ PyThreadState *_save;")
+ code.putln("#ifdef WITH_THREAD")
+ code.putln("PyThreadState *_save;")
+ code.putln("#endif")
code.putln("Py_UNBLOCK_THREADS")
TryFinallyStatNode.generate_execution_code(self, code)
code.putln("}")
def generate_execution_code(self, code):
if self.state == 'gil':
- code.putln("PyGILState_Release();")
+ code.putln("#ifdef WITH_THREAD")
+ code.putln("PyGILState_Release(_save);")
+ code.putln("#endif")
else:
code.putln("Py_BLOCK_THREADS")
break
else:
entry = env.lookup(target.name)
- if (entry.is_type and
- entry.type.name == name and
- entry.type.module_name == self.module.module_name.value):
- continue # already cimported
+ # check whether or not entry is already cimported
+ if (entry.is_type and entry.type.name == name
+ and hasattr(entry.type, 'module_name')):
+ if entry.type.module_name == self.module.module_name.value:
+ # cimported with absolute name
+ continue
+ try:
+ # cimported with relative name
+ module = env.find_module(self.module.module_name.value,
+ pos=None)
+ if entry.type.module_name == module.qualified_name:
+ continue
+ except AttributeError:
+ pass
target.analyse_target_expression(env, None)
if target.type is py_object_type:
coerced_item = None
else:
coerced_item = self.item.coerce_to(target.type, env)
- self.interned_items.append(
- (name, target, coerced_item))
+ self.interned_items.append((name, target, coerced_item))
def generate_execution_code(self, code):
self.module.generate_evaluation_code(code)
""",
impl = """
static int __Pyx_SetVtable(PyObject *dict, void *vtable) {
-#if PY_VERSION_HEX < 0x03010000
- PyObject *ob = PyCObject_FromVoidPtr(vtable, 0);
-#else
+#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
PyObject *ob = PyCapsule_New(vtable, 0, 0);
+#else
+ PyObject *ob = PyCObject_FromVoidPtr(vtable, 0);
#endif
if (!ob)
goto bad;
PyObject *ob = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__");
if (!ob)
goto bad;
-#if PY_VERSION_HEX < 0x03010000
- *(void **)vtabptr = PyCObject_AsVoidPtr(ob);
-#else
+#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
*(void **)vtabptr = PyCapsule_GetPointer(ob, 0);
+#else
+ *(void **)vtabptr = PyCObject_AsVoidPtr(ob);
#endif
if (!*(void **)vtabptr)
goto bad;