from PyrexTypes import py_object_type, error_type, CTypedefType, CFuncType
from Symtab import ModuleScope, LocalScope, GeneratorLocalScope, \
StructOrUnionScope, PyClassScope, CClassScope
-from Cython.Utils import open_new_file, replace_suffix, UtilityCode
+from Cython.Utils import open_new_file, replace_suffix
+from Code import UtilityCode
from StringEncoding import EncodedString, escape_byte_string, split_docstring
import Options
import ControlFlow
import DebugFlags
-from DebugFlags import debug_disposal_code
-
absolute_path_length = 0
def relative_position(pos):
gil_message = "Operation"
- gil_check = None
- def _gil_check(self, env):
- if env.nogil:
- self.gil_error()
+ nogil_check = None
- def gil_error(self):
+ def gil_error(self, env=None):
error(self.pos, "%s not allowed without gil" % self.gil_message)
def clone_node(self):
self.dimension.analyse_const_expression(env)
if not self.dimension.type.is_int:
error(self.dimension.pos, "Array dimension not integer")
- size = self.dimension.get_constant_result_code()
- try:
- size = int(size)
- except ValueError:
- # runtime constant?
- pass
+ size = self.dimension.get_constant_c_result_code()
+ if size is not None:
+ try:
+ size = int(size)
+ except ValueError:
+ # runtime constant?
+ pass
else:
size = None
if not base_type.is_complete():
if self.optional_arg_count:
scope = StructOrUnionScope()
- scope.declare_var('%sn' % Naming.pyrex_prefix, PyrexTypes.c_int_type, self.pos)
+ arg_count_member = '%sn' % Naming.pyrex_prefix
+ scope.declare_var(arg_count_member, PyrexTypes.c_int_type, self.pos)
for arg in func_type_args[len(func_type_args)-self.optional_arg_count:]:
scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject = 1)
struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name)
exc_val = None
exc_check = 0
+ if self.exception_check == '+':
+ env.add_include_file('stdexcept')
if return_type.is_pyobject \
and (self.exception_value or self.exception_check) \
and self.exception_check != '+':
else:
if self.exception_value:
self.exception_value.analyse_const_expression(env)
- exc_val = self.exception_value.get_constant_result_code()
+ exc_val = self.exception_value.get_constant_c_result_code()
if self.exception_check == '+':
exc_val_type = self.exception_value.type
if not exc_val_type.is_error and \
nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable)
if self.optional_arg_count:
func_type.op_arg_struct = PyrexTypes.c_ptr_type(self.op_args_struct.type)
+ callspec = env.directives['callspec']
+ if callspec:
+ current = func_type.calling_convention
+ if current and current != callspec:
+ error(self.pos, "cannot have both '%s' and '%s' "
+ "calling conventions" % (current, callspec))
+ func_type.calling_convention = callspec
return self.base.analyse(func_type, env)
# is_basic_c_type boolean
# signed boolean
# longness integer
+ # complex boolean
# is_self_arg boolean Is self argument of C method
child_attrs = []
self.arg_name = self.name
else:
error(self.pos, "'%s' is not a type identifier" % self.name)
+ if self.complex:
+ if not type.is_numeric or type.is_complex:
+ error(self.pos, "can only complexify c numeric types")
+ type = PyrexTypes.CComplexType(type)
+ type.create_declaration_utility_code(env)
if type:
return type
else:
self.positional_args,
self.keyword_args,
base_type.buffer_defaults)
-
+
+ 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() ])
+
self.type = PyrexTypes.BufferType(base_type, **options)
return self.type
dest_scope = env
self.dest_scope = dest_scope
base_type = self.base_type.analyse(env)
+
+ # If the field is an external typedef, we cannot be sure about the type,
+ # so do conversion ourself rather than rely on the CPython mechanism (through
+ # a property; made in AnalyseDeclarationsTransform).
if (dest_scope.is_c_class_scope
and self.visibility == 'public'
and base_type.is_pyobject
# in_pxd boolean
# attributes [CVarDefNode] or None
# entry Entry
+ # packed boolean
child_attrs = ["attributes"]
def analyse_declarations(self, env):
scope = None
+ if self.visibility == 'extern' and self.packed:
+ error(self.pos, "Cannot declare extern struct as 'packed'")
if self.attributes is not None:
scope = StructOrUnionScope(self.name)
self.entry = env.declare_struct_or_union(
self.name, self.kind, scope, self.typedef_flag, self.pos,
- self.cname, visibility = self.visibility)
+ self.cname, visibility = self.visibility, packed = self.packed)
if self.attributes is not None:
if self.in_pxd and not env.in_cinclude:
self.entry.defined_in_pxd = 1
cname = self.cname, visibility='ignore')
struct_entry.type.typedef_flag = False
# FIXME: this might be considered a hack ;-)
- struct_entry.cname = struct_entry.type.cname = '_' + self.cname
+ struct_entry.cname = struct_entry.type.cname = \
+ '_' + self.entry.type.typedef_cname
def analyse_expressions(self, env):
pass
item.analyse_declarations(env, self.entry)
def analyse_expressions(self, env):
- if self.visibility == 'public':
- self.temp = env.allocate_temp_pyobject()
- env.release_temp(self.temp)
-
+ pass
+
def generate_execution_code(self, code):
if self.visibility == 'public':
+ temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
for item in self.entry.enum_values:
code.putln("%s = PyInt_FromLong(%s); %s" % (
- self.temp,
+ temp,
item.cname,
- code.error_goto_if_null(self.temp, item.pos)))
+ code.error_goto_if_null(temp, item.pos)))
+ code.put_gotref(temp)
code.putln('if (__Pyx_SetAttrString(%s, "%s", %s) < 0) %s' % (
Naming.module_cname,
item.name,
- self.temp,
+ temp,
code.error_goto(item.pos)))
- code.putln("%s = 0;" % self.temp)
+ code.put_decref_clear(temp, PyrexTypes.py_object_type)
+ code.funcstate.release_temp(temp)
class CEnumDefItemNode(StatNode):
py_func = None
assmt = None
needs_closure = False
+ modifiers = []
def analyse_default_values(self, env):
genv = env.global_scope()
+ default_seen = 0
for arg in self.args:
if arg.default:
+ default_seen = 1
if arg.is_generic:
arg.default.analyse_types(env)
arg.default = arg.default.coerce_to(arg.type, genv)
- arg.default.allocate_temps(genv)
else:
error(arg.pos,
"This argument cannot have a default value")
arg.default = None
+ elif arg.kw_only:
+ default_seen = 1
+ elif default_seen:
+ error(arg.pos, "Non-default argument following default argument")
def need_gil_acquisition(self, lenv):
return 0
if type.is_cfunction:
lenv.nogil = type.nogil and not type.with_gil
self.local_scope = lenv
+ lenv.directives = env.directives
return lenv
def generate_function_definitions(self, env, code):
is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
self.entry.scope.is_c_class_scope)
+
+ profile = code.globalstate.directives['profile']
+ if profile:
+ if lenv.nogil:
+ error(self.pos, "Cannot profile nogil function.")
+ code.globalstate.use_utility_code(profile_utility_code)
# Generate C code for header and body of function
code.enter_cfunc_scope()
# ----- Extern library function declarations
lenv.generate_library_function_declarations(code)
# ----- GIL acquisition
- acquire_gil = self.need_gil_acquisition(lenv)
+ acquire_gil = self.acquire_gil
if acquire_gil:
env.use_utility_code(force_init_threads_utility_code)
code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
# ----- Automatic lead-ins for certain special functions
+ if profile:
+ code.put_trace_call(self.entry.name, self.pos)
if not lenv.nogil:
code.put_setup_refcount_context(self.entry.name)
if is_getbuffer_slot:
if code.error_label in code.labels_used:
code.put_goto(code.return_label)
code.put_label(code.error_label)
- # cleanup temps the old way
- code.put_var_xdecrefs(lenv.temp_entries)
- # cleanup temps the new way
for cname, type in code.funcstate.all_managed_temps():
code.put_xdecref(cname, type)
err_val = self.error_value()
exc_check = self.caller_will_check_exceptions()
if err_val is not None or exc_check:
+ # TODO: Fix exception tracing (though currently unused by cProfile).
+ # code.globalstate.use_utility_code(get_exception_tuple_utility_code)
+ # code.put_trace_exception()
code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
else:
warning(self.entry.pos, "Unraisable exception in function '%s'." \
# ----- Non-error return cleanup
- # If you add anything here, remember to add a condition to the
- # if-test above in the error block (so that it can jump past this
- # block).
code.put_label(code.return_label)
for entry in lenv.buffer_entries:
if entry.used:
code.put_finish_refcount_context()
+ if self.entry.is_special and self.entry.name == "__hash__":
+ # Returning -1 for __hash__ is supposed to signal an error
+ # We do as Python instances and coerce -1 into -2.
+ code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % (Naming.retval_cname, Naming.retval_cname))
+
+ if profile:
+ if self.return_type.is_pyobject:
+ code.put_trace_return(Naming.retval_cname)
+ else:
+ code.put_trace_return("Py_None")
+
if acquire_gil:
code.putln("PyGILState_Release(_save);")
code.putln("}")
# ----- Go back and insert temp variable declarations
- tempvardecl_code.put_var_declarations(lenv.temp_entries)
tempvardecl_code.put_temp_declarations(code.funcstate)
# ----- Python version
code.exit_cfunc_scope()
return self.entry.name
def analyse_declarations(self, env):
- if 'locals' in env.directives and env.directives['locals']:
- self.directive_locals = env.directives['locals']
- directive_locals = self.directive_locals
+ 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.
name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
self.entry.inline_func_in_pxd = self.inline_in_pxd
self.return_type = type.return_type
- if self.overridable and len(self.args) > 0:
+ if self.overridable and not env.is_module_scope:
+ if len(self.args) < 1 or not self.args[0].type.is_pyobject:
+ # An error will be produced in the cdef function
+ self.overridable = False
+
+ if self.overridable:
import ExprNodes
py_func_body = self.call_self_node(is_module_scope = env.is_module_scope)
self.py_func = DefNode(pos = self.pos,
def need_gil_acquisition(self, lenv):
return self.type.with_gil
- def gil_check(self, env):
+ def nogil_check(self, env):
type = self.type
with_gil = type.with_gil
if type.nogil and not with_gil:
if type.return_type.is_pyobject:
error(self.pos,
"Function with Python return type cannot be declared nogil")
- for entry in env.var_entries + env.temp_entries:
+ for entry in self.local_scope.var_entries:
if entry.type.is_pyobject:
error(self.pos, "Function declared nogil has Python locals or temporaries")
def analyse_expressions(self, env):
+ self.local_scope.directives = env.directives
if self.py_func is not None:
# this will also analyse the default values
self.py_func.analyse_expressions(env)
else:
self.analyse_default_values(env)
+ self.acquire_gil = self.need_gil_acquisition(self.local_scope)
def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
arg_decls = []
code.putln('if (%s) {' % Naming.optional_args_cname)
for arg in self.args:
if arg.default:
+ # FIXME: simple name prefixing doesn't work when
+ # argument name mangling is in place
code.putln('if (%s->%sn > %s) {' % (Naming.optional_args_cname, Naming.pyrex_prefix, i))
declarator = arg.declarator
while not hasattr(declarator, 'name'):
is_wrapper = 0
decorators = None
entry = None
+ acquire_gil = 0
def __init__(self, pos, **kwds):
nogil = cfunc_type.nogil,
visibility = 'private',
api = False,
- directive_locals = cfunc.directive_locals)
+ directive_locals = getattr(cfunc, 'directive_locals', {}))
def analyse_declarations(self, env):
- if 'locals' in env.directives:
- directive_locals = env.directives['locals']
- else:
- directive_locals = {}
- self.directive_locals = directive_locals
+ directive_locals = self.directive_locals = env.directives['locals']
for arg in self.args:
if hasattr(arg, 'name'):
type = arg.type
def analyse_signature(self, env):
any_type_tests_needed = 0
- # Use the simpler calling signature for zero- and one-argument functions.
- if not self.entry.is_special and not self.star_arg and not self.starstar_arg:
- if self.entry.signature is TypeSlots.pyfunction_signature and Options.optimize_simple_methods:
+ if self.entry.is_special:
+ self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
+ elif not env.directives['always_allow_keywords'] and not (self.star_arg or self.starstar_arg):
+ # Use the simpler calling signature for zero- and one-argument functions.
+ if self.entry.signature is TypeSlots.pyfunction_signature:
if len(self.args) == 0:
self.entry.signature = TypeSlots.pyfunction_noargs
elif len(self.args) == 1:
elif len(self.args) == 2:
if self.args[1].default is None and not self.args[1].kw_only:
self.entry.signature = TypeSlots.ibinaryfunc
- elif self.entry.is_special:
- self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
sig = self.entry.signature
nfixed = sig.num_fixed_args()
for i in range(nfixed):
env.control_flow.set_state((), (arg.name, 'initalized'), True)
def analyse_expressions(self, env):
+ self.local_scope.directives = env.directives
self.analyse_default_values(env)
if env.is_py_class_scope:
self.synthesize_assignment_node(env)
-
+
def synthesize_assignment_node(self, env):
import ExprNodes
self.assmt = SingleAssignmentNode(self.pos,
lhs = ExprNodes.NameNode(self.pos, name = self.name),
rhs = ExprNodes.UnboundMethodNode(self.pos,
- class_cname = env.class_obj_cname,
function = ExprNodes.PyCFunctionNode(self.pos,
pymethdef_cname = self.entry.pymethdef_cname)))
self.assmt.analyse_declarations(env)
return
if self.entry.doc and Options.docstrings:
docstr = self.entry.doc
- if not isinstance(docstr, str):
+ if docstr.is_unicode:
docstr = docstr.utf8encode()
code.putln(
'static char %s[] = "%s";' % (
has_star_or_kw_args = self.star_arg is not None \
or self.starstar_arg is not None or has_kwonly_args
+ for arg in self.args:
+ if not arg.type.is_pyobject:
+ done = arg.type.create_from_py_utility_code(env)
+ if not done: pass # will fail later
+
if not self.signature_has_generic_args():
if has_star_or_kw_args:
error(self.pos, "This method cannot have * or keyword arguments")
else:
positional_args = []
kw_only_args = []
- default_seen = 0
for arg in self.args:
arg_entry = arg.entry
if arg.is_generic:
if arg.default:
- default_seen = 1
if not arg.is_self_arg:
if arg.kw_only:
kw_only_args.append(arg)
positional_args.append(arg)
elif arg.kw_only:
kw_only_args.append(arg)
- default_seen = 1
- elif default_seen:
- error(arg.pos, "Non-default argument following default argument")
elif not arg.is_self_arg:
positional_args.append(arg)
code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > 0)) {" %
Naming.args_cname)
code.put('__Pyx_RaiseArgtupleInvalid("%s", 1, 0, 0, PyTuple_GET_SIZE(%s)); return %s;' % (
- self.name.utf8encode(), Naming.args_cname, self.error_value()))
+ self.name, Naming.args_cname, self.error_value()))
code.putln("}")
code.globalstate.use_utility_code(keyword_string_check_utility_code)
pystring_cname = code.intern_identifier(arg.name)
# required keyword-only argument missing
code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % (
- self.name.utf8encode(),
+ self.name,
pystring_cname))
code.putln(code.error_goto(self.pos))
break
code.put_goto(success_label)
code.put_label(argtuple_error_label)
code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % (
- self.name.utf8encode(), has_fixed_positional_count,
+ self.name, has_fixed_positional_count,
min_positional_args, max_positional_args,
Naming.args_cname))
code.putln(code.error_goto(self.pos))
# arguments up to this point
code.putln('else {')
code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % (
- self.name.utf8encode(), has_fixed_positional_count,
+ self.name, has_fixed_positional_count,
min_positional_args, max_positional_args, i))
code.putln(code.error_goto(self.pos))
code.putln('}')
elif arg.kw_only:
code.putln('else {')
code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' %(
- self.name.utf8encode(), pystring_cname))
+ self.name, pystring_cname))
code.putln(code.error_goto(self.pos))
code.putln('}')
if max_positional_args > 0:
Naming.pykwdlist_cname,
self.starstar_arg and self.starstar_arg.entry.cname or '0',
pos_arg_count,
- self.name.utf8encode()))
+ self.name))
code.putln(code.error_goto(self.pos))
code.putln('}')
code.putln("else {")
else:
code.putln("else if (unlikely(Py_TYPE(%s)->tp_dictoffset != 0)) {" % self_arg)
+ self.func_node.allocate(code)
err = code.error_goto_if_null(self.func_node.result(), self.pos)
# need to get attribute manually--scope would return cdef method
code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (
code.putln('}')
code.put_decref_clear(self.func_node.result(), PyrexTypes.py_object_type)
code.putln("}")
+ self.func_node.release(code)
class ClassDefNode(StatNode, BlockNode):
pass
# body StatNode Attribute definition code
# entry Symtab.Entry
# scope PyClassScope
+ # decorators [DecoratorNode] list of decorators or None
#
# The following subnodes are constructed internally:
#
# target NameNode Variable to assign class object to
child_attrs = ["body", "dict", "classobj", "target"]
+ decorators = None
- def __init__(self, pos, name, bases, doc, body):
+ def __init__(self, pos, name, bases, doc, body, decorators = 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:
class_name = self.name,
base_class_module = base_class_module,
base_class_name = base_class_name,
+ decorators = self.decorators,
body = self.body,
in_pxd = False,
doc = self.doc)
def analyse_declarations(self, env):
self.target.analyse_target_declaration(env)
cenv = self.create_scope(env)
+ cenv.directives = env.directives
cenv.class_obj_cname = self.target.entry.cname
self.body.analyse_declarations(cenv)
self.classobj.analyse_expressions(env)
genv = env.global_scope()
cenv = self.scope
- cenv.class_dict_cname = self.dict.result()
- cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
self.body.analyse_expressions(cenv)
self.target.analyse_target_expression(env, self.classobj)
- self.dict.release_temp(env)
- #self.classobj.release_temp(env)
- #self.target.release_target_temp(env)
def generate_function_definitions(self, env, code):
self.body.generate_function_definitions(self.scope, code)
def generate_execution_code(self, code):
+ code.pyclass_stack.append(self)
+ cenv = self.scope
self.dict.generate_evaluation_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)
+ code.pyclass_stack.pop()
class CClassDefNode(ClassDefNode):
# objstruct_name string or None Specified C name of object struct
# typeobj_name string or None Specified C name of type object
# in_pxd boolean Is in a .pxd file
+ # decorators [DecoratorNode] list of decorators or None
# doc string or None
# body StatNode or None
# entry Symtab.Entry
api = False
objstruct_name = None
typeobj_name = None
+ decorators = None
def analyse_declarations(self, env):
#print "CClassDefNode.analyse_declarations:", self.class_name
return
else:
home_scope = env
+
+ if self.visibility == 'extern':
+ if self.module_name == '__builtin__' and self.class_name in Builtin.builtin_types:
+ warning(self.pos, "%s already a builtin Cython type" % self.class_name, 1)
+
self.entry = home_scope.declare_c_class(
name = self.class_name,
pos = self.pos,
if home_scope is not env and self.visibility == 'extern':
env.add_imported_entry(self.class_name, self.entry, pos)
scope = self.entry.type.scope
+ if scope is not None:
+ scope.directives = env.directives
if self.doc and Options.docstrings:
scope.doc = embed_position(self.pos, self.doc)
def analyse_declarations(self, env):
entry = env.declare_property(self.name, self.doc, self.pos)
if entry:
+ entry.scope.directives = env.directives
self.body.analyse_declarations(entry.scope)
def analyse_expressions(self, env):
def analyse_expressions(self, env):
self.expr.analyse_expressions(env)
- self.expr.release_temp(env)
def generate_execution_code(self, code):
self.expr.generate_evaluation_code(code)
def analyse_expressions(self, env):
self.analyse_types(env)
- self.allocate_rhs_temps(env)
- self.allocate_lhs_temps(env)
# def analyse_expressions(self, env):
# self.analyse_expressions_1(env)
if use_temp:
self.rhs = self.rhs.coerce_to_temp(env)
- def allocate_rhs_temps(self, env):
- self.rhs.allocate_temps(env)
-
- def allocate_lhs_temps(self, env):
- self.lhs.allocate_target_temps(env, self.rhs)
- #self.lhs.release_target_temp(env)
- #self.rhs.release_temp(env)
-
def generate_rhs_evaluation_code(self, code):
self.rhs.generate_evaluation_code(code)
rhs = rhs.coerce_to(lhs.type, env)
self.coerced_rhs_list.append(rhs)
- def allocate_rhs_temps(self, env):
- self.rhs.allocate_temps(env)
-
- def allocate_lhs_temps(self, env):
- for lhs, rhs in zip(self.lhs_list, self.coerced_rhs_list):
- rhs.allocate_temps(env)
- lhs.allocate_target_temps(env, rhs)
- #lhs.release_target_temp(env)
- #rhs.release_temp(env)
- self.rhs.release_temp(env)
-
def generate_rhs_evaluation_code(self, code):
self.rhs.generate_evaluation_code(code)
def analyse_expressions(self, env):
for stat in self.stats:
stat.analyse_types(env, use_temp = 1)
- stat.allocate_rhs_temps(env)
- for stat in self.stats:
- stat.allocate_lhs_temps(env)
# def analyse_expressions(self, env):
# for stat in self.stats:
self.lhs.analyse_target_types(env)
if Options.incref_local_binop and self.dup.type.is_pyobject:
self.dup = self.dup.coerce_to_temp(env)
-
- def allocate_rhs_temps(self, 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 = ExprNodes.PyTempNode(self.pos, env).coerce_to(self.lhs.type, env)
- self.result_value.allocate_temps(env)
-# if use_temp:
-# self.rhs = self.rhs.coerce_to_temp(env)
- self.rhs.allocate_temps(env)
- self.dup.allocate_subexpr_temps(env)
- self.dup.allocate_temp(env)
-
- def allocate_lhs_temps(self, env):
- self.lhs.allocate_target_temps(env, self.rhs)
-# self.lhs.release_target_temp(env)
- self.dup.release_temp(env)
- if self.dup.is_temp:
- self.dup.release_subexpr_temps(env)
-# self.rhs.release_temp(env)
- if self.lhs.type.is_pyobject:
- self.result_value.release_temp(env)
-
+ 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 isinstance(self.dup, ExprNodes.NewTempExprNode):
- # This is because we're manually messing with subexpr nodes
- if self.dup.is_temp:
- self.dup.allocate_temp_result(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"
if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
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.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 == "**":
- if self.lhs.type.is_int and self.rhs.type.is_int:
- error(self.pos, "** with two C int types is ambiguous")
- else:
- error(self.pos, "No C inplace power operator")
+ error(self.pos, "No C inplace power operator")
+ elif self.lhs.type.is_complex and not code.globalstate.directives['c99_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)
def analyse_expressions(self, env):
self.arg_tuple.analyse_expressions(env)
self.arg_tuple = self.arg_tuple.coerce_to_pyobject(env)
- self.arg_tuple.release_temp(env)
env.use_utility_code(printing_utility_code)
if len(self.arg_tuple.args) == 1 and self.append_newline:
env.use_utility_code(printing_one_utility_code)
- gil_check = StatNode._gil_check
+ nogil_check = Node.gil_error
gil_message = "Python print statement"
def generate_execution_code(self, code):
for i, arg in enumerate(self.args):
arg.analyse_expressions(env)
arg = arg.coerce_to_pyobject(env)
- arg.release_temp(env)
self.args[i] = arg
- self.temp_result = env.allocate_temp_pyobject()
- env.release_temp(self.temp_result)
env.use_utility_code(Builtin.pyexec_utility_code)
- gil_check = StatNode._gil_check
+ nogil_check = Node.gil_error
gil_message = "Python exec statement"
def generate_execution_code(self, code):
arg.generate_evaluation_code(code)
args.append( arg.py_result() )
args = tuple(args + ['0', '0'][:3-len(args)])
+ temp_result = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
code.putln("%s = __Pyx_PyRun(%s, %s, %s);" % (
- (self.temp_result,) + args))
+ (temp_result,) + args))
for arg in self.args:
arg.generate_disposal_code(code)
arg.free_temps(code)
code.putln(
- code.error_goto_if_null(self.temp_result, self.pos))
- code.put_gotref(self.temp_result)
- code.put_decref_clear(self.temp_result, py_object_type)
+ code.error_goto_if_null(temp_result, self.pos))
+ code.put_gotref(temp_result)
+ code.put_decref_clear(temp_result, py_object_type)
+ code.funcstate.release_temp(temp_result)
def annotate(self, code):
for arg in self.args:
error(arg.pos, "Deletion of non-Python object")
#arg.release_target_temp(env)
- def gil_check(self, env):
+ def nogil_check(self, env):
for arg in self.args:
if arg.type.is_pyobject:
- self._gil_check(env)
+ self.gil_error()
gil_message = "Deleting Python object"
#
# value ExprNode or None
# return_type PyrexType
- # temps_in_use [Entry] Temps in use at time of return
child_attrs = ["value"]
def analyse_expressions(self, env):
return_type = env.return_type
self.return_type = return_type
- self.temps_in_use = env.temps_in_use()
if not return_type:
error(self.pos, "Return not inside a function body")
return
"Return with value in void function")
else:
self.value = self.value.coerce_to(env.return_type, env)
- self.value.allocate_temps(env)
- self.value.release_temp(env)
else:
if (not return_type.is_void
and not return_type.is_pyobject
and not return_type.is_returncode):
error(self.pos, "Return value required")
- def gil_check(self, env):
+ def nogil_check(self, env):
if self.return_type.is_pyobject:
- self._gil_check(env)
+ self.gil_error()
gil_message = "Returning Python object"
"%s = %s;" % (
Naming.retval_cname,
self.return_type.default_value))
- # free temps the old way
- for entry in self.temps_in_use:
- code.put_var_decref_clear(entry)
- # free temps the new way
for cname, type in code.funcstate.temps_holding_reference():
code.put_decref_clear(cname, type)
- #code.putln(
- # "goto %s;" %
- # code.return_label)
code.put_goto(code.return_label)
def annotate(self, code):
if self.exc_type:
self.exc_type.analyse_types(env)
self.exc_type = self.exc_type.coerce_to_pyobject(env)
- self.exc_type.allocate_temps(env)
if self.exc_value:
self.exc_value.analyse_types(env)
self.exc_value = self.exc_value.coerce_to_pyobject(env)
- self.exc_value.allocate_temps(env)
if self.exc_tb:
self.exc_tb.analyse_types(env)
self.exc_tb = self.exc_tb.coerce_to_pyobject(env)
- self.exc_tb.allocate_temps(env)
- if self.exc_type:
- self.exc_type.release_temp(env)
- if self.exc_value:
- self.exc_value.release_temp(env)
- if self.exc_tb:
- self.exc_tb.release_temp(env)
env.use_utility_code(raise_utility_code)
env.use_utility_code(restore_exception_utility_code)
- gil_check = StatNode._gil_check
+ nogil_check = Node.gil_error
gil_message = "Raising exception"
def generate_execution_code(self, code):
env.use_utility_code(raise_utility_code)
env.use_utility_code(restore_exception_utility_code)
- gil_check = StatNode._gil_check
+ nogil_check = Node.gil_error
gil_message = "Raising exception"
def generate_execution_code(self, code):
if self.value:
self.value.analyse_types(env)
self.value = self.value.coerce_to_pyobject(env)
- self.value.allocate_temps(env)
- self.cond.release_temp(env)
- if self.value:
- self.value.release_temp(env)
- #env.recycle_pending_temps() # TEMPORARY
- gil_check = StatNode._gil_check
+ nogil_check = Node.gil_error
gil_message = "Raising exception"
def generate_execution_code(self, code):
def analyse_expressions(self, env):
self.condition = \
self.condition.analyse_temp_boolean_expression(env)
- self.condition.release_temp(env)
self.body.analyse_expressions(env)
def generate_execution_code(self, code, end_label):
def analyse_expressions(self, env):
self.condition = \
self.condition.analyse_temp_boolean_expression(env)
- self.condition.release_temp(env)
- #env.recycle_pending_temps() # TEMPORARY
self.body.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
self.iterator.analyse_expressions(env)
self.item = ExprNodes.NextNode(self.iterator, env)
self.item = self.item.coerce_to(self.target.type, env)
- self.item.allocate_temps(env)
- self.target.allocate_target_temps(env, self.item)
- #self.item.release_temp(env)
- #self.target.release_target_temp(env)
self.body.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
- self.iterator.release_temp(env)
def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels()
py_loopvar_node = None
from_range = False
+ gil_message = "For-loop using object bounds or target"
+
+ def nogil_check(self, env):
+ for x in (self.target, self.bound1, self.bound2):
+ if x.type.is_pyobject:
+ self.gil_error()
+
def analyse_declarations(self, env):
self.target.analyse_target_declaration(env)
self.body.analyse_declarations(env)
self.target.analyse_target_types(env)
self.bound1.analyse_types(env)
self.bound2.analyse_types(env)
+ if self.step is not None:
+ if isinstance(self.step, ExprNodes.UnaryMinusNode):
+ warning(self.step.pos, "Probable infinite loop in for-from-by statment. Consider switching the directions of the relations.", 2)
+ self.step.analyse_types(env)
+
+ target_type = self.target.type
if self.target.type.is_numeric:
- self.bound1 = self.bound1.coerce_to(self.target.type, env)
- self.bound2 = self.bound2.coerce_to(self.target.type, env)
+ loop_type = self.target.type
else:
- self.bound1 = self.bound1.coerce_to_integer(env)
- self.bound2 = self.bound2.coerce_to_integer(env)
+ loop_type = PyrexTypes.c_int_type
+ if not self.bound1.type.is_pyobject:
+ loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound1.type)
+ if not self.bound2.type.is_pyobject:
+ loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound2.type)
+ if self.step is not None and not self.step.type.is_pyobject:
+ loop_type = PyrexTypes.widest_numeric_type(loop_type, self.step.type)
+ self.bound1 = self.bound1.coerce_to(loop_type, env)
+ self.bound2 = self.bound2.coerce_to(loop_type, env)
if not self.bound2.is_literal:
self.bound2 = self.bound2.coerce_to_temp(env)
if self.step is not None:
- if isinstance(self.step, ExprNodes.UnaryMinusNode):
- warning(self.step.pos, "Probable infinite loop in for-from-by statment. Consider switching the directions of the relations.", 2)
- self.step.analyse_types(env)
- self.step = self.step.coerce_to_integer(env)
+ self.step = self.step.coerce_to(loop_type, env)
if not self.step.is_literal:
self.step = self.step.coerce_to_temp(env)
+
target_type = self.target.type
if not (target_type.is_pyobject or target_type.is_numeric):
error(self.target.pos,
- "Integer for-loop variable must be of type int or Python object")
- #if not (target_type.is_pyobject
- # or target_type.assignable_from(PyrexTypes.c_int_type)):
- # error(self.target.pos,
- # "Cannot assign integer to variable of type '%s'" % target_type)
+ "for-from loop variable must be c numeric type or Python object")
if target_type.is_numeric:
- self.is_py_target = 0
+ self.is_py_target = False
if isinstance(self.target, ExprNodes.IndexNode) and self.target.is_buffer_access:
raise error(self.pos, "Buffer indexing not allowed as for loop target.")
self.loopvar_node = self.target
self.py_loopvar_node = None
else:
- self.is_py_target = 1
- c_loopvar_node = ExprNodes.TempNode(self.pos,
- PyrexTypes.c_long_type, env)
- c_loopvar_node.allocate_temps(env)
+ self.is_py_target = True
+ c_loopvar_node = ExprNodes.TempNode(self.pos, loop_type, env)
self.loopvar_node = c_loopvar_node
self.py_loopvar_node = \
ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env)
- self.bound1.allocate_temps(env)
- self.bound2.allocate_temps(env)
- if self.step is not None:
- self.step.allocate_temps(env)
- if self.is_py_target:
- self.py_loopvar_node.allocate_temps(env)
- self.target.allocate_target_temps(env, self.py_loopvar_node)
- #self.target.release_target_temp(env)
- #self.py_loopvar_node.release_temp(env)
self.body.analyse_expressions(env)
- if self.is_py_target:
- c_loopvar_node.release_temp(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
- self.bound1.release_temp(env)
- self.bound2.release_temp(env)
- if self.step is not None:
- self.step.release_temp(env)
def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels()
self.step.generate_evaluation_code(code)
step = self.step.result()
incop = "%s=%s" % (incop[0], step)
+ import ExprNodes
+ if isinstance(self.loopvar_node, ExprNodes.TempNode):
+ self.loopvar_node.allocate(code)
+ if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
+ self.py_loopvar_node.allocate(code)
if from_range:
loopvar_name = code.funcstate.allocate_temp(self.target.type, False)
else:
self.body.generate_execution_code(code)
code.put_label(code.continue_label)
if self.py_loopvar_node:
- # Reassign py variable to loop var here.
- # (For consistancy, should rarely come up in practice.)
+ # This mess is to make for..from loops with python targets behave
+ # exactly like those with C targets with regards to re-assignment
+ # of the loop variable.
import ExprNodes
- from_py_node = ExprNodes.CoerceFromPyTypeNode(self.loopvar_node.type, self.target, None)
+ if self.target.entry.is_pyglobal:
+ # We know target is a NameNode, this is the only ugly case.
+ target_node = ExprNodes.PyTempNode(self.target.pos, None)
+ target_node.allocate(code)
+ interned_cname = code.intern_identifier(self.target.entry.name)
+ code.putln("/*here*/")
+ code.putln("%s = __Pyx_GetName(%s, %s); %s" % (
+ target_node.result(),
+ Naming.module_cname,
+ interned_cname,
+ code.error_goto_if_null(target_node.result(), self.target.pos)))
+ code.put_gotref(target_node.result())
+ else:
+ target_node = self.target
+ from_py_node = ExprNodes.CoerceFromPyTypeNode(self.loopvar_node.type, target_node, None)
from_py_node.temp_code = loopvar_name
from_py_node.generate_result_code(code)
+ if self.target.entry.is_pyglobal:
+ code.put_decref(target_node.result(), target_node.type)
+ target_node.release(code)
code.putln("}")
if self.py_loopvar_node:
# This is potentially wasteful, but we don't want the semantics to
self.bound1.free_temps(code)
self.bound2.generate_disposal_code(code)
self.bound2.free_temps(code)
+ if isinstance(self.loopvar_node, ExprNodes.TempNode):
+ self.loopvar_node.release(code)
+ if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
+ self.py_loopvar_node.release(code)
if self.step is not None:
self.step.generate_disposal_code(code)
self.step.free_temps(code)
- if from_range:
- code.funcstate.release_temp(loopvar_name)
relation_table = {
# {relop : (initial offset, increment op)}
# body StatNode
# except_clauses [ExceptClauseNode]
# else_clause StatNode or None
- # cleanup_list [Entry] old style temps to clean up on error
child_attrs = ["body", "except_clauses", "else_clause"]
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
- self.cleanup_list = env.free_temp_entries[:]
default_clause_seen = 0
for except_clause in self.except_clauses:
except_clause.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
- gil_check = StatNode._gil_check
+ nogil_check = Node.gil_error
gil_message = "Try-except statement"
def generate_execution_code(self, code):
code.put_xdecref_clear(var, py_object_type)
code.put_goto(old_return_label)
code.put_label(our_error_label)
- code.put_var_xdecrefs_clear(self.cleanup_list)
for temp_name, type in temps_to_clean_up:
code.put_xdecref_clear(temp_name, type)
for except_clause in self.except_clauses:
if self.pattern:
self.pattern.analyse_expressions(env)
self.pattern = self.pattern.coerce_to_pyobject(env)
- self.match_flag = env.allocate_temp(PyrexTypes.c_int_type)
- self.pattern.release_temp(env)
- env.release_temp(self.match_flag)
- self.exc_vars = [env.allocate_temp(py_object_type) for i in xrange(3)]
+
if self.target:
- self.exc_value = ExprNodes.ExcValueNode(self.pos, env, self.exc_vars[1])
- self.exc_value.allocate_temps(env)
+ self.exc_value = ExprNodes.ExcValueNode(self.pos, env)
self.target.analyse_target_expression(env, self.exc_value)
if self.excinfo_target is not None:
import ExprNodes
self.excinfo_tuple = ExprNodes.TupleNode(pos=self.pos, args=[
- ExprNodes.ExcValueNode(pos=self.pos, env=env, var=self.exc_vars[0]),
- ExprNodes.ExcValueNode(pos=self.pos, env=env, var=self.exc_vars[1]),
- ExprNodes.ExcValueNode(pos=self.pos, env=env, var=self.exc_vars[2])
- ])
+ ExprNodes.ExcValueNode(pos=self.pos, env=env) for x in range(3)])
self.excinfo_tuple.analyse_expressions(env)
- self.excinfo_tuple.allocate_temps(env)
self.excinfo_target.analyse_target_expression(env, self.excinfo_tuple)
self.body.analyse_expressions(env)
- for var in self.exc_vars:
- env.release_temp(var)
- env.use_utility_code(get_exception_utility_code)
- env.use_utility_code(restore_exception_utility_code)
-
+
def generate_handling_code(self, code, end_label):
code.mark_pos(self.pos)
if self.pattern:
self.pattern.generate_evaluation_code(code)
+
+ match_flag = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
code.putln(
"%s = PyErr_ExceptionMatches(%s);" % (
- self.match_flag,
+ match_flag,
self.pattern.py_result()))
self.pattern.generate_disposal_code(code)
self.pattern.free_temps(code)
code.putln(
"if (%s) {" %
- self.match_flag)
+ match_flag)
+ code.funcstate.release_temp(match_flag)
else:
code.putln("/*except:*/ {")
+
+ if not getattr(self.body, 'stats', True):
+ # most simple case: no exception variable, empty body (pass)
+ # => reset the exception state, done
+ code.putln("PyErr_Restore(0,0,0);")
+ code.put_goto(end_label)
+ code.putln("}")
+ return
+
+ exc_vars = [code.funcstate.allocate_temp(py_object_type,
+ manage_ref=True)
+ for i in xrange(3)]
code.putln('__Pyx_AddTraceback("%s");' % self.function_name)
# We always have to fetch the exception value even if
# there is no target, because this also normalises the
# exception and stores it in the thread state.
- exc_args = "&%s, &%s, &%s" % tuple(self.exc_vars)
+ code.globalstate.use_utility_code(get_exception_utility_code)
+ exc_args = "&%s, &%s, &%s" % tuple(exc_vars)
code.putln("if (__Pyx_GetException(%s) < 0) %s" % (exc_args,
code.error_goto(self.pos)))
- for x in self.exc_vars:
+ for x in exc_vars:
code.put_gotref(x)
if self.target:
+ self.exc_value.set_var(exc_vars[1])
self.exc_value.generate_evaluation_code(code)
self.target.generate_assignment_code(self.exc_value, code)
if self.excinfo_target is not None:
+ for tempvar, node in zip(exc_vars, self.excinfo_tuple.args):
+ node.set_var(tempvar)
self.excinfo_tuple.generate_evaluation_code(code)
self.excinfo_target.generate_assignment_code(self.excinfo_tuple, code)
-
old_break_label, old_continue_label = code.break_label, code.continue_label
code.break_label = code.new_label('except_break')
code.continue_label = code.new_label('except_continue')
old_exc_vars = code.funcstate.exc_vars
- code.funcstate.exc_vars = self.exc_vars
+ code.funcstate.exc_vars = exc_vars
self.body.generate_execution_code(code)
code.funcstate.exc_vars = old_exc_vars
- for var in self.exc_vars:
+ for var in exc_vars:
code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
code.put_goto(end_label)
if code.label_used(code.break_label):
code.put_label(code.break_label)
- for var in self.exc_vars:
+ for var in exc_vars:
code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
code.put_goto(old_break_label)
code.break_label = old_break_label
if code.label_used(code.continue_label):
code.put_label(code.continue_label)
- for var in self.exc_vars:
+ for var in exc_vars:
code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
code.put_goto(old_continue_label)
code.continue_label = old_continue_label
-
+
+ for temp in exc_vars:
+ code.funcstate.release_temp(temp)
+
code.putln(
"}")
# body StatNode
# finally_clause StatNode
#
- # cleanup_list [Entry] old_style temps to clean up on error
- #
# The plan is that we funnel all continue, break
# return and error gotos into the beginning of the
# finally block, setting a variable to remember which
def create_analysed(pos, env, body, finally_clause):
node = TryFinallyStatNode(pos, body=body, finally_clause=finally_clause)
- node.cleanup_list = []
return node
create_analysed = staticmethod(create_analysed)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
- self.cleanup_list = env.free_temp_entries[:]
self.finally_clause.analyse_expressions(env)
- gil_check = StatNode._gil_check
+ nogil_check = Node.gil_error
gil_message = "Try-finally statement"
def generate_execution_code(self, code):
code.putln(
"__pyx_why = %s;" %
i)
- code.put_var_xdecrefs_clear(self.cleanup_list)
for temp_name, type in temps_to_clean_up:
code.put_xdecref_clear(temp_name, type)
code.putln(
TryFinallyStatNode.analyse_expressions(self, env)
env.nogil = was_nogil
- def gil_check(self, env):
- pass
+ nogil_check = None
def generate_execution_code(self, code):
code.mark_pos(self.pos)
entry = module_scope.declare_c_class(name, pos = pos,
module_name = self.module_name)
else:
- error(pos, "Name '%s' not declared in module '%s'"
- % (name, self.module_name))
+ submodule_scope = env.context.find_module(name, relative_to = module_scope, pos = self.pos)
+ if submodule_scope.parent_module is module_scope:
+ env.declare_module(as_name or name, submodule_scope, self.pos)
+ else:
+ error(pos, "Name '%s' not declared in module '%s'"
+ % (name, self.module_name))
if entry:
local_name = as_name or name
import ExprNodes
self.module.analyse_expressions(env)
self.item = ExprNodes.PyTempNode(self.pos, env)
- self.item.allocate_temp(env)
self.interned_items = []
for name, target in self.items:
if name == '*':
coerced_item = self.item.coerce_to(target.type, env)
self.interned_items.append(
(name, target, coerced_item))
- #target.release_target_temp(env) # was release_temp ?!?
- self.module.release_temp(env)
- self.item.release_temp(env)
def generate_execution_code(self, code):
self.module.generate_evaluation_code(code)
Naming.import_star,
self.module.py_result(),
code.error_goto(self.pos)))
+ self.item.allocate(code)
for name, target, coerced_item in self.interned_items:
cname = code.intern_identifier(name)
code.putln(
target.generate_assignment_code(coerced_item, code)
if self.item.result() != coerced_item.result():
code.put_decref_clear(self.item.result(), self.item.type)
+ self.item.release(code)
self.module.generate_disposal_code(code)
self.module.free_temps(code)
}
#endif
-""")
+""",
+requires=[printing_utility_code])
#------------------------------------------------------------------------------------
-unraisable_exception_utility_code = UtilityCode(
-proto = """
-static void __Pyx_WriteUnraisable(const char *name); /*proto*/
-""",
-impl = """
-static void __Pyx_WriteUnraisable(const char *name) {
- PyObject *old_exc, *old_val, *old_tb;
- PyObject *ctx;
- __Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
- #if PY_MAJOR_VERSION < 3
- ctx = PyString_FromString(name);
- #else
- ctx = PyUnicode_FromString(name);
- #endif
- __Pyx_ErrRestore(old_exc, old_val, old_tb);
- if (!ctx) {
- PyErr_WriteUnraisable(Py_None);
- } else {
- PyErr_WriteUnraisable(ctx);
- Py_DECREF(ctx);
- }
-}
-""")
-
-#------------------------------------------------------------------------------------
-
traceback_utility_code = UtilityCode(
proto = """
static void __Pyx_AddTraceback(const char *funcname); /*proto*/
PyObject *py_srcfile = 0;
PyObject *py_funcname = 0;
PyObject *py_globals = 0;
- PyObject *empty_string = 0;
PyCodeObject *py_code = 0;
PyFrameObject *py_frame = 0;
if (!py_funcname) goto bad;
py_globals = PyModule_GetDict(%(GLOBALS)s);
if (!py_globals) goto bad;
- #if PY_MAJOR_VERSION < 3
- empty_string = PyString_FromStringAndSize("", 0);
- #else
- empty_string = PyBytes_FromStringAndSize("", 0);
- #endif
- if (!empty_string) goto bad;
py_code = PyCode_New(
0, /*int argcount,*/
#if PY_MAJOR_VERSION >= 3
0, /*int nlocals,*/
0, /*int stacksize,*/
0, /*int flags,*/
- empty_string, /*PyObject *code,*/
+ %(EMPTY_BYTES)s, /*PyObject *code,*/
%(EMPTY_TUPLE)s, /*PyObject *consts,*/
%(EMPTY_TUPLE)s, /*PyObject *names,*/
%(EMPTY_TUPLE)s, /*PyObject *varnames,*/
py_srcfile, /*PyObject *filename,*/
py_funcname, /*PyObject *name,*/
%(LINENO)s, /*int firstlineno,*/
- empty_string /*PyObject *lnotab*/
+ %(EMPTY_BYTES)s /*PyObject *lnotab*/
);
if (!py_code) goto bad;
py_frame = PyFrame_New(
bad:
Py_XDECREF(py_srcfile);
Py_XDECREF(py_funcname);
- Py_XDECREF(empty_string);
Py_XDECREF(py_code);
Py_XDECREF(py_frame);
}
'CLINENO': Naming.clineno_cname,
'GLOBALS': Naming.module_cname,
'EMPTY_TUPLE' : Naming.empty_tuple,
+ 'EMPTY_BYTES' : Naming.empty_bytes,
})
restore_exception_utility_code = UtilityCode(
#------------------------------------------------------------------------------------
+unraisable_exception_utility_code = UtilityCode(
+proto = """
+static void __Pyx_WriteUnraisable(const char *name); /*proto*/
+""",
+impl = """
+static void __Pyx_WriteUnraisable(const char *name) {
+ PyObject *old_exc, *old_val, *old_tb;
+ PyObject *ctx;
+ __Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
+ #if PY_MAJOR_VERSION < 3
+ ctx = PyString_FromString(name);
+ #else
+ ctx = PyUnicode_FromString(name);
+ #endif
+ __Pyx_ErrRestore(old_exc, old_val, old_tb);
+ if (!ctx) {
+ PyErr_WriteUnraisable(Py_None);
+ } else {
+ PyErr_WriteUnraisable(ctx);
+ Py_DECREF(ctx);
+ }
+}
+""",
+requires=[restore_exception_utility_code])
+
+#------------------------------------------------------------------------------------
+
set_vtable_utility_code = UtilityCode(
proto = """
static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
- __Pyx_ErrFetch(type, value, tb);
+ *type = tstate->curexc_type;
+ *value = tstate->curexc_value;
+ *tb = tstate->curexc_traceback;
+ tstate->curexc_type = 0;
+ tstate->curexc_value = 0;
+ tstate->curexc_traceback = 0;
PyErr_NormalizeException(type, value, tb);
if (PyErr_Occurred())
goto bad;
#------------------------------------------------------------------------------------
+get_exception_tuple_utility_code = UtilityCode(proto="""
+static PyObject *__Pyx_GetExceptionTuple(void); /*proto*/
+""",
+impl = """
+static PyObject *__Pyx_GetExceptionTuple(void) {
+ PyObject *type = NULL, *value = NULL, *tb = NULL;
+ if (__Pyx_GetException(&type, &value, &tb) == 0) {
+ PyObject* exc_info = PyTuple_New(3);
+ if (exc_info) {
+ Py_INCREF(type);
+ Py_INCREF(value);
+ Py_INCREF(tb);
+ PyTuple_SET_ITEM(exc_info, 0, type);
+ PyTuple_SET_ITEM(exc_info, 1, value);
+ PyTuple_SET_ITEM(exc_info, 2, tb);
+ return exc_info;
+ }
+ }
+ return NULL;
+}
+""",
+requires=[get_exception_utility_code])
+
+#------------------------------------------------------------------------------------
+
reset_exception_utility_code = UtilityCode(
proto = """
static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""")
#------------------------------------------------------------------------------------
+
+# Note that cPython ignores PyTrace_EXCEPTION,
+# but maybe some other profilers don't.
+
+profile_utility_code = UtilityCode(proto="""
+#ifndef CYTHON_PROFILE
+#define CYTHON_PROFILE 1
+#endif
+
+#ifndef CYTHON_PROFILE_REUSE_FRAME
+#define CYTHON_PROFILE_REUSE_FRAME 0
+#endif
+
+#if CYTHON_PROFILE
+
+#include "compile.h"
+#include "frameobject.h"
+#include "traceback.h"
+
+#if CYTHON_PROFILE_REUSE_FRAME
+#define CYTHON_FRAME_MODIFIER static
+#define CYTHON_FRAME_DEL
+#else
+#define CYTHON_FRAME_MODIFIER
+#define CYTHON_FRAME_DEL Py_DECREF(%(FRAME)s)
+#endif
+
+#define __Pyx_TraceCall(funcname, srcfile, firstlineno) \\
+static PyCodeObject *%(FRAME_CODE)s = NULL; \\
+CYTHON_FRAME_MODIFIER PyFrameObject *%(FRAME)s = NULL; \\
+int __Pyx_use_tracing = 0; \\
+if (unlikely(PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc)) { \\
+ __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&%(FRAME_CODE)s, &%(FRAME)s, funcname, srcfile, firstlineno); \\
+}
+
+#define __Pyx_TraceException() \\
+if (unlikely(__Pyx_use_tracing( && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) { \\
+ PyObject *exc_info = __Pyx_GetExceptionTuple(); \\
+ if (exc_info) { \\
+ PyThreadState_GET()->c_profilefunc( \\
+ PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_EXCEPTION, exc_info); \\
+ Py_DECREF(exc_info); \\
+ } \\
+}
+
+#define __Pyx_TraceReturn(result) \\
+if (unlikely(__Pyx_use_tracing) && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) { \\
+ PyThreadState_GET()->c_profilefunc( \\
+ PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_RETURN, (PyObject*)result); \\
+ CYTHON_FRAME_DEL; \\
+}
+
+static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno); /*proto*/
+static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, const char *funcname, const char *srcfile, int firstlineno); /*proto*/
+
+#else
+#define __Pyx_TraceCall(funcname, srcfile, firstlineno)
+#define __Pyx_TraceException()
+#define __Pyx_TraceReturn(result)
+#endif /* CYTHON_PROFILE */
+"""
+% {
+ "FRAME": Naming.frame_cname,
+ "FRAME_CODE": Naming.frame_code_cname,
+},
+impl = """
+
+#if CYTHON_PROFILE
+
+static int __Pyx_TraceSetupAndCall(PyCodeObject** code,
+ PyFrameObject** frame,
+ const char *funcname,
+ const char *srcfile,
+ int firstlineno) {
+ if (*frame == NULL || !CYTHON_PROFILE_REUSE_FRAME) {
+ if (*code == NULL) {
+ *code = __Pyx_createFrameCodeObject(funcname, srcfile, firstlineno);
+ if (*code == NULL) return 0;
+ }
+ *frame = PyFrame_New(
+ PyThreadState_GET(), /*PyThreadState *tstate*/
+ *code, /*PyCodeObject *code*/
+ PyModule_GetDict(%(MODULE)s), /*PyObject *globals*/
+ 0 /*PyObject *locals*/
+ );
+ if (*frame == NULL) return 0;
+ }
+ else {
+ (*frame)->f_tstate = PyThreadState_GET();
+ }
+ return PyThreadState_GET()->c_profilefunc(PyThreadState_GET()->c_profileobj, *frame, PyTrace_CALL, NULL) == 0;
+}
+
+static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno) {
+ PyObject *py_srcfile = 0;
+ PyObject *py_funcname = 0;
+ PyCodeObject *py_code = 0;
+
+ #if PY_MAJOR_VERSION < 3
+ py_funcname = PyString_FromString(funcname);
+ py_srcfile = PyString_FromString(srcfile);
+ #else
+ py_funcname = PyUnicode_FromString(funcname);
+ py_srcfile = PyUnicode_FromString(srcfile);
+ #endif
+ if (!py_funcname | !py_srcfile) goto bad;
+
+ py_code = PyCode_New(
+ 0, /*int argcount,*/
+ #if PY_MAJOR_VERSION >= 3
+ 0, /*int kwonlyargcount,*/
+ #endif
+ 0, /*int nlocals,*/
+ 0, /*int stacksize,*/
+ 0, /*int flags,*/
+ %(EMPTY_BYTES)s, /*PyObject *code,*/
+ %(EMPTY_TUPLE)s, /*PyObject *consts,*/
+ %(EMPTY_TUPLE)s, /*PyObject *names,*/
+ %(EMPTY_TUPLE)s, /*PyObject *varnames,*/
+ %(EMPTY_TUPLE)s, /*PyObject *freevars,*/
+ %(EMPTY_TUPLE)s, /*PyObject *cellvars,*/
+ py_srcfile, /*PyObject *filename,*/
+ py_funcname, /*PyObject *name,*/
+ firstlineno, /*int firstlineno,*/
+ %(EMPTY_BYTES)s /*PyObject *lnotab*/
+ );
+
+bad:
+ Py_XDECREF(py_srcfile);
+ Py_XDECREF(py_funcname);
+
+ return py_code;
+}
+
+#endif /* CYTHON_PROFILE */
+""" % {
+ 'EMPTY_TUPLE' : Naming.empty_tuple,
+ 'EMPTY_BYTES' : Naming.empty_bytes,
+ "MODULE": Naming.module_cname,
+})