summaryrefslogtreecommitdiffstats
path: root/contrib/tools/cython/Cython/Compiler/ExprNodes.py
diff options
context:
space:
mode:
authororivej <[email protected]>2022-02-10 16:45:01 +0300
committerDaniil Cherednik <[email protected]>2022-02-10 16:45:01 +0300
commit2d37894b1b037cf24231090eda8589bbb44fb6fc (patch)
treebe835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/tools/cython/Cython/Compiler/ExprNodes.py
parent718c552901d703c502ccbefdfc3c9028d608b947 (diff)
Restoring authorship annotation for <[email protected]>. Commit 2 of 2.
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler/ExprNodes.py')
-rw-r--r--contrib/tools/cython/Cython/Compiler/ExprNodes.py5444
1 files changed, 2722 insertions, 2722 deletions
diff --git a/contrib/tools/cython/Cython/Compiler/ExprNodes.py b/contrib/tools/cython/Cython/Compiler/ExprNodes.py
index 45938521c94..4a402f81262 100644
--- a/contrib/tools/cython/Cython/Compiler/ExprNodes.py
+++ b/contrib/tools/cython/Cython/Compiler/ExprNodes.py
@@ -13,12 +13,12 @@ cython.declare(error=object, warning=object, warn_once=object, InternalError=obj
unicode_type=object, str_type=object, bytes_type=object, type_type=object,
Builtin=object, Symtab=object, Utils=object, find_coercion_error=object,
debug_disposal_code=object, debug_temp_alloc=object, debug_coercion=object,
- bytearray_type=object, slice_type=object, _py_int_types=object,
- IS_PYTHON3=cython.bint)
+ bytearray_type=object, slice_type=object, _py_int_types=object,
+ IS_PYTHON3=cython.bint)
import re
-import sys
-import copy
+import sys
+import copy
import os.path
import operator
@@ -43,31 +43,31 @@ from . import Future
from ..Debugging import print_call_chain
from .DebugFlags import debug_disposal_code, debug_temp_alloc, \
debug_coercion
-from .Pythran import (to_pythran, is_pythran_supported_type, is_pythran_supported_operation_type,
- is_pythran_expr, pythran_func_type, pythran_binop_type, pythran_unaryop_type, has_np_pythran,
- pythran_indexing_code, pythran_indexing_type, is_pythran_supported_node_or_none, pythran_type,
- pythran_is_numpy_func_supported, pythran_get_func_include_file, pythran_functor)
+from .Pythran import (to_pythran, is_pythran_supported_type, is_pythran_supported_operation_type,
+ is_pythran_expr, pythran_func_type, pythran_binop_type, pythran_unaryop_type, has_np_pythran,
+ pythran_indexing_code, pythran_indexing_type, is_pythran_supported_node_or_none, pythran_type,
+ pythran_is_numpy_func_supported, pythran_get_func_include_file, pythran_functor)
from .PyrexTypes import PythranExpr
try:
from __builtin__ import basestring
except ImportError:
- # Python 3
- basestring = str
- any_string_type = (bytes, str)
-else:
- # Python 2
- any_string_type = (bytes, unicode)
-
-
-if sys.version_info[0] >= 3:
- IS_PYTHON3 = True
- _py_int_types = int
-else:
- IS_PYTHON3 = False
- _py_int_types = (int, long)
-
-
+ # Python 3
+ basestring = str
+ any_string_type = (bytes, str)
+else:
+ # Python 2
+ any_string_type = (bytes, unicode)
+
+
+if sys.version_info[0] >= 3:
+ IS_PYTHON3 = True
+ _py_int_types = int
+else:
+ IS_PYTHON3 = False
+ _py_int_types = (int, long)
+
+
class NotConstant(object):
_obj = None
@@ -86,46 +86,46 @@ constant_value_not_set = object()
# error messages when coercing from key[0] to key[1]
coercion_error_dict = {
# string related errors
- (unicode_type, str_type): ("Cannot convert Unicode string to 'str' implicitly."
- " This is not portable and requires explicit encoding."),
- (unicode_type, bytes_type): "Cannot convert Unicode string to 'bytes' implicitly, encoding required.",
- (unicode_type, PyrexTypes.c_char_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.",
- (unicode_type, PyrexTypes.c_const_char_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.",
- (unicode_type, PyrexTypes.c_uchar_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.",
- (unicode_type, PyrexTypes.c_const_uchar_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.",
- (bytes_type, unicode_type): "Cannot convert 'bytes' object to unicode implicitly, decoding required",
- (bytes_type, str_type): "Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.",
- (bytes_type, basestring_type): ("Cannot convert 'bytes' object to basestring implicitly."
- " This is not portable to Py3."),
- (bytes_type, PyrexTypes.c_py_unicode_ptr_type): "Cannot convert 'bytes' object to Py_UNICODE*, use 'unicode'.",
- (bytes_type, PyrexTypes.c_const_py_unicode_ptr_type): (
- "Cannot convert 'bytes' object to Py_UNICODE*, use 'unicode'."),
- (basestring_type, bytes_type): "Cannot convert 'basestring' object to bytes implicitly. This is not portable.",
- (str_type, unicode_type): ("str objects do not support coercion to unicode,"
- " use a unicode string literal instead (u'')"),
- (str_type, bytes_type): "Cannot convert 'str' to 'bytes' implicitly. This is not portable.",
- (str_type, PyrexTypes.c_char_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).",
- (str_type, PyrexTypes.c_const_char_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).",
- (str_type, PyrexTypes.c_uchar_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).",
- (str_type, PyrexTypes.c_const_uchar_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).",
- (str_type, PyrexTypes.c_py_unicode_ptr_type): "'str' objects do not support coercion to C types (use 'unicode'?).",
- (str_type, PyrexTypes.c_const_py_unicode_ptr_type): (
- "'str' objects do not support coercion to C types (use 'unicode'?)."),
- (PyrexTypes.c_char_ptr_type, unicode_type): "Cannot convert 'char*' to unicode implicitly, decoding required",
- (PyrexTypes.c_const_char_ptr_type, unicode_type): (
- "Cannot convert 'char*' to unicode implicitly, decoding required"),
- (PyrexTypes.c_uchar_ptr_type, unicode_type): "Cannot convert 'char*' to unicode implicitly, decoding required",
- (PyrexTypes.c_const_uchar_ptr_type, unicode_type): (
- "Cannot convert 'char*' to unicode implicitly, decoding required"),
+ (unicode_type, str_type): ("Cannot convert Unicode string to 'str' implicitly."
+ " This is not portable and requires explicit encoding."),
+ (unicode_type, bytes_type): "Cannot convert Unicode string to 'bytes' implicitly, encoding required.",
+ (unicode_type, PyrexTypes.c_char_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.",
+ (unicode_type, PyrexTypes.c_const_char_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.",
+ (unicode_type, PyrexTypes.c_uchar_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.",
+ (unicode_type, PyrexTypes.c_const_uchar_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.",
+ (bytes_type, unicode_type): "Cannot convert 'bytes' object to unicode implicitly, decoding required",
+ (bytes_type, str_type): "Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.",
+ (bytes_type, basestring_type): ("Cannot convert 'bytes' object to basestring implicitly."
+ " This is not portable to Py3."),
+ (bytes_type, PyrexTypes.c_py_unicode_ptr_type): "Cannot convert 'bytes' object to Py_UNICODE*, use 'unicode'.",
+ (bytes_type, PyrexTypes.c_const_py_unicode_ptr_type): (
+ "Cannot convert 'bytes' object to Py_UNICODE*, use 'unicode'."),
+ (basestring_type, bytes_type): "Cannot convert 'basestring' object to bytes implicitly. This is not portable.",
+ (str_type, unicode_type): ("str objects do not support coercion to unicode,"
+ " use a unicode string literal instead (u'')"),
+ (str_type, bytes_type): "Cannot convert 'str' to 'bytes' implicitly. This is not portable.",
+ (str_type, PyrexTypes.c_char_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).",
+ (str_type, PyrexTypes.c_const_char_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).",
+ (str_type, PyrexTypes.c_uchar_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).",
+ (str_type, PyrexTypes.c_const_uchar_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).",
+ (str_type, PyrexTypes.c_py_unicode_ptr_type): "'str' objects do not support coercion to C types (use 'unicode'?).",
+ (str_type, PyrexTypes.c_const_py_unicode_ptr_type): (
+ "'str' objects do not support coercion to C types (use 'unicode'?)."),
+ (PyrexTypes.c_char_ptr_type, unicode_type): "Cannot convert 'char*' to unicode implicitly, decoding required",
+ (PyrexTypes.c_const_char_ptr_type, unicode_type): (
+ "Cannot convert 'char*' to unicode implicitly, decoding required"),
+ (PyrexTypes.c_uchar_ptr_type, unicode_type): "Cannot convert 'char*' to unicode implicitly, decoding required",
+ (PyrexTypes.c_const_uchar_ptr_type, unicode_type): (
+ "Cannot convert 'char*' to unicode implicitly, decoding required"),
}
def find_coercion_error(type_tuple, default, env):
err = coercion_error_dict.get(type_tuple)
if err is None:
return default
- elif (env.directives['c_string_encoding'] and
- any(t in type_tuple for t in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_uchar_ptr_type,
- PyrexTypes.c_const_char_ptr_type, PyrexTypes.c_const_uchar_ptr_type))):
+ elif (env.directives['c_string_encoding'] and
+ any(t in type_tuple for t in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_uchar_ptr_type,
+ PyrexTypes.c_const_char_ptr_type, PyrexTypes.c_const_uchar_ptr_type))):
if type_tuple[1].is_pyobject:
return default
elif env.directives['c_string_encoding'] in ('ascii', 'default'):
@@ -151,9 +151,9 @@ def check_negative_indices(*nodes):
Used to find (potential) bugs inside of "wraparound=False" sections.
"""
for node in nodes:
- if node is None or (
- not isinstance(node.constant_result, _py_int_types) and
- not isinstance(node.constant_result, float)):
+ if node is None or (
+ not isinstance(node.constant_result, _py_int_types) and
+ not isinstance(node.constant_result, float)):
continue
if node.constant_result < 0:
warning(node.pos,
@@ -187,111 +187,111 @@ def infer_sequence_item_type(env, seq_node, index_node=None, seq_type=None):
return item_types.pop()
return None
-
-def make_dedup_key(outer_type, item_nodes):
- """
- Recursively generate a deduplication key from a sequence of values.
- Includes Cython node types to work around the fact that (1, 2.0) == (1.0, 2), for example.
-
- @param outer_type: The type of the outer container.
- @param item_nodes: A sequence of constant nodes that will be traversed recursively.
- @return: A tuple that can be used as a dict key for deduplication.
- """
- item_keys = [
- (py_object_type, None, type(None)) if node is None
- # For sequences and their "mult_factor", see TupleNode.
- else make_dedup_key(node.type, [node.mult_factor if node.is_literal else None] + node.args) if node.is_sequence_constructor
- else make_dedup_key(node.type, (node.start, node.stop, node.step)) if node.is_slice
- # For constants, look at the Python value type if we don't know the concrete Cython type.
- else (node.type, node.constant_result,
- type(node.constant_result) if node.type is py_object_type else None) if node.has_constant_result()
- else None # something we cannot handle => short-circuit below
- for node in item_nodes
- ]
- if None in item_keys:
- return None
- return outer_type, tuple(item_keys)
-
-
-# Returns a block of code to translate the exception,
-# plus a boolean indicating whether to check for Python exceptions.
-def get_exception_handler(exception_value):
- if exception_value is None:
- return "__Pyx_CppExn2PyErr();", False
- elif (exception_value.type == PyrexTypes.c_char_type
- and exception_value.value == '*'):
- return "__Pyx_CppExn2PyErr();", True
- elif exception_value.type.is_pyobject:
- return (
- 'try { throw; } catch(const std::exception& exn) {'
- 'PyErr_SetString(%s, exn.what());'
- '} catch(...) { PyErr_SetNone(%s); }' % (
- exception_value.entry.cname,
- exception_value.entry.cname),
- False)
- else:
- return (
- '%s(); if (!PyErr_Occurred())'
- 'PyErr_SetString(PyExc_RuntimeError, '
- '"Error converting c++ exception.");' % (
- exception_value.entry.cname),
- False)
-
-def maybe_check_py_error(code, check_py_exception, pos, nogil):
- if check_py_exception:
- if nogil:
- code.putln(code.error_goto_if("__Pyx_ErrOccurredWithGIL()", pos))
- else:
- code.putln(code.error_goto_if("PyErr_Occurred()", pos))
-
-def translate_cpp_exception(code, pos, inside, py_result, exception_value, nogil):
- raise_py_exception, check_py_exception = get_exception_handler(exception_value)
- code.putln("try {")
- code.putln("%s" % inside)
- if py_result:
- code.putln(code.error_goto_if_null(py_result, pos))
- maybe_check_py_error(code, check_py_exception, pos, nogil)
- code.putln("} catch(...) {")
- if nogil:
- code.put_ensure_gil(declare_gilstate=True)
- code.putln(raise_py_exception)
- if nogil:
- code.put_release_ensured_gil()
- code.putln(code.error_goto(pos))
- code.putln("}")
-
-# Used to handle the case where an lvalue expression and an overloaded assignment
-# both have an exception declaration.
-def translate_double_cpp_exception(code, pos, lhs_type, lhs_code, rhs_code,
- lhs_exc_val, assign_exc_val, nogil):
- handle_lhs_exc, lhc_check_py_exc = get_exception_handler(lhs_exc_val)
- handle_assignment_exc, assignment_check_py_exc = get_exception_handler(assign_exc_val)
- code.putln("try {")
- code.putln(lhs_type.declaration_code("__pyx_local_lvalue = %s;" % lhs_code))
- maybe_check_py_error(code, lhc_check_py_exc, pos, nogil)
- code.putln("try {")
- code.putln("__pyx_local_lvalue = %s;" % rhs_code)
- maybe_check_py_error(code, assignment_check_py_exc, pos, nogil)
- # Catch any exception from the overloaded assignment.
- code.putln("} catch(...) {")
- if nogil:
- code.put_ensure_gil(declare_gilstate=True)
- code.putln(handle_assignment_exc)
- if nogil:
- code.put_release_ensured_gil()
- code.putln(code.error_goto(pos))
- code.putln("}")
- # Catch any exception from evaluating lhs.
- code.putln("} catch(...) {")
- if nogil:
- code.put_ensure_gil(declare_gilstate=True)
- code.putln(handle_lhs_exc)
- if nogil:
- code.put_release_ensured_gil()
- code.putln(code.error_goto(pos))
- code.putln('}')
-
-
+
+def make_dedup_key(outer_type, item_nodes):
+ """
+ Recursively generate a deduplication key from a sequence of values.
+ Includes Cython node types to work around the fact that (1, 2.0) == (1.0, 2), for example.
+
+ @param outer_type: The type of the outer container.
+ @param item_nodes: A sequence of constant nodes that will be traversed recursively.
+ @return: A tuple that can be used as a dict key for deduplication.
+ """
+ item_keys = [
+ (py_object_type, None, type(None)) if node is None
+ # For sequences and their "mult_factor", see TupleNode.
+ else make_dedup_key(node.type, [node.mult_factor if node.is_literal else None] + node.args) if node.is_sequence_constructor
+ else make_dedup_key(node.type, (node.start, node.stop, node.step)) if node.is_slice
+ # For constants, look at the Python value type if we don't know the concrete Cython type.
+ else (node.type, node.constant_result,
+ type(node.constant_result) if node.type is py_object_type else None) if node.has_constant_result()
+ else None # something we cannot handle => short-circuit below
+ for node in item_nodes
+ ]
+ if None in item_keys:
+ return None
+ return outer_type, tuple(item_keys)
+
+
+# Returns a block of code to translate the exception,
+# plus a boolean indicating whether to check for Python exceptions.
+def get_exception_handler(exception_value):
+ if exception_value is None:
+ return "__Pyx_CppExn2PyErr();", False
+ elif (exception_value.type == PyrexTypes.c_char_type
+ and exception_value.value == '*'):
+ return "__Pyx_CppExn2PyErr();", True
+ elif exception_value.type.is_pyobject:
+ return (
+ 'try { throw; } catch(const std::exception& exn) {'
+ 'PyErr_SetString(%s, exn.what());'
+ '} catch(...) { PyErr_SetNone(%s); }' % (
+ exception_value.entry.cname,
+ exception_value.entry.cname),
+ False)
+ else:
+ return (
+ '%s(); if (!PyErr_Occurred())'
+ 'PyErr_SetString(PyExc_RuntimeError, '
+ '"Error converting c++ exception.");' % (
+ exception_value.entry.cname),
+ False)
+
+def maybe_check_py_error(code, check_py_exception, pos, nogil):
+ if check_py_exception:
+ if nogil:
+ code.putln(code.error_goto_if("__Pyx_ErrOccurredWithGIL()", pos))
+ else:
+ code.putln(code.error_goto_if("PyErr_Occurred()", pos))
+
+def translate_cpp_exception(code, pos, inside, py_result, exception_value, nogil):
+ raise_py_exception, check_py_exception = get_exception_handler(exception_value)
+ code.putln("try {")
+ code.putln("%s" % inside)
+ if py_result:
+ code.putln(code.error_goto_if_null(py_result, pos))
+ maybe_check_py_error(code, check_py_exception, pos, nogil)
+ code.putln("} catch(...) {")
+ if nogil:
+ code.put_ensure_gil(declare_gilstate=True)
+ code.putln(raise_py_exception)
+ if nogil:
+ code.put_release_ensured_gil()
+ code.putln(code.error_goto(pos))
+ code.putln("}")
+
+# Used to handle the case where an lvalue expression and an overloaded assignment
+# both have an exception declaration.
+def translate_double_cpp_exception(code, pos, lhs_type, lhs_code, rhs_code,
+ lhs_exc_val, assign_exc_val, nogil):
+ handle_lhs_exc, lhc_check_py_exc = get_exception_handler(lhs_exc_val)
+ handle_assignment_exc, assignment_check_py_exc = get_exception_handler(assign_exc_val)
+ code.putln("try {")
+ code.putln(lhs_type.declaration_code("__pyx_local_lvalue = %s;" % lhs_code))
+ maybe_check_py_error(code, lhc_check_py_exc, pos, nogil)
+ code.putln("try {")
+ code.putln("__pyx_local_lvalue = %s;" % rhs_code)
+ maybe_check_py_error(code, assignment_check_py_exc, pos, nogil)
+ # Catch any exception from the overloaded assignment.
+ code.putln("} catch(...) {")
+ if nogil:
+ code.put_ensure_gil(declare_gilstate=True)
+ code.putln(handle_assignment_exc)
+ if nogil:
+ code.put_release_ensured_gil()
+ code.putln(code.error_goto(pos))
+ code.putln("}")
+ # Catch any exception from evaluating lhs.
+ code.putln("} catch(...) {")
+ if nogil:
+ code.put_ensure_gil(declare_gilstate=True)
+ code.putln(handle_lhs_exc)
+ if nogil:
+ code.put_release_ensured_gil()
+ code.putln(code.error_goto(pos))
+ code.putln('}')
+
+
class ExprNode(Node):
# subexprs [string] Class var holding names of subexpr node attrs
# type PyrexType Type of the result
@@ -434,18 +434,18 @@ class ExprNode(Node):
is_sequence_constructor = False
is_dict_literal = False
- is_set_literal = False
+ is_set_literal = False
is_string_literal = False
is_attribute = False
is_subscript = False
- is_slice = False
-
- is_buffer_access = False
- is_memview_index = False
- is_memview_slice = False
- is_memview_broadcast = False
- is_memview_copy_assignment = False
-
+ is_slice = False
+
+ is_buffer_access = False
+ is_memview_index = False
+ is_memview_slice = False
+ is_memview_broadcast = False
+ is_memview_copy_assignment = False
+
saved_subexpr_nodes = None
is_temp = False
is_target = False
@@ -505,12 +505,12 @@ class ExprNode(Node):
assert(type_ is not None)
return to_pythran(self, type_)
- def is_c_result_required(self):
- """
- Subtypes may return False here if result temp allocation can be skipped.
- """
- return True
-
+ def is_c_result_required(self):
+ """
+ Subtypes may return False here if result temp allocation can be skipped.
+ """
+ return True
+
def result_as(self, type = None):
# Return the result code cast to the specified C type.
if (self.is_temp and self.type.is_pyobject and
@@ -635,14 +635,14 @@ class ExprNode(Node):
# can't be modified as part of globals or closures.
return self.is_literal or self.is_temp or self.type.is_array or self.type.is_cfunction
- def inferable_item_node(self, index=0):
- """
- Return a node that represents the (type) result of an indexing operation,
- e.g. for tuple unpacking or iteration.
- """
- return IndexNode(self.pos, base=self, index=IntNode(
- self.pos, value=str(index), constant_result=index, type=PyrexTypes.c_py_ssize_t_type))
-
+ def inferable_item_node(self, index=0):
+ """
+ Return a node that represents the (type) result of an indexing operation,
+ e.g. for tuple unpacking or iteration.
+ """
+ return IndexNode(self.pos, base=self, index=IntNode(
+ self.pos, value=str(index), constant_result=index, type=PyrexTypes.c_py_ssize_t_type))
+
# --------------- Type Analysis ------------------
def analyse_as_module(self, env):
@@ -718,9 +718,9 @@ class ExprNode(Node):
if not type.is_void:
if type.is_pyobject:
type = PyrexTypes.py_object_type
- elif not (self.result_is_used or type.is_memoryviewslice or self.is_c_result_required()):
- self.temp_code = None
- return
+ elif not (self.result_is_used or type.is_memoryviewslice or self.is_c_result_required()):
+ self.temp_code = None
+ return
self.temp_code = code.funcstate.allocate_temp(
type, manage_ref=self.use_managed_ref)
else:
@@ -796,8 +796,8 @@ class ExprNode(Node):
elif self.type.is_memoryviewslice:
code.put_xdecref_memoryviewslice(
self.result(), have_gil=not self.in_nogil_context)
- code.putln("%s.memview = NULL;" % self.result())
- code.putln("%s.data = NULL;" % self.result())
+ code.putln("%s.memview = NULL;" % self.result())
+ code.putln("%s.data = NULL;" % self.result())
else:
# Already done if self.is_temp
self.generate_subexpr_disposal_code(code)
@@ -822,8 +822,8 @@ class ExprNode(Node):
else:
self.generate_subexpr_disposal_code(code)
- def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
- exception_check=None, exception_value=None):
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
+ exception_check=None, exception_value=None):
# Stub method for nodes which are not legal as
# the LHS of an assignment. An error will have
# been reported earlier.
@@ -879,8 +879,8 @@ class ExprNode(Node):
if self.check_for_coercion_error(dst_type, env):
return self
- used_as_reference = dst_type.is_reference
- if used_as_reference and not src_type.is_reference:
+ used_as_reference = dst_type.is_reference
+ if used_as_reference and not src_type.is_reference:
dst_type = dst_type.ref_base_type
if src_type.is_const:
@@ -903,9 +903,9 @@ class ExprNode(Node):
if src_type.is_fused:
error(self.pos, "Type is not specialized")
- elif src_type.is_null_ptr and dst_type.is_ptr:
- # NULL can be implicitly cast to any pointer type
- return self
+ elif src_type.is_null_ptr and dst_type.is_ptr:
+ # NULL can be implicitly cast to any pointer type
+ return self
else:
error(self.pos, "Cannot coerce to a type that is not specialized")
@@ -923,10 +923,10 @@ class ExprNode(Node):
if src.type.is_pyobject:
src = CoerceToMemViewSliceNode(src, dst_type, env)
elif src.type.is_array:
- src = CythonArrayNode.from_carray(src, env).coerce_to(dst_type, env)
+ src = CythonArrayNode.from_carray(src, env).coerce_to(dst_type, env)
elif not src_type.is_error:
error(self.pos,
- "Cannot convert '%s' to memoryviewslice" % (src_type,))
+ "Cannot convert '%s' to memoryviewslice" % (src_type,))
else:
if src.type.writable_needed:
dst_type.writable_needed = True
@@ -961,10 +961,10 @@ class ExprNode(Node):
# Else, we need to convert the Pythran expression to a Python object
src = CoerceToPyTypeNode(src, env, type=dst_type)
elif src.type.is_pyobject:
- if used_as_reference and dst_type.is_cpp_class:
- warning(
- self.pos,
- "Cannot pass Python object as C++ data structure reference (%s &), will pass by copy." % dst_type)
+ if used_as_reference and dst_type.is_cpp_class:
+ warning(
+ self.pos,
+ "Cannot pass Python object as C++ data structure reference (%s &), will pass by copy." % dst_type)
src = CoerceFromPyTypeNode(dst_type, src, env)
elif (dst_type.is_complex
and src_type != dst_type
@@ -974,8 +974,8 @@ class ExprNode(Node):
# Added the string comparison, since for c types that
# is enough, but Cython gets confused when the types are
# in different pxi files.
- # TODO: Remove this hack and require shared declarations.
- if not (src.type == dst_type or str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)):
+ # TODO: Remove this hack and require shared declarations.
+ if not (src.type == dst_type or str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)):
self.fail_assignment(dst_type)
return src
@@ -1013,15 +1013,15 @@ class ExprNode(Node):
elif type.is_pyobject or type.is_int or type.is_ptr or type.is_float:
return CoerceToBooleanNode(self, env)
elif type.is_cpp_class and type.scope and type.scope.lookup("operator bool"):
- return SimpleCallNode(
- self.pos,
- function=AttributeNode(
+ return SimpleCallNode(
+ self.pos,
+ function=AttributeNode(
self.pos, obj=self, attribute=StringEncoding.EncodedString('operator bool')),
- args=[]).analyse_types(env)
- elif type.is_ctuple:
- bool_value = len(type.components) == 0
- return BoolNode(self.pos, value=bool_value,
- constant_result=bool_value)
+ args=[]).analyse_types(env)
+ elif type.is_ctuple:
+ bool_value = len(type.components) == 0
+ return BoolNode(self.pos, value=bool_value,
+ constant_result=bool_value)
else:
error(self.pos, "Type '%s' not acceptable as a boolean" % type)
return self
@@ -1209,10 +1209,10 @@ class BoolNode(ConstNode):
return str(int(self.value))
def coerce_to(self, dst_type, env):
- if dst_type == self.type:
- return self
- if dst_type is py_object_type and self.type is Builtin.bool_type:
- return self
+ if dst_type == self.type:
+ return self
+ if dst_type is py_object_type and self.type is Builtin.bool_type:
+ return self
if dst_type.is_pyobject and self.type.is_int:
return BoolNode(
self.pos, value=self.value,
@@ -1272,7 +1272,7 @@ class IntNode(ConstNode):
# we ignore 'is_c_literal = True' and instead map signed 32bit
# integers as C long values
if self.is_c_literal or \
- not self.has_constant_result() or \
+ not self.has_constant_result() or \
self.unsigned or self.longness == 'LL':
# clearly a C literal
rank = (self.longness == 'LL') and 2 or 1
@@ -1302,12 +1302,12 @@ class IntNode(ConstNode):
constant_result=not_a_constant)
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, is_c_literal=True,
+ 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, is_c_literal=False,
+ type=PyrexTypes.py_object_type, is_c_literal=False,
unsigned=self.unsigned, longness=self.longness)
else:
# FIXME: not setting the type here to keep it working with
@@ -1335,43 +1335,43 @@ class IntNode(ConstNode):
self.result_code = self.get_constant_c_result_code()
def get_constant_c_result_code(self):
- unsigned, longness = self.unsigned, self.longness
- literal = self.value_as_c_integer_string()
- if not (unsigned or longness) and self.type.is_int and literal[0] == '-' and literal[1] != '0':
- # negative decimal literal => guess longness from type to prevent wrap-around
- if self.type.rank >= PyrexTypes.c_longlong_type.rank:
- longness = 'LL'
- elif self.type.rank >= PyrexTypes.c_long_type.rank:
- longness = 'L'
- return literal + unsigned + longness
+ unsigned, longness = self.unsigned, self.longness
+ literal = self.value_as_c_integer_string()
+ if not (unsigned or longness) and self.type.is_int and literal[0] == '-' and literal[1] != '0':
+ # negative decimal literal => guess longness from type to prevent wrap-around
+ if self.type.rank >= PyrexTypes.c_longlong_type.rank:
+ longness = 'LL'
+ elif self.type.rank >= PyrexTypes.c_long_type.rank:
+ longness = 'L'
+ return literal + unsigned + longness
def value_as_c_integer_string(self):
value = self.value
- if len(value) <= 2:
- # too short to go wrong (and simplifies code below)
- return value
- neg_sign = ''
- if value[0] == '-':
- neg_sign = '-'
- value = value[1:]
- if value[0] == '0':
- literal_type = value[1] # 0'o' - 0'b' - 0'x'
- # 0x123 hex literals and 0123 octal literals work nicely in C
- # but C-incompatible Py3 oct/bin notations need conversion
- if neg_sign and literal_type in 'oOxX0123456789' and value[2:].isdigit():
- # negative hex/octal literal => prevent C compiler from using
- # unsigned integer types by converting to decimal (see C standard 6.4.4.1)
- value = str(Utils.str_to_number(value))
- elif literal_type in 'oO':
- value = '0' + value[2:] # '0o123' => '0123'
- elif literal_type in 'bB':
- value = str(int(value[2:], 2))
- elif value.isdigit() and not self.unsigned and not self.longness:
- if not neg_sign:
- # C compilers do not consider unsigned types for decimal literals,
- # but they do for hex (see C standard 6.4.4.1)
- value = '0x%X' % int(value)
- return neg_sign + value
+ if len(value) <= 2:
+ # too short to go wrong (and simplifies code below)
+ return value
+ neg_sign = ''
+ if value[0] == '-':
+ neg_sign = '-'
+ value = value[1:]
+ if value[0] == '0':
+ literal_type = value[1] # 0'o' - 0'b' - 0'x'
+ # 0x123 hex literals and 0123 octal literals work nicely in C
+ # but C-incompatible Py3 oct/bin notations need conversion
+ if neg_sign and literal_type in 'oOxX0123456789' and value[2:].isdigit():
+ # negative hex/octal literal => prevent C compiler from using
+ # unsigned integer types by converting to decimal (see C standard 6.4.4.1)
+ value = str(Utils.str_to_number(value))
+ elif literal_type in 'oO':
+ value = '0' + value[2:] # '0o123' => '0123'
+ elif literal_type in 'bB':
+ value = str(int(value[2:], 2))
+ elif value.isdigit() and not self.unsigned and not self.longness:
+ if not neg_sign:
+ # C compilers do not consider unsigned types for decimal literals,
+ # but they do for hex (see C standard 6.4.4.1)
+ value = '0x%X' % int(value)
+ return neg_sign + value
def calculate_result_code(self):
return self.result_code
@@ -1409,7 +1409,7 @@ class FloatNode(ConstNode):
def get_constant_c_result_code(self):
strval = self.value
- assert isinstance(strval, basestring)
+ assert isinstance(strval, basestring)
cmpval = repr(float(strval))
if cmpval == 'nan':
return "(Py_HUGE_VAL * 0)"
@@ -1433,12 +1433,12 @@ def _analyse_name_as_type(name, pos, env):
if type is not None:
return type
- global_entry = env.global_scope().lookup(name)
- if global_entry and global_entry.type and (
- global_entry.type.is_extension_type
- or global_entry.type.is_struct_or_union
- or global_entry.type.is_builtin_type
- or global_entry.type.is_cpp_class):
+ global_entry = env.global_scope().lookup(name)
+ if global_entry and global_entry.type and (
+ global_entry.type.is_extension_type
+ or global_entry.type.is_struct_or_union
+ or global_entry.type.is_builtin_type
+ or global_entry.type.is_cpp_class):
return global_entry.type
from .TreeFragment import TreeFragment
@@ -1470,11 +1470,11 @@ class BytesNode(ConstNode):
self.constant_result = self.value
def as_sliced_node(self, start, stop, step=None):
- value = StringEncoding.bytes_literal(self.value[start:stop:step], self.value.encoding)
- return BytesNode(self.pos, value=value, constant_result=value)
+ value = StringEncoding.bytes_literal(self.value[start:stop:step], self.value.encoding)
+ return BytesNode(self.pos, value=value, constant_result=value)
def compile_time_value(self, denv):
- return self.value.byteencode()
+ return self.value.byteencode()
def analyse_as_type(self, env):
return _analyse_name_as_type(self.value.decode('ISO8859-1'), self.pos, env)
@@ -1501,20 +1501,20 @@ class BytesNode(ConstNode):
return CharNode(self.pos, value=self.value,
constant_result=ord(self.value))
- node = BytesNode(self.pos, value=self.value, constant_result=self.constant_result)
+ node = BytesNode(self.pos, value=self.value, constant_result=self.constant_result)
if dst_type.is_pyobject:
if dst_type in (py_object_type, Builtin.bytes_type):
node.type = Builtin.bytes_type
else:
self.check_for_coercion_error(dst_type, env, fail=True)
return node
- elif dst_type in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_const_char_ptr_type):
+ elif dst_type in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_const_char_ptr_type):
node.type = dst_type
return node
- elif dst_type in (PyrexTypes.c_uchar_ptr_type, PyrexTypes.c_const_uchar_ptr_type, PyrexTypes.c_void_ptr_type):
- node.type = (PyrexTypes.c_const_char_ptr_type if dst_type == PyrexTypes.c_const_uchar_ptr_type
- else PyrexTypes.c_char_ptr_type)
- return CastNode(node, dst_type)
+ elif dst_type in (PyrexTypes.c_uchar_ptr_type, PyrexTypes.c_const_uchar_ptr_type, PyrexTypes.c_void_ptr_type):
+ node.type = (PyrexTypes.c_const_char_ptr_type if dst_type == PyrexTypes.c_const_uchar_ptr_type
+ else PyrexTypes.c_char_ptr_type)
+ return CastNode(node, dst_type)
elif dst_type.assignable_from(PyrexTypes.c_char_ptr_type):
# Exclude the case of passing a C string literal into a non-const C++ string.
if not dst_type.is_cpp_class or dst_type.is_const:
@@ -1528,15 +1528,15 @@ class BytesNode(ConstNode):
def generate_evaluation_code(self, code):
if self.type.is_pyobject:
- result = code.get_py_string_const(self.value)
- elif self.type.is_const:
- result = code.get_string_const(self.value)
+ result = code.get_py_string_const(self.value)
+ elif self.type.is_const:
+ result = code.get_string_const(self.value)
else:
- # not const => use plain C string literal and cast to mutable type
- literal = self.value.as_c_string_literal()
- # C++ may require a cast
- result = typecast(self.type, PyrexTypes.c_void_ptr_type, literal)
- self.result_code = result
+ # not const => use plain C string literal and cast to mutable type
+ literal = self.value.as_c_string_literal()
+ # C++ may require a cast
+ result = typecast(self.type, PyrexTypes.c_void_ptr_type, literal)
+ self.result_code = result
def get_constant_c_result_code(self):
return None # FIXME
@@ -1570,8 +1570,8 @@ class UnicodeNode(ConstNode):
value = StringEncoding.EncodedString(self.value[start:stop:step])
value.encoding = self.value.encoding
if self.bytes_value is not None:
- bytes_value = StringEncoding.bytes_literal(
- self.bytes_value[start:stop:step], self.bytes_value.encoding)
+ bytes_value = StringEncoding.bytes_literal(
+ self.bytes_value[start:stop:step], self.bytes_value.encoding)
else:
bytes_value = None
return UnicodeNode(
@@ -1634,17 +1634,17 @@ class UnicodeNode(ConstNode):
self.result_code = code.get_py_const(py_object_type, 'ustring')
data_cname = code.get_string_const(
StringEncoding.BytesLiteral(self.value.encode('unicode_escape')))
- const_code = code.get_cached_constants_writer(self.result_code)
- if const_code is None:
- return # already initialised
- const_code.mark_pos(self.pos)
- const_code.putln(
+ const_code = code.get_cached_constants_writer(self.result_code)
+ if const_code is None:
+ return # already initialised
+ const_code.mark_pos(self.pos)
+ const_code.putln(
"%s = PyUnicode_DecodeUnicodeEscape(%s, sizeof(%s) - 1, NULL); %s" % (
self.result_code,
data_cname,
data_cname,
- const_code.error_goto_if_null(self.result_code, self.pos)))
- const_code.put_error_if_neg(
+ const_code.error_goto_if_null(self.result_code, self.pos)))
+ const_code.put_error_if_neg(
self.pos, "__Pyx_PyUnicode_READY(%s)" % self.result_code)
else:
self.result_code = code.get_py_string_const(self.value)
@@ -1720,15 +1720,15 @@ class StringNode(PyConstNode):
return self.result_code
def compile_time_value(self, env):
- if self.value.is_unicode:
- return self.value
- if not IS_PYTHON3:
- # use plain str/bytes object in Py2
- return self.value.byteencode()
- # in Py3, always return a Unicode string
- if self.unicode_value is not None:
- return self.unicode_value
- return self.value.decode('iso8859-1')
+ if self.value.is_unicode:
+ return self.value
+ if not IS_PYTHON3:
+ # use plain str/bytes object in Py2
+ return self.value.byteencode()
+ # in Py3, always return a Unicode string
+ if self.unicode_value is not None:
+ return self.unicode_value
+ return self.value.decode('iso8859-1')
class IdentifierStringNode(StringNode):
@@ -1820,7 +1820,7 @@ class NewExprNode(AtomicExprNode):
pass
def calculate_result_code(self):
- return "new " + self.class_type.empty_declaration_code()
+ return "new " + self.class_type.empty_declaration_code()
class NameNode(AtomicExprNode):
@@ -2023,25 +2023,25 @@ class NameNode(AtomicExprNode):
def analyse_target_types(self, env):
self.analyse_entry(env, is_target=True)
- entry = self.entry
- if entry.is_cfunction and entry.as_variable:
- # FIXME: unify "is_overridable" flags below
- if (entry.is_overridable or entry.type.is_overridable) or not self.is_lvalue() and entry.fused_cfunction:
- # We need this for assigning to cpdef names and for the fused 'def' TreeFragment
- entry = self.entry = entry.as_variable
- self.type = entry.type
+ entry = self.entry
+ if entry.is_cfunction and entry.as_variable:
+ # FIXME: unify "is_overridable" flags below
+ if (entry.is_overridable or entry.type.is_overridable) or not self.is_lvalue() and entry.fused_cfunction:
+ # We need this for assigning to cpdef names and for the fused 'def' TreeFragment
+ entry = self.entry = entry.as_variable
+ self.type = entry.type
if self.type.is_const:
error(self.pos, "Assignment to const '%s'" % self.name)
if self.type.is_reference:
error(self.pos, "Assignment to reference '%s'" % self.name)
if not self.is_lvalue():
- error(self.pos, "Assignment to non-lvalue '%s'" % self.name)
+ error(self.pos, "Assignment to non-lvalue '%s'" % self.name)
self.type = PyrexTypes.error_type
- entry.used = 1
- if entry.type.is_buffer:
+ entry.used = 1
+ if entry.type.is_buffer:
from . import Buffer
- Buffer.used_buffer_aux_vars(entry)
+ Buffer.used_buffer_aux_vars(entry)
return self
def analyse_rvalue_entry(self, env):
@@ -2096,11 +2096,11 @@ class NameNode(AtomicExprNode):
entry = self.entry
if entry.is_type and entry.type.is_extension_type:
self.type_entry = entry
- if entry.is_type and entry.type.is_enum:
- py_entry = Symtab.Entry(self.name, None, py_object_type)
- py_entry.is_pyglobal = True
- py_entry.scope = self.entry.scope
- self.entry = py_entry
+ if entry.is_type and entry.type.is_enum:
+ py_entry = Symtab.Entry(self.name, None, py_object_type)
+ py_entry.is_pyglobal = True
+ py_entry.scope = self.entry.scope
+ self.entry = py_entry
elif not (entry.is_const or entry.is_variable or
entry.is_builtin or entry.is_cfunction or
entry.is_cpp_class):
@@ -2170,13 +2170,13 @@ class NameNode(AtomicExprNode):
return True
def is_lvalue(self):
- return (
- self.entry.is_variable and
+ return (
+ self.entry.is_variable and
not self.entry.is_readonly
- ) or (
- self.entry.is_cfunction and
- self.entry.is_overridable
- )
+ ) or (
+ self.entry.is_cfunction and
+ self.entry.is_overridable
+ )
def is_addressable(self):
return self.entry.is_variable and not self.type.is_memoryviewslice
@@ -2197,8 +2197,8 @@ class NameNode(AtomicExprNode):
entry = self.entry
if entry is None:
return # There was an error earlier
- if entry.utility_code:
- code.globalstate.use_utility_code(entry.utility_code)
+ if entry.utility_code:
+ code.globalstate.use_utility_code(entry.utility_code)
if entry.is_builtin and entry.is_const:
return # Lookup already cached
elif entry.is_pyclass_attr:
@@ -2219,7 +2219,7 @@ class NameNode(AtomicExprNode):
code.globalstate.use_utility_code(
UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c"))
code.putln(
- '__Pyx_GetModuleGlobalName(%s, %s);' % (
+ '__Pyx_GetModuleGlobalName(%s, %s);' % (
self.result(),
interned_cname))
if not self.cf_is_null:
@@ -2248,7 +2248,7 @@ class NameNode(AtomicExprNode):
code.globalstate.use_utility_code(
UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c"))
code.putln(
- '__Pyx_GetModuleGlobalName(%s, %s); %s' % (
+ '__Pyx_GetModuleGlobalName(%s, %s); %s' % (
self.result(),
interned_cname,
code.error_goto_if_null(self.result(), self.pos)))
@@ -2257,7 +2257,7 @@ class NameNode(AtomicExprNode):
code.globalstate.use_utility_code(
UtilityCode.load_cached("GetNameInClass", "ObjectHandling.c"))
code.putln(
- '__Pyx_GetNameInClass(%s, %s, %s); %s' % (
+ '__Pyx_GetNameInClass(%s, %s, %s); %s' % (
self.result(),
entry.scope.namespace_cname,
interned_cname,
@@ -2275,15 +2275,15 @@ class NameNode(AtomicExprNode):
if null_code and raise_unbound and (entry.type.is_pyobject or memslice_check):
code.put_error_if_unbound(self.pos, entry, self.in_nogil_context)
- def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
- exception_check=None, exception_value=None):
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
+ exception_check=None, exception_value=None):
#print "NameNode.generate_assignment_code:", self.name ###
entry = self.entry
if entry is None:
return # There was an error earlier
if (self.entry.type.is_ptr and isinstance(rhs, ListNode)
- and not self.lhs_of_first_assignment and not rhs.in_module_scope):
+ and not self.lhs_of_first_assignment and not rhs.in_module_scope):
error(self.pos, "Literal list must be assigned to pointer at time of declaration")
# is_pyglobal seems to be True for module level-globals only.
@@ -2367,22 +2367,22 @@ class NameNode(AtomicExprNode):
code.put_giveref(rhs.py_result())
if not self.type.is_memoryviewslice:
if not assigned:
- if overloaded_assignment:
- result = rhs.result()
- if exception_check == '+':
- translate_cpp_exception(
- code, self.pos,
- '%s = %s;' % (self.result(), result),
- self.result() if self.type.is_pyobject else None,
- exception_value, self.in_nogil_context)
- else:
- code.putln('%s = %s;' % (self.result(), result))
- else:
- result = rhs.result_as(self.ctype())
+ if overloaded_assignment:
+ result = rhs.result()
+ if exception_check == '+':
+ translate_cpp_exception(
+ code, self.pos,
+ '%s = %s;' % (self.result(), result),
+ self.result() if self.type.is_pyobject else None,
+ exception_value, self.in_nogil_context)
+ else:
+ code.putln('%s = %s;' % (self.result(), result))
+ else:
+ result = rhs.result_as(self.ctype())
if is_pythran_expr(self.type):
code.putln('new (&%s) decltype(%s){%s};' % (self.result(), self.result(), result))
- elif result != self.result():
+ elif result != self.result():
code.putln('%s = %s;' % (self.result(), result))
if debug_disposal_code:
print("NameNode.generate_assignment_code:")
@@ -2456,10 +2456,10 @@ class NameNode(AtomicExprNode):
del_code = '__Pyx_PyObject_DelAttrStr(%s, %s)' % (
Naming.module_cname, interned_cname)
if ignore_nonexisting:
- code.putln(
- 'if (unlikely(%s < 0)) {'
- ' if (likely(PyErr_ExceptionMatches(PyExc_AttributeError))) PyErr_Clear(); else %s '
- '}' % (del_code, code.error_goto(self.pos)))
+ code.putln(
+ 'if (unlikely(%s < 0)) {'
+ ' if (likely(PyErr_ExceptionMatches(PyExc_AttributeError))) PyErr_Clear(); else %s '
+ '}' % (del_code, code.error_goto(self.pos)))
else:
code.put_error_if_neg(self.pos, del_code)
elif self.entry.type.is_pyobject or self.entry.type.is_memoryviewslice:
@@ -2566,24 +2566,24 @@ class ImportNode(ExprNode):
name_list_code = self.name_list.py_result()
else:
name_list_code = "0"
-
- code.globalstate.use_utility_code(UtilityCode.load_cached("Import", "ImportExport.c"))
- import_code = "__Pyx_Import(%s, %s, %d)" % (
- self.module_name.py_result(),
- name_list_code,
- self.level)
-
- if (self.level <= 0 and
- self.module_name.is_string_literal and
- self.module_name.value in utility_code_for_imports):
- helper_func, code_name, code_file = utility_code_for_imports[self.module_name.value]
- code.globalstate.use_utility_code(UtilityCode.load_cached(code_name, code_file))
- import_code = '%s(%s)' % (helper_func, import_code)
-
- code.putln("%s = %s; %s" % (
- self.result(),
- import_code,
- code.error_goto_if_null(self.result(), self.pos)))
+
+ code.globalstate.use_utility_code(UtilityCode.load_cached("Import", "ImportExport.c"))
+ import_code = "__Pyx_Import(%s, %s, %d)" % (
+ self.module_name.py_result(),
+ name_list_code,
+ self.level)
+
+ if (self.level <= 0 and
+ self.module_name.is_string_literal and
+ self.module_name.value in utility_code_for_imports):
+ helper_func, code_name, code_file = utility_code_for_imports[self.module_name.value]
+ code.globalstate.use_utility_code(UtilityCode.load_cached(code_name, code_file))
+ import_code = '%s(%s)' % (helper_func, import_code)
+
+ code.putln("%s = %s; %s" % (
+ self.result(),
+ import_code,
+ code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
@@ -2599,7 +2599,7 @@ class IteratorNode(ExprNode):
counter_cname = None
cpp_iterator_cname = None
reversed = False # currently only used for list/tuple types (see Optimize.py)
- is_async = False
+ is_async = False
subexprs = ['sequence']
@@ -2613,7 +2613,7 @@ class IteratorNode(ExprNode):
self.analyse_cpp_types(env)
else:
self.sequence = self.sequence.coerce_to_pyobject(env)
- if self.sequence.type in (list_type, tuple_type):
+ if self.sequence.type in (list_type, tuple_type):
self.sequence = self.sequence.as_none_safe_node("'NoneType' object is not iterable")
self.is_temp = 1
return self
@@ -2701,8 +2701,8 @@ class IteratorNode(ExprNode):
return
if sequence_type.is_array or sequence_type.is_ptr:
raise InternalError("for in carray slice not transformed")
-
- is_builtin_sequence = sequence_type in (list_type, tuple_type)
+
+ is_builtin_sequence = sequence_type in (list_type, tuple_type)
if not is_builtin_sequence:
# reversed() not currently optimised (see Optimize.py)
assert not self.reversed, "internal error: reversed() only implemented for list/tuple objects"
@@ -2712,7 +2712,7 @@ class IteratorNode(ExprNode):
"if (likely(PyList_CheckExact(%s)) || PyTuple_CheckExact(%s)) {" % (
self.sequence.py_result(),
self.sequence.py_result()))
-
+
if is_builtin_sequence or self.may_be_a_sequence:
self.counter_cname = code.funcstate.allocate_temp(
PyrexTypes.c_py_ssize_t_type, manage_ref=False)
@@ -2723,25 +2723,25 @@ class IteratorNode(ExprNode):
init_value = 'PyTuple_GET_SIZE(%s) - 1' % self.result()
else:
init_value = '0'
- code.putln("%s = %s; __Pyx_INCREF(%s); %s = %s;" % (
- self.result(),
- self.sequence.py_result(),
- self.result(),
- self.counter_cname,
- init_value))
+ code.putln("%s = %s; __Pyx_INCREF(%s); %s = %s;" % (
+ self.result(),
+ self.sequence.py_result(),
+ self.result(),
+ self.counter_cname,
+ init_value))
if not is_builtin_sequence:
self.iter_func_ptr = code.funcstate.allocate_temp(self._func_iternext_type, manage_ref=False)
if self.may_be_a_sequence:
code.putln("%s = NULL;" % self.iter_func_ptr)
code.putln("} else {")
code.put("%s = -1; " % self.counter_cname)
-
+
code.putln("%s = PyObject_GetIter(%s); %s" % (
- self.result(),
- self.sequence.py_result(),
- code.error_goto_if_null(self.result(), self.pos)))
+ self.result(),
+ self.sequence.py_result(),
+ code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
-
+
# PyObject_GetIter() fails if "tp_iternext" is not set, but the check below
# makes it visible to the C compiler that the pointer really isn't NULL, so that
# it can distinguish between the special cases and the generic case
@@ -2758,14 +2758,14 @@ class IteratorNode(ExprNode):
item_count = len(self.sequence.args)
if self.sequence.mult_factor is None:
final_size = item_count
- elif isinstance(self.sequence.mult_factor.constant_result, _py_int_types):
+ elif isinstance(self.sequence.mult_factor.constant_result, _py_int_types):
final_size = item_count * self.sequence.mult_factor.constant_result
code.putln("if (%s >= %s) break;" % (self.counter_cname, final_size))
if self.reversed:
inc_dec = '--'
else:
inc_dec = '++'
- code.putln("#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS")
+ code.putln("#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS")
code.putln(
"%s = Py%s_GET_ITEM(%s, %s); __Pyx_INCREF(%s); %s%s; %s" % (
result_name,
@@ -2787,7 +2787,7 @@ class IteratorNode(ExprNode):
self.counter_cname,
inc_dec,
code.error_goto_if_null(result_name, self.pos)))
- code.put_gotref(result_name)
+ code.put_gotref(result_name)
code.putln("#endif")
def generate_iter_next_result_code(self, result_name, code):
@@ -2854,7 +2854,7 @@ class IteratorNode(ExprNode):
class NextNode(AtomicExprNode):
# Used as part of for statement implementation.
- # Implements result = next(iterator)
+ # Implements result = next(iterator)
# Created during analyse_types phase.
# The iterator is not owned by this node.
#
@@ -2864,14 +2864,14 @@ class NextNode(AtomicExprNode):
AtomicExprNode.__init__(self, iterator.pos)
self.iterator = iterator
- def nogil_check(self, env):
- # ignore - errors (if any) are already handled by IteratorNode
- pass
-
+ def nogil_check(self, env):
+ # ignore - errors (if any) are already handled by IteratorNode
+ pass
+
def type_dependencies(self, env):
return self.iterator.type_dependencies(env)
- def infer_type(self, env, iterator_type=None):
+ def infer_type(self, env, iterator_type=None):
if iterator_type is None:
iterator_type = self.iterator.infer_type(env)
if iterator_type.is_ptr or iterator_type.is_array:
@@ -2901,68 +2901,68 @@ class NextNode(AtomicExprNode):
self.iterator.generate_iter_next_result_code(self.result(), code)
-class AsyncIteratorNode(ExprNode):
- # Used as part of 'async for' statement implementation.
- #
- # Implements result = sequence.__aiter__()
- #
- # sequence ExprNode
-
- subexprs = ['sequence']
-
- is_async = True
- type = py_object_type
- is_temp = 1
-
- def infer_type(self, env):
- return py_object_type
-
- def analyse_types(self, env):
- self.sequence = self.sequence.analyse_types(env)
- if not self.sequence.type.is_pyobject:
- error(self.pos, "async for loops not allowed on C/C++ types")
- self.sequence = self.sequence.coerce_to_pyobject(env)
- return self
-
- def generate_result_code(self, code):
- code.globalstate.use_utility_code(UtilityCode.load_cached("AsyncIter", "Coroutine.c"))
- code.putln("%s = __Pyx_Coroutine_GetAsyncIter(%s); %s" % (
- self.result(),
- self.sequence.py_result(),
- code.error_goto_if_null(self.result(), self.pos)))
- code.put_gotref(self.result())
-
-
-class AsyncNextNode(AtomicExprNode):
- # Used as part of 'async for' statement implementation.
- # Implements result = iterator.__anext__()
- # Created during analyse_types phase.
- # The iterator is not owned by this node.
- #
- # iterator IteratorNode
-
- type = py_object_type
- is_temp = 1
-
- def __init__(self, iterator):
- AtomicExprNode.__init__(self, iterator.pos)
- self.iterator = iterator
-
- def infer_type(self, env):
- return py_object_type
-
- def analyse_types(self, env):
- return self
-
- def generate_result_code(self, code):
- code.globalstate.use_utility_code(UtilityCode.load_cached("AsyncIter", "Coroutine.c"))
- code.putln("%s = __Pyx_Coroutine_AsyncIterNext(%s); %s" % (
- self.result(),
- self.iterator.py_result(),
- code.error_goto_if_null(self.result(), self.pos)))
- code.put_gotref(self.result())
-
-
+class AsyncIteratorNode(ExprNode):
+ # Used as part of 'async for' statement implementation.
+ #
+ # Implements result = sequence.__aiter__()
+ #
+ # sequence ExprNode
+
+ subexprs = ['sequence']
+
+ is_async = True
+ type = py_object_type
+ is_temp = 1
+
+ def infer_type(self, env):
+ return py_object_type
+
+ def analyse_types(self, env):
+ self.sequence = self.sequence.analyse_types(env)
+ if not self.sequence.type.is_pyobject:
+ error(self.pos, "async for loops not allowed on C/C++ types")
+ self.sequence = self.sequence.coerce_to_pyobject(env)
+ return self
+
+ def generate_result_code(self, code):
+ code.globalstate.use_utility_code(UtilityCode.load_cached("AsyncIter", "Coroutine.c"))
+ code.putln("%s = __Pyx_Coroutine_GetAsyncIter(%s); %s" % (
+ self.result(),
+ self.sequence.py_result(),
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.result())
+
+
+class AsyncNextNode(AtomicExprNode):
+ # Used as part of 'async for' statement implementation.
+ # Implements result = iterator.__anext__()
+ # Created during analyse_types phase.
+ # The iterator is not owned by this node.
+ #
+ # iterator IteratorNode
+
+ type = py_object_type
+ is_temp = 1
+
+ def __init__(self, iterator):
+ AtomicExprNode.__init__(self, iterator.pos)
+ self.iterator = iterator
+
+ def infer_type(self, env):
+ return py_object_type
+
+ def analyse_types(self, env):
+ return self
+
+ def generate_result_code(self, code):
+ code.globalstate.use_utility_code(UtilityCode.load_cached("AsyncIter", "Coroutine.c"))
+ code.putln("%s = __Pyx_Coroutine_AsyncIterNext(%s); %s" % (
+ self.result(),
+ self.iterator.py_result(),
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.result())
+
+
class WithExitCallNode(ExprNode):
# The __exit__() call of a 'with' statement. Used in both the
# except and finally clauses.
@@ -3004,14 +3004,14 @@ class WithExitCallNode(ExprNode):
code.putln(code.error_goto_if_null(result_var, self.pos))
code.put_gotref(result_var)
-
+
if self.await_expr:
- # FIXME: result_var temp currently leaks into the closure
+ # FIXME: result_var temp currently leaks into the closure
self.await_expr.generate_evaluation_code(code, source_cname=result_var, decref_source=True)
code.putln("%s = %s;" % (result_var, self.await_expr.py_result()))
self.await_expr.generate_post_assignment_code(code)
self.await_expr.free_temps(code)
-
+
if self.result_is_used:
self.allocate_temp_result(code)
code.putln("%s = __Pyx_PyObject_IsTrue(%s);" % (self.result(), result_var))
@@ -3123,59 +3123,59 @@ class RawCNameExprNode(ExprNode):
#-------------------------------------------------------------------
#
-# F-strings
-#
-#-------------------------------------------------------------------
-
-
-class JoinedStrNode(ExprNode):
- # F-strings
- #
- # values [UnicodeNode|FormattedValueNode] Substrings of the f-string
- #
- type = unicode_type
- is_temp = True
-
- subexprs = ['values']
-
- def analyse_types(self, env):
- self.values = [v.analyse_types(env).coerce_to_pyobject(env) for v in self.values]
- return self
-
- def may_be_none(self):
- # PyUnicode_Join() always returns a Unicode string or raises an exception
- return False
-
- def generate_evaluation_code(self, code):
- code.mark_pos(self.pos)
- num_items = len(self.values)
- list_var = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
- ulength_var = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False)
- max_char_var = code.funcstate.allocate_temp(PyrexTypes.c_py_ucs4_type, manage_ref=False)
-
- code.putln('%s = PyTuple_New(%s); %s' % (
- list_var,
- num_items,
- code.error_goto_if_null(list_var, self.pos)))
- code.put_gotref(list_var)
- code.putln("%s = 0;" % ulength_var)
- code.putln("%s = 127;" % max_char_var) # at least ASCII character range
-
- for i, node in enumerate(self.values):
- node.generate_evaluation_code(code)
- node.make_owned_reference(code)
-
- ulength = "__Pyx_PyUnicode_GET_LENGTH(%s)" % node.py_result()
- max_char_value = "__Pyx_PyUnicode_MAX_CHAR_VALUE(%s)" % node.py_result()
- is_ascii = False
- if isinstance(node, UnicodeNode):
- try:
+# F-strings
+#
+#-------------------------------------------------------------------
+
+
+class JoinedStrNode(ExprNode):
+ # F-strings
+ #
+ # values [UnicodeNode|FormattedValueNode] Substrings of the f-string
+ #
+ type = unicode_type
+ is_temp = True
+
+ subexprs = ['values']
+
+ def analyse_types(self, env):
+ self.values = [v.analyse_types(env).coerce_to_pyobject(env) for v in self.values]
+ return self
+
+ def may_be_none(self):
+ # PyUnicode_Join() always returns a Unicode string or raises an exception
+ return False
+
+ def generate_evaluation_code(self, code):
+ code.mark_pos(self.pos)
+ num_items = len(self.values)
+ list_var = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
+ ulength_var = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False)
+ max_char_var = code.funcstate.allocate_temp(PyrexTypes.c_py_ucs4_type, manage_ref=False)
+
+ code.putln('%s = PyTuple_New(%s); %s' % (
+ list_var,
+ num_items,
+ code.error_goto_if_null(list_var, self.pos)))
+ code.put_gotref(list_var)
+ code.putln("%s = 0;" % ulength_var)
+ code.putln("%s = 127;" % max_char_var) # at least ASCII character range
+
+ for i, node in enumerate(self.values):
+ node.generate_evaluation_code(code)
+ node.make_owned_reference(code)
+
+ ulength = "__Pyx_PyUnicode_GET_LENGTH(%s)" % node.py_result()
+ max_char_value = "__Pyx_PyUnicode_MAX_CHAR_VALUE(%s)" % node.py_result()
+ is_ascii = False
+ if isinstance(node, UnicodeNode):
+ try:
# most strings will be ASCII or at least Latin-1
- node.value.encode('iso8859-1')
- max_char_value = '255'
- node.value.encode('us-ascii')
- is_ascii = True
- except UnicodeEncodeError:
+ node.value.encode('iso8859-1')
+ max_char_value = '255'
+ node.value.encode('us-ascii')
+ is_ascii = True
+ except UnicodeEncodeError:
if max_char_value != '255':
# not ISO8859-1 => check BMP limit
max_char = max(map(ord, node.value))
@@ -3191,133 +3191,133 @@ class JoinedStrNode(ExprNode):
# not really worth implementing a check for surrogate pairs here
# drawback: C code can differ when generating on Py2 with 2-byte Unicode
pass
- else:
- ulength = str(len(node.value))
- elif isinstance(node, FormattedValueNode) and node.value.type.is_numeric:
- is_ascii = True # formatted C numbers are always ASCII
-
- if not is_ascii:
- code.putln("%s = (%s > %s) ? %s : %s;" % (
- max_char_var, max_char_value, max_char_var, max_char_value, max_char_var))
- code.putln("%s += %s;" % (ulength_var, ulength))
-
- code.put_giveref(node.py_result())
- code.putln('PyTuple_SET_ITEM(%s, %s, %s);' % (list_var, i, node.py_result()))
- node.generate_post_assignment_code(code)
- node.free_temps(code)
-
- code.mark_pos(self.pos)
- self.allocate_temp_result(code)
- code.globalstate.use_utility_code(UtilityCode.load_cached("JoinPyUnicode", "StringTools.c"))
- code.putln('%s = __Pyx_PyUnicode_Join(%s, %d, %s, %s); %s' % (
- self.result(),
- list_var,
- num_items,
- ulength_var,
- max_char_var,
- code.error_goto_if_null(self.py_result(), self.pos)))
- code.put_gotref(self.py_result())
-
- code.put_decref_clear(list_var, py_object_type)
- code.funcstate.release_temp(list_var)
- code.funcstate.release_temp(ulength_var)
- code.funcstate.release_temp(max_char_var)
-
-
-class FormattedValueNode(ExprNode):
- # {}-delimited portions of an f-string
- #
- # value ExprNode The expression itself
+ else:
+ ulength = str(len(node.value))
+ elif isinstance(node, FormattedValueNode) and node.value.type.is_numeric:
+ is_ascii = True # formatted C numbers are always ASCII
+
+ if not is_ascii:
+ code.putln("%s = (%s > %s) ? %s : %s;" % (
+ max_char_var, max_char_value, max_char_var, max_char_value, max_char_var))
+ code.putln("%s += %s;" % (ulength_var, ulength))
+
+ code.put_giveref(node.py_result())
+ code.putln('PyTuple_SET_ITEM(%s, %s, %s);' % (list_var, i, node.py_result()))
+ node.generate_post_assignment_code(code)
+ node.free_temps(code)
+
+ code.mark_pos(self.pos)
+ self.allocate_temp_result(code)
+ code.globalstate.use_utility_code(UtilityCode.load_cached("JoinPyUnicode", "StringTools.c"))
+ code.putln('%s = __Pyx_PyUnicode_Join(%s, %d, %s, %s); %s' % (
+ self.result(),
+ list_var,
+ num_items,
+ ulength_var,
+ max_char_var,
+ code.error_goto_if_null(self.py_result(), self.pos)))
+ code.put_gotref(self.py_result())
+
+ code.put_decref_clear(list_var, py_object_type)
+ code.funcstate.release_temp(list_var)
+ code.funcstate.release_temp(ulength_var)
+ code.funcstate.release_temp(max_char_var)
+
+
+class FormattedValueNode(ExprNode):
+ # {}-delimited portions of an f-string
+ #
+ # value ExprNode The expression itself
# conversion_char str or None Type conversion (!s, !r, !a, or none, or 'd' for integer conversion)
- # format_spec JoinedStrNode or None Format string passed to __format__
- # c_format_spec str or None If not None, formatting can be done at the C level
-
- subexprs = ['value', 'format_spec']
-
- type = unicode_type
- is_temp = True
- c_format_spec = None
-
- find_conversion_func = {
- 's': 'PyObject_Unicode',
- 'r': 'PyObject_Repr',
- 'a': 'PyObject_ASCII', # NOTE: mapped to PyObject_Repr() in Py2
+ # format_spec JoinedStrNode or None Format string passed to __format__
+ # c_format_spec str or None If not None, formatting can be done at the C level
+
+ subexprs = ['value', 'format_spec']
+
+ type = unicode_type
+ is_temp = True
+ c_format_spec = None
+
+ find_conversion_func = {
+ 's': 'PyObject_Unicode',
+ 'r': 'PyObject_Repr',
+ 'a': 'PyObject_ASCII', # NOTE: mapped to PyObject_Repr() in Py2
'd': '__Pyx_PyNumber_IntOrLong', # NOTE: internal mapping for '%d' formatting
- }.get
-
- def may_be_none(self):
- # PyObject_Format() always returns a Unicode string or raises an exception
- return False
-
- def analyse_types(self, env):
- self.value = self.value.analyse_types(env)
- if not self.format_spec or self.format_spec.is_string_literal:
- c_format_spec = self.format_spec.value if self.format_spec else self.value.type.default_format_spec
- if self.value.type.can_coerce_to_pystring(env, format_spec=c_format_spec):
- self.c_format_spec = c_format_spec
-
- if self.format_spec:
- self.format_spec = self.format_spec.analyse_types(env).coerce_to_pyobject(env)
- if self.c_format_spec is None:
- self.value = self.value.coerce_to_pyobject(env)
+ }.get
+
+ def may_be_none(self):
+ # PyObject_Format() always returns a Unicode string or raises an exception
+ return False
+
+ def analyse_types(self, env):
+ self.value = self.value.analyse_types(env)
+ if not self.format_spec or self.format_spec.is_string_literal:
+ c_format_spec = self.format_spec.value if self.format_spec else self.value.type.default_format_spec
+ if self.value.type.can_coerce_to_pystring(env, format_spec=c_format_spec):
+ self.c_format_spec = c_format_spec
+
+ if self.format_spec:
+ self.format_spec = self.format_spec.analyse_types(env).coerce_to_pyobject(env)
+ if self.c_format_spec is None:
+ self.value = self.value.coerce_to_pyobject(env)
if not self.format_spec and (not self.conversion_char or self.conversion_char == 's'):
- if self.value.type is unicode_type and not self.value.may_be_none():
- # value is definitely a unicode string and we don't format it any special
- return self.value
- return self
-
- def generate_result_code(self, code):
- if self.c_format_spec is not None and not self.value.type.is_pyobject:
- convert_func_call = self.value.type.convert_to_pystring(
- self.value.result(), code, self.c_format_spec)
- code.putln("%s = %s; %s" % (
- self.result(),
- convert_func_call,
- code.error_goto_if_null(self.result(), self.pos)))
- code.put_gotref(self.py_result())
- return
-
- value_result = self.value.py_result()
- value_is_unicode = self.value.type is unicode_type and not self.value.may_be_none()
- if self.format_spec:
- format_func = '__Pyx_PyObject_Format'
- format_spec = self.format_spec.py_result()
- else:
- # common case: expect simple Unicode pass-through if no format spec
- format_func = '__Pyx_PyObject_FormatSimple'
- # passing a Unicode format string in Py2 forces PyObject_Format() to also return a Unicode string
- format_spec = Naming.empty_unicode
-
- conversion_char = self.conversion_char
- if conversion_char == 's' and value_is_unicode:
- # no need to pipe unicode strings through str()
- conversion_char = None
-
- if conversion_char:
- fn = self.find_conversion_func(conversion_char)
- assert fn is not None, "invalid conversion character found: '%s'" % conversion_char
- value_result = '%s(%s)' % (fn, value_result)
- code.globalstate.use_utility_code(
- UtilityCode.load_cached("PyObjectFormatAndDecref", "StringTools.c"))
- format_func += 'AndDecref'
- elif self.format_spec:
- code.globalstate.use_utility_code(
- UtilityCode.load_cached("PyObjectFormat", "StringTools.c"))
- else:
- code.globalstate.use_utility_code(
- UtilityCode.load_cached("PyObjectFormatSimple", "StringTools.c"))
-
- code.putln("%s = %s(%s, %s); %s" % (
- self.result(),
- format_func,
- value_result,
- format_spec,
- code.error_goto_if_null(self.result(), self.pos)))
- code.put_gotref(self.py_result())
-
-
-#-------------------------------------------------------------------
-#
+ if self.value.type is unicode_type and not self.value.may_be_none():
+ # value is definitely a unicode string and we don't format it any special
+ return self.value
+ return self
+
+ def generate_result_code(self, code):
+ if self.c_format_spec is not None and not self.value.type.is_pyobject:
+ convert_func_call = self.value.type.convert_to_pystring(
+ self.value.result(), code, self.c_format_spec)
+ code.putln("%s = %s; %s" % (
+ self.result(),
+ convert_func_call,
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.py_result())
+ return
+
+ value_result = self.value.py_result()
+ value_is_unicode = self.value.type is unicode_type and not self.value.may_be_none()
+ if self.format_spec:
+ format_func = '__Pyx_PyObject_Format'
+ format_spec = self.format_spec.py_result()
+ else:
+ # common case: expect simple Unicode pass-through if no format spec
+ format_func = '__Pyx_PyObject_FormatSimple'
+ # passing a Unicode format string in Py2 forces PyObject_Format() to also return a Unicode string
+ format_spec = Naming.empty_unicode
+
+ conversion_char = self.conversion_char
+ if conversion_char == 's' and value_is_unicode:
+ # no need to pipe unicode strings through str()
+ conversion_char = None
+
+ if conversion_char:
+ fn = self.find_conversion_func(conversion_char)
+ assert fn is not None, "invalid conversion character found: '%s'" % conversion_char
+ value_result = '%s(%s)' % (fn, value_result)
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached("PyObjectFormatAndDecref", "StringTools.c"))
+ format_func += 'AndDecref'
+ elif self.format_spec:
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached("PyObjectFormat", "StringTools.c"))
+ else:
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached("PyObjectFormatSimple", "StringTools.c"))
+
+ code.putln("%s = %s(%s, %s); %s" % (
+ self.result(),
+ format_func,
+ value_result,
+ format_spec,
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.py_result())
+
+
+#-------------------------------------------------------------------
+#
# Parallel nodes (cython.parallel.thread(savailable|id))
#
#-------------------------------------------------------------------
@@ -3380,38 +3380,38 @@ class ParallelThreadIdNode(AtomicExprNode): #, Nodes.ParallelNode):
#
#-------------------------------------------------------------------
-
-class _IndexingBaseNode(ExprNode):
- # Base class for indexing nodes.
- #
- # base ExprNode the value being indexed
-
- def is_ephemeral(self):
- # in most cases, indexing will return a safe reference to an object in a container,
- # so we consider the result safe if the base object is
- return self.base.is_ephemeral() or self.base.type in (
+
+class _IndexingBaseNode(ExprNode):
+ # Base class for indexing nodes.
+ #
+ # base ExprNode the value being indexed
+
+ def is_ephemeral(self):
+ # in most cases, indexing will return a safe reference to an object in a container,
+ # so we consider the result safe if the base object is
+ return self.base.is_ephemeral() or self.base.type in (
basestring_type, str_type, bytes_type, bytearray_type, unicode_type)
-
- def check_const_addr(self):
- return self.base.check_const_addr() and self.index.check_const()
-
- def is_lvalue(self):
- # NOTE: references currently have both is_reference and is_ptr
- # set. Since pointers and references have different lvalue
- # rules, we must be careful to separate the two.
- if self.type.is_reference:
- if self.type.ref_base_type.is_array:
- # fixed-sized arrays aren't l-values
- return False
- elif self.type.is_ptr:
- # non-const pointers can always be reassigned
- return True
- # Just about everything else returned by the index operator
- # can be an lvalue.
- return True
-
-
-class IndexNode(_IndexingBaseNode):
+
+ def check_const_addr(self):
+ return self.base.check_const_addr() and self.index.check_const()
+
+ def is_lvalue(self):
+ # NOTE: references currently have both is_reference and is_ptr
+ # set. Since pointers and references have different lvalue
+ # rules, we must be careful to separate the two.
+ if self.type.is_reference:
+ if self.type.ref_base_type.is_array:
+ # fixed-sized arrays aren't l-values
+ return False
+ elif self.type.is_ptr:
+ # non-const pointers can always be reassigned
+ return True
+ # Just about everything else returned by the index operator
+ # can be an lvalue.
+ return True
+
+
+class IndexNode(_IndexingBaseNode):
# Sequence indexing.
#
# base ExprNode
@@ -3421,21 +3421,21 @@ class IndexNode(_IndexingBaseNode):
# is_fused_index boolean Whether the index is used to specialize a
# c(p)def function
- subexprs = ['base', 'index']
+ subexprs = ['base', 'index']
type_indices = None
is_subscript = True
is_fused_index = False
def calculate_constant_result(self):
- self.constant_result = self.base.constant_result[self.index.constant_result]
+ self.constant_result = self.base.constant_result[self.index.constant_result]
def compile_time_value(self, denv):
base = self.base.compile_time_value(denv)
index = self.index.compile_time_value(denv)
try:
return base[index]
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def is_simple(self):
@@ -3467,26 +3467,26 @@ class IndexNode(_IndexingBaseNode):
else:
template_values = [self.index]
type_node = Nodes.TemplatedTypeNode(
- pos=self.pos,
- positional_args=template_values,
- keyword_args=None)
- return type_node.analyse(env, base_type=base_type)
- elif self.index.is_slice or self.index.is_sequence_constructor:
- # memory view
- from . import MemoryView
- env.use_utility_code(MemoryView.view_utility_code)
- axes = [self.index] if self.index.is_slice else list(self.index.args)
- return PyrexTypes.MemoryViewSliceType(base_type, MemoryView.get_axes_specs(env, axes))
+ pos=self.pos,
+ positional_args=template_values,
+ keyword_args=None)
+ return type_node.analyse(env, base_type=base_type)
+ elif self.index.is_slice or self.index.is_sequence_constructor:
+ # memory view
+ from . import MemoryView
+ env.use_utility_code(MemoryView.view_utility_code)
+ axes = [self.index] if self.index.is_slice else list(self.index.args)
+ return PyrexTypes.MemoryViewSliceType(base_type, MemoryView.get_axes_specs(env, axes))
else:
- # C array
+ # C array
index = self.index.compile_time_value(env)
if index is not None:
- try:
- index = int(index)
- except (ValueError, TypeError):
- pass
- else:
- return PyrexTypes.CArrayType(base_type, index)
+ try:
+ index = int(index)
+ except (ValueError, TypeError):
+ pass
+ else:
+ return PyrexTypes.CArrayType(base_type, index)
error(self.pos, "Array size must be a compile time constant")
return None
@@ -3495,7 +3495,7 @@ class IndexNode(_IndexingBaseNode):
def infer_type(self, env):
base_type = self.base.infer_type(env)
- if self.index.is_slice:
+ if self.index.is_slice:
# slicing!
if base_type.is_string:
# sliced C strings must coerce to Python
@@ -3542,13 +3542,13 @@ class IndexNode(_IndexingBaseNode):
return item_type
elif base_type.is_ptr or base_type.is_array:
return base_type.base_type
- elif base_type.is_ctuple and isinstance(self.index, IntNode):
- if self.index.has_constant_result():
- index = self.index.constant_result
- if index < 0:
- index += base_type.size
- if 0 <= index < base_type.size:
- return base_type.components[index]
+ elif base_type.is_ctuple and isinstance(self.index, IntNode):
+ if self.index.has_constant_result():
+ index = self.index.constant_result
+ if index < 0:
+ index += base_type.size
+ if 0 <= index < base_type.size:
+ return base_type.components[index]
if base_type.is_cpp_class:
class FakeOperand:
@@ -3581,7 +3581,7 @@ class IndexNode(_IndexingBaseNode):
node = self.analyse_base_and_index_types(env, setting=True)
if node.type.is_const:
error(self.pos, "Assignment to const dereference")
- if node is self and not node.is_lvalue():
+ if node is self and not node.is_lvalue():
error(self.pos, "Assignment to non-lvalue of type '%s'" % node.type)
return node
@@ -3599,7 +3599,7 @@ class IndexNode(_IndexingBaseNode):
self.type = PyrexTypes.error_type
return self
- is_slice = self.index.is_slice
+ is_slice = self.index.is_slice
if not env.directives['wraparound']:
if is_slice:
check_negative_indices(self.index.start, self.index.stop)
@@ -3616,16 +3616,16 @@ class IndexNode(_IndexingBaseNode):
if self.base.type.is_string or not (self.base.type.is_ptr or self.base.type.is_array):
self.base = self.base.coerce_to_pyobject(env)
- replacement_node = self.analyse_as_buffer_operation(env, getting)
- if replacement_node is not None:
- return replacement_node
+ replacement_node = self.analyse_as_buffer_operation(env, getting)
+ if replacement_node is not None:
+ return replacement_node
self.nogil = env.nogil
- base_type = self.base.type
+ base_type = self.base.type
- if not base_type.is_cfunction:
- self.index = self.index.analyse_types(env)
- self.original_index_type = self.index.type
+ if not base_type.is_cfunction:
+ self.index = self.index.analyse_types(env)
+ self.original_index_type = self.index.type
if base_type.is_unicode_char:
# we infer Py_UNICODE/Py_UCS4 for unicode strings in some
@@ -3637,26 +3637,26 @@ class IndexNode(_IndexingBaseNode):
return self.base
self.base = self.base.coerce_to_pyobject(env)
base_type = self.base.type
-
- if base_type.is_pyobject:
- return self.analyse_as_pyobject(env, is_slice, getting, setting)
- elif base_type.is_ptr or base_type.is_array:
- return self.analyse_as_c_array(env, is_slice)
- elif base_type.is_cpp_class:
- return self.analyse_as_cpp(env, setting)
- elif base_type.is_cfunction:
- return self.analyse_as_c_function(env)
- elif base_type.is_ctuple:
- return self.analyse_as_c_tuple(env, getting, setting)
- else:
- error(self.pos,
- "Attempting to index non-array type '%s'" %
- base_type)
- self.type = PyrexTypes.error_type
- return self
-
- def analyse_as_pyobject(self, env, is_slice, getting, setting):
- base_type = self.base.type
+
+ if base_type.is_pyobject:
+ return self.analyse_as_pyobject(env, is_slice, getting, setting)
+ elif base_type.is_ptr or base_type.is_array:
+ return self.analyse_as_c_array(env, is_slice)
+ elif base_type.is_cpp_class:
+ return self.analyse_as_cpp(env, setting)
+ elif base_type.is_cfunction:
+ return self.analyse_as_c_function(env)
+ elif base_type.is_ctuple:
+ return self.analyse_as_c_tuple(env, getting, setting)
+ else:
+ error(self.pos,
+ "Attempting to index non-array type '%s'" %
+ base_type)
+ self.type = PyrexTypes.error_type
+ return self
+
+ def analyse_as_pyobject(self, env, is_slice, getting, setting):
+ base_type = self.base.type
if self.index.type.is_unicode_char and base_type is not dict_type:
# TODO: eventually fold into case below and remove warning, once people have adapted their code
warning(self.pos,
@@ -3665,139 +3665,139 @@ class IndexNode(_IndexingBaseNode):
self.index = self.index.coerce_to_pyobject(env)
self.is_temp = 1
elif self.index.type.is_int and base_type is not dict_type:
- if (getting
- and (base_type in (list_type, tuple_type, bytearray_type))
- and (not self.index.type.signed
- or not env.directives['wraparound']
- or (isinstance(self.index, IntNode) and
- self.index.has_constant_result() and self.index.constant_result >= 0))
- and not env.directives['boundscheck']):
- self.is_temp = 0
+ if (getting
+ and (base_type in (list_type, tuple_type, bytearray_type))
+ and (not self.index.type.signed
+ or not env.directives['wraparound']
+ or (isinstance(self.index, IntNode) and
+ self.index.has_constant_result() and self.index.constant_result >= 0))
+ and not env.directives['boundscheck']):
+ self.is_temp = 0
+ else:
+ self.is_temp = 1
+ self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env)
+ self.original_index_type.create_to_py_utility_code(env)
+ else:
+ self.index = self.index.coerce_to_pyobject(env)
+ self.is_temp = 1
+
+ if self.index.type.is_int and base_type is unicode_type:
+ # Py_UNICODE/Py_UCS4 will automatically coerce to a unicode string
+ # if required, so this is fast and safe
+ self.type = PyrexTypes.c_py_ucs4_type
+ elif self.index.type.is_int and base_type is bytearray_type:
+ if setting:
+ self.type = PyrexTypes.c_uchar_type
else:
- self.is_temp = 1
- self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env)
- self.original_index_type.create_to_py_utility_code(env)
- else:
- self.index = self.index.coerce_to_pyobject(env)
- self.is_temp = 1
-
- if self.index.type.is_int and base_type is unicode_type:
- # Py_UNICODE/Py_UCS4 will automatically coerce to a unicode string
- # if required, so this is fast and safe
- self.type = PyrexTypes.c_py_ucs4_type
- elif self.index.type.is_int and base_type is bytearray_type:
- if setting:
- self.type = PyrexTypes.c_uchar_type
- else:
- # not using 'uchar' to enable fast and safe error reporting as '-1'
- self.type = PyrexTypes.c_int_type
+ # not using 'uchar' to enable fast and safe error reporting as '-1'
+ self.type = PyrexTypes.c_int_type
elif is_slice and base_type in (bytes_type, bytearray_type, str_type, unicode_type, list_type, tuple_type):
- self.type = base_type
- else:
- item_type = None
- if base_type in (list_type, tuple_type) and self.index.type.is_int:
- item_type = infer_sequence_item_type(
- env, self.base, self.index, seq_type=base_type)
- if item_type is None:
- item_type = py_object_type
- self.type = item_type
- if base_type in (list_type, tuple_type, dict_type):
- # do the None check explicitly (not in a helper) to allow optimising it away
- self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable")
-
+ self.type = base_type
+ else:
+ item_type = None
+ if base_type in (list_type, tuple_type) and self.index.type.is_int:
+ item_type = infer_sequence_item_type(
+ env, self.base, self.index, seq_type=base_type)
+ if item_type is None:
+ item_type = py_object_type
+ self.type = item_type
+ if base_type in (list_type, tuple_type, dict_type):
+ # do the None check explicitly (not in a helper) to allow optimising it away
+ self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable")
+
self.wrap_in_nonecheck_node(env, getting)
return self
- def analyse_as_c_array(self, env, is_slice):
- base_type = self.base.type
- self.type = base_type.base_type
- if is_slice:
- self.type = base_type
- elif self.index.type.is_pyobject:
- self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env)
- elif not self.index.type.is_int:
- error(self.pos, "Invalid index type '%s'" % self.index.type)
- return self
-
- def analyse_as_cpp(self, env, setting):
- base_type = self.base.type
- function = env.lookup_operator("[]", [self.base, self.index])
- if function is None:
- error(self.pos, "Indexing '%s' not supported for index type '%s'" % (base_type, self.index.type))
- self.type = PyrexTypes.error_type
- self.result_code = "<error>"
- return self
- func_type = function.type
- if func_type.is_ptr:
- func_type = func_type.base_type
- self.exception_check = func_type.exception_check
- self.exception_value = func_type.exception_value
- if self.exception_check:
- if not setting:
- self.is_temp = True
- if self.exception_value is None:
- env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
- self.index = self.index.coerce_to(func_type.args[0].type, env)
- self.type = func_type.return_type
- if setting and not func_type.return_type.is_reference:
- error(self.pos, "Can't set non-reference result '%s'" % self.type)
- return self
-
- def analyse_as_c_function(self, env):
- base_type = self.base.type
- if base_type.is_fused:
- self.parse_indexed_fused_cdef(env)
- else:
- self.type_indices = self.parse_index_as_types(env)
- self.index = None # FIXME: use a dedicated Node class instead of generic IndexNode
- if base_type.templates is None:
- error(self.pos, "Can only parameterize template functions.")
- self.type = error_type
+ def analyse_as_c_array(self, env, is_slice):
+ base_type = self.base.type
+ self.type = base_type.base_type
+ if is_slice:
+ self.type = base_type
+ elif self.index.type.is_pyobject:
+ self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env)
+ elif not self.index.type.is_int:
+ error(self.pos, "Invalid index type '%s'" % self.index.type)
+ return self
+
+ def analyse_as_cpp(self, env, setting):
+ base_type = self.base.type
+ function = env.lookup_operator("[]", [self.base, self.index])
+ if function is None:
+ error(self.pos, "Indexing '%s' not supported for index type '%s'" % (base_type, self.index.type))
+ self.type = PyrexTypes.error_type
+ self.result_code = "<error>"
+ return self
+ func_type = function.type
+ if func_type.is_ptr:
+ func_type = func_type.base_type
+ self.exception_check = func_type.exception_check
+ self.exception_value = func_type.exception_value
+ if self.exception_check:
+ if not setting:
+ self.is_temp = True
+ if self.exception_value is None:
+ env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
+ self.index = self.index.coerce_to(func_type.args[0].type, env)
+ self.type = func_type.return_type
+ if setting and not func_type.return_type.is_reference:
+ error(self.pos, "Can't set non-reference result '%s'" % self.type)
+ return self
+
+ def analyse_as_c_function(self, env):
+ base_type = self.base.type
+ if base_type.is_fused:
+ self.parse_indexed_fused_cdef(env)
+ else:
+ self.type_indices = self.parse_index_as_types(env)
+ self.index = None # FIXME: use a dedicated Node class instead of generic IndexNode
+ if base_type.templates is None:
+ error(self.pos, "Can only parameterize template functions.")
+ self.type = error_type
elif self.type_indices is None:
# Error recorded earlier.
self.type = error_type
- elif len(base_type.templates) != len(self.type_indices):
- error(self.pos, "Wrong number of template arguments: expected %s, got %s" % (
- (len(base_type.templates), len(self.type_indices))))
- self.type = error_type
+ elif len(base_type.templates) != len(self.type_indices):
+ error(self.pos, "Wrong number of template arguments: expected %s, got %s" % (
+ (len(base_type.templates), len(self.type_indices))))
+ self.type = error_type
+ else:
+ self.type = base_type.specialize(dict(zip(base_type.templates, self.type_indices)))
+ # FIXME: use a dedicated Node class instead of generic IndexNode
+ return self
+
+ def analyse_as_c_tuple(self, env, getting, setting):
+ base_type = self.base.type
+ if isinstance(self.index, IntNode) and self.index.has_constant_result():
+ index = self.index.constant_result
+ if -base_type.size <= index < base_type.size:
+ if index < 0:
+ index += base_type.size
+ self.type = base_type.components[index]
else:
- self.type = base_type.specialize(dict(zip(base_type.templates, self.type_indices)))
- # FIXME: use a dedicated Node class instead of generic IndexNode
- return self
-
- def analyse_as_c_tuple(self, env, getting, setting):
- base_type = self.base.type
- if isinstance(self.index, IntNode) and self.index.has_constant_result():
- index = self.index.constant_result
- if -base_type.size <= index < base_type.size:
- if index < 0:
- index += base_type.size
- self.type = base_type.components[index]
- else:
- error(self.pos,
- "Index %s out of bounds for '%s'" %
- (index, base_type))
- self.type = PyrexTypes.error_type
- return self
- else:
- self.base = self.base.coerce_to_pyobject(env)
- return self.analyse_base_and_index_types(env, getting=getting, setting=setting, analyse_base=False)
-
- def analyse_as_buffer_operation(self, env, getting):
- """
- Analyse buffer indexing and memoryview indexing/slicing
- """
- if isinstance(self.index, TupleNode):
- indices = self.index.args
- else:
- indices = [self.index]
+ error(self.pos,
+ "Index %s out of bounds for '%s'" %
+ (index, base_type))
+ self.type = PyrexTypes.error_type
+ return self
+ else:
+ self.base = self.base.coerce_to_pyobject(env)
+ return self.analyse_base_and_index_types(env, getting=getting, setting=setting, analyse_base=False)
+
+ def analyse_as_buffer_operation(self, env, getting):
+ """
+ Analyse buffer indexing and memoryview indexing/slicing
+ """
+ if isinstance(self.index, TupleNode):
+ indices = self.index.args
+ else:
+ indices = [self.index]
base = self.base
base_type = base.type
- replacement_node = None
- if base_type.is_memoryviewslice:
- # memoryviewslice indexing or slicing
- from . import MemoryView
+ replacement_node = None
+ if base_type.is_memoryviewslice:
+ # memoryviewslice indexing or slicing
+ from . import MemoryView
if base.is_memview_slice:
# For memory views, "view[i][j]" is the same as "view[i, j]" => use the latter for speed.
merged_indices = base.merged_indices(indices)
@@ -3805,10 +3805,10 @@ class IndexNode(_IndexingBaseNode):
base = base.base
base_type = base.type
indices = merged_indices
- have_slices, indices, newaxes = MemoryView.unellipsify(indices, base_type.ndim)
- if have_slices:
+ have_slices, indices, newaxes = MemoryView.unellipsify(indices, base_type.ndim)
+ if have_slices:
replacement_node = MemoryViewSliceNode(self.pos, indices=indices, base=base)
- else:
+ else:
replacement_node = MemoryViewIndexNode(self.pos, indices=indices, base=base)
elif base_type.is_buffer or base_type.is_pythran_expr:
if base_type.is_pythran_expr or len(indices) == base_type.ndim:
@@ -3831,16 +3831,16 @@ class IndexNode(_IndexingBaseNode):
replacement_node = BufferIndexNode(self.pos, indices=indices, base=base)
# On cloning, indices is cloned. Otherwise, unpack index into indices.
assert not isinstance(self.index, CloneNode)
-
- if replacement_node is not None:
- replacement_node = replacement_node.analyse_types(env, getting)
- return replacement_node
-
- def wrap_in_nonecheck_node(self, env, getting):
- if not env.directives['nonecheck'] or not self.base.may_be_none():
- return
- self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable")
-
+
+ if replacement_node is not None:
+ replacement_node = replacement_node.analyse_types(env, getting)
+ return replacement_node
+
+ def wrap_in_nonecheck_node(self, env, getting):
+ if not env.directives['nonecheck'] or not self.base.may_be_none():
+ return
+ self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable")
+
def parse_index_as_types(self, env, required=True):
if isinstance(self.index, TupleNode):
indices = self.index.args
@@ -3949,7 +3949,7 @@ class IndexNode(_IndexingBaseNode):
gil_message = "Indexing Python object"
def calculate_result_code(self):
- if self.base.type in (list_type, tuple_type, bytearray_type):
+ if self.base.type in (list_type, tuple_type, bytearray_type):
if self.base.type is list_type:
index_code = "PyList_GET_ITEM(%s, %s)"
elif self.base.type is tuple_type:
@@ -3961,12 +3961,12 @@ class IndexNode(_IndexingBaseNode):
elif self.base.type.is_cfunction:
return "%s<%s>" % (
self.base.result(),
- ",".join([param.empty_declaration_code() for param in self.type_indices]))
- elif self.base.type.is_ctuple:
- index = self.index.constant_result
- if index < 0:
- index += self.base.type.size
- return "%s.f%s" % (self.base.result(), index)
+ ",".join([param.empty_declaration_code() for param in self.type_indices]))
+ elif self.base.type.is_ctuple:
+ index = self.index.constant_result
+ if index < 0:
+ index += self.base.type.size
+ return "%s.f%s" % (self.base.result(), index)
else:
if (self.type.is_ptr or self.type.is_array) and self.type == self.base.type:
error(self.pos, "Invalid use of pointer slice")
@@ -3980,11 +3980,11 @@ class IndexNode(_IndexingBaseNode):
wraparound = (
bool(code.globalstate.directives['wraparound']) and
self.original_index_type.signed and
- not (isinstance(self.index.constant_result, _py_int_types)
+ not (isinstance(self.index.constant_result, _py_int_types)
and self.index.constant_result >= 0))
boundscheck = bool(code.globalstate.directives['boundscheck'])
return ", %s, %d, %s, %d, %d, %d" % (
- self.original_index_type.empty_declaration_code(),
+ self.original_index_type.empty_declaration_code(),
self.original_index_type.signed and 1 or 0,
self.original_index_type.to_py_function,
is_list, wraparound, boundscheck)
@@ -3992,24 +3992,24 @@ class IndexNode(_IndexingBaseNode):
return ""
def generate_result_code(self, code):
- if not self.is_temp:
- # all handled in self.calculate_result_code()
- return
+ if not self.is_temp:
+ # all handled in self.calculate_result_code()
+ return
utility_code = None
- if self.type.is_pyobject:
- error_value = 'NULL'
- if self.index.type.is_int:
- if self.base.type is list_type:
- function = "__Pyx_GetItemInt_List"
- elif self.base.type is tuple_type:
- function = "__Pyx_GetItemInt_Tuple"
+ if self.type.is_pyobject:
+ error_value = 'NULL'
+ if self.index.type.is_int:
+ if self.base.type is list_type:
+ function = "__Pyx_GetItemInt_List"
+ elif self.base.type is tuple_type:
+ function = "__Pyx_GetItemInt_Tuple"
else:
- function = "__Pyx_GetItemInt"
+ function = "__Pyx_GetItemInt"
utility_code = TempitaUtilityCode.load_cached("GetItemInt", "ObjectHandling.c")
else:
- if self.base.type is dict_type:
- function = "__Pyx_PyDict_GetItem"
+ if self.base.type is dict_type:
+ function = "__Pyx_PyDict_GetItem"
utility_code = UtilityCode.load_cached("DictGetItem", "ObjectHandling.c")
elif self.base.type is py_object_type and self.index.type in (str_type, unicode_type):
# obj[str] is probably doing a dict lookup
@@ -4017,50 +4017,50 @@ class IndexNode(_IndexingBaseNode):
utility_code = UtilityCode.load_cached("DictGetItem", "ObjectHandling.c")
else:
function = "__Pyx_PyObject_GetItem"
- code.globalstate.use_utility_code(
+ code.globalstate.use_utility_code(
TempitaUtilityCode.load_cached("GetItemInt", "ObjectHandling.c"))
utility_code = UtilityCode.load_cached("ObjectGetItem", "ObjectHandling.c")
- elif self.type.is_unicode_char and self.base.type is unicode_type:
- assert self.index.type.is_int
- function = "__Pyx_GetItemInt_Unicode"
- error_value = '(Py_UCS4)-1'
+ elif self.type.is_unicode_char and self.base.type is unicode_type:
+ assert self.index.type.is_int
+ function = "__Pyx_GetItemInt_Unicode"
+ error_value = '(Py_UCS4)-1'
utility_code = UtilityCode.load_cached("GetItemIntUnicode", "StringTools.c")
- elif self.base.type is bytearray_type:
- assert self.index.type.is_int
- assert self.type.is_int
- function = "__Pyx_GetItemInt_ByteArray"
- error_value = '-1'
+ elif self.base.type is bytearray_type:
+ assert self.index.type.is_int
+ assert self.type.is_int
+ function = "__Pyx_GetItemInt_ByteArray"
+ error_value = '-1'
utility_code = UtilityCode.load_cached("GetItemIntByteArray", "StringTools.c")
- elif not (self.base.type.is_cpp_class and self.exception_check):
- assert False, "unexpected type %s and base type %s for indexing" % (
- self.type, self.base.type)
+ elif not (self.base.type.is_cpp_class and self.exception_check):
+ assert False, "unexpected type %s and base type %s for indexing" % (
+ self.type, self.base.type)
if utility_code is not None:
code.globalstate.use_utility_code(utility_code)
- if self.index.type.is_int:
- index_code = self.index.result()
- else:
- index_code = self.index.py_result()
-
- if self.base.type.is_cpp_class and self.exception_check:
- translate_cpp_exception(code, self.pos,
- "%s = %s[%s];" % (self.result(), self.base.result(),
- self.index.result()),
- self.result() if self.type.is_pyobject else None,
- self.exception_value, self.in_nogil_context)
- else:
- error_check = '!%s' if error_value == 'NULL' else '%%s == %s' % error_value
+ if self.index.type.is_int:
+ index_code = self.index.result()
+ else:
+ index_code = self.index.py_result()
+
+ if self.base.type.is_cpp_class and self.exception_check:
+ translate_cpp_exception(code, self.pos,
+ "%s = %s[%s];" % (self.result(), self.base.result(),
+ self.index.result()),
+ self.result() if self.type.is_pyobject else None,
+ self.exception_value, self.in_nogil_context)
+ else:
+ error_check = '!%s' if error_value == 'NULL' else '%%s == %s' % error_value
code.putln(
- "%s = %s(%s, %s%s); %s" % (
+ "%s = %s(%s, %s%s); %s" % (
self.result(),
function,
self.base.py_result(),
index_code,
self.extra_index_params(code),
- code.error_goto_if(error_check % self.result(), self.pos)))
- if self.type.is_pyobject:
- code.put_gotref(self.py_result())
+ code.error_goto_if(error_check % self.result(), self.pos)))
+ if self.type.is_pyobject:
+ code.put_gotref(self.py_result())
def generate_setitem_code(self, value_code, code):
if self.index.type.is_int:
@@ -4086,46 +4086,46 @@ class IndexNode(_IndexingBaseNode):
# (PyTuple_SetItem() is for creating new tuples from scratch).
else:
function = "PyObject_SetItem"
- code.putln(code.error_goto_if_neg(
- "%s(%s, %s, %s%s)" % (
+ code.putln(code.error_goto_if_neg(
+ "%s(%s, %s, %s%s)" % (
function,
self.base.py_result(),
index_code,
value_code,
- self.extra_index_params(code)),
- self.pos))
+ self.extra_index_params(code)),
+ self.pos))
- def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
- exception_check=None, exception_value=None):
- self.generate_subexpr_evaluation_code(code)
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
+ exception_check=None, exception_value=None):
+ self.generate_subexpr_evaluation_code(code)
- if self.type.is_pyobject:
+ if self.type.is_pyobject:
self.generate_setitem_code(rhs.py_result(), code)
elif self.base.type is bytearray_type:
value_code = self._check_byte_value(code, rhs)
self.generate_setitem_code(value_code, code)
- elif self.base.type.is_cpp_class and self.exception_check and self.exception_check == '+':
- if overloaded_assignment and exception_check and \
- self.exception_value != exception_value:
- # Handle the case that both the index operator and the assignment
- # operator have a c++ exception handler and they are not the same.
- translate_double_cpp_exception(code, self.pos, self.type,
- self.result(), rhs.result(), self.exception_value,
- exception_value, self.in_nogil_context)
- else:
- # Handle the case that only the index operator has a
- # c++ exception handler, or that
- # both exception handlers are the same.
- translate_cpp_exception(code, self.pos,
- "%s = %s;" % (self.result(), rhs.result()),
- self.result() if self.type.is_pyobject else None,
- self.exception_value, self.in_nogil_context)
+ elif self.base.type.is_cpp_class and self.exception_check and self.exception_check == '+':
+ if overloaded_assignment and exception_check and \
+ self.exception_value != exception_value:
+ # Handle the case that both the index operator and the assignment
+ # operator have a c++ exception handler and they are not the same.
+ translate_double_cpp_exception(code, self.pos, self.type,
+ self.result(), rhs.result(), self.exception_value,
+ exception_value, self.in_nogil_context)
+ else:
+ # Handle the case that only the index operator has a
+ # c++ exception handler, or that
+ # both exception handlers are the same.
+ translate_cpp_exception(code, self.pos,
+ "%s = %s;" % (self.result(), rhs.result()),
+ self.result() if self.type.is_pyobject else None,
+ self.exception_value, self.in_nogil_context)
else:
code.putln(
- "%s = %s;" % (self.result(), rhs.result()))
+ "%s = %s;" % (self.result(), rhs.result()))
- self.generate_subexpr_disposal_code(code)
- self.free_subexpr_temps(code)
+ self.generate_subexpr_disposal_code(code)
+ self.free_subexpr_temps(code)
rhs.generate_disposal_code(code)
rhs.free_temps(code)
@@ -4179,101 +4179,101 @@ class IndexNode(_IndexingBaseNode):
function = "PyDict_DelItem"
else:
function = "PyObject_DelItem"
- code.putln(code.error_goto_if_neg(
- "%s(%s, %s%s)" % (
+ code.putln(code.error_goto_if_neg(
+ "%s(%s, %s%s)" % (
function,
self.base.py_result(),
index_code,
- self.extra_index_params(code)),
- self.pos))
+ self.extra_index_params(code)),
+ self.pos))
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
-
-class BufferIndexNode(_IndexingBaseNode):
- """
- Indexing of buffers and memoryviews. This node is created during type
- analysis from IndexNode and replaces it.
-
- Attributes:
- base - base node being indexed
- indices - list of indexing expressions
- """
-
- subexprs = ['base', 'indices']
-
- is_buffer_access = True
-
- # Whether we're assigning to a buffer (in that case it needs to be writable)
- writable_needed = False
-
+
+class BufferIndexNode(_IndexingBaseNode):
+ """
+ Indexing of buffers and memoryviews. This node is created during type
+ analysis from IndexNode and replaces it.
+
+ Attributes:
+ base - base node being indexed
+ indices - list of indexing expressions
+ """
+
+ subexprs = ['base', 'indices']
+
+ is_buffer_access = True
+
+ # Whether we're assigning to a buffer (in that case it needs to be writable)
+ writable_needed = False
+
# Any indexing temp variables that we need to clean up.
index_temps = ()
- def analyse_target_types(self, env):
- self.analyse_types(env, getting=False)
-
- def analyse_types(self, env, getting=True):
- """
- Analyse types for buffer indexing only. Overridden by memoryview
- indexing and slicing subclasses
- """
- # self.indices are already analyzed
+ def analyse_target_types(self, env):
+ self.analyse_types(env, getting=False)
+
+ def analyse_types(self, env, getting=True):
+ """
+ Analyse types for buffer indexing only. Overridden by memoryview
+ indexing and slicing subclasses
+ """
+ # self.indices are already analyzed
if not self.base.is_name and not is_pythran_expr(self.base.type):
- error(self.pos, "Can only index buffer variables")
- self.type = error_type
- return self
-
- if not getting:
- if not self.base.entry.type.writable:
- error(self.pos, "Writing to readonly buffer")
- else:
- self.writable_needed = True
- if self.base.type.is_buffer:
- self.base.entry.buffer_aux.writable_needed = True
-
- self.none_error_message = "'NoneType' object is not subscriptable"
- self.analyse_buffer_index(env, getting)
- self.wrap_in_nonecheck_node(env)
- return self
-
- def analyse_buffer_index(self, env, getting):
+ error(self.pos, "Can only index buffer variables")
+ self.type = error_type
+ return self
+
+ if not getting:
+ if not self.base.entry.type.writable:
+ error(self.pos, "Writing to readonly buffer")
+ else:
+ self.writable_needed = True
+ if self.base.type.is_buffer:
+ self.base.entry.buffer_aux.writable_needed = True
+
+ self.none_error_message = "'NoneType' object is not subscriptable"
+ self.analyse_buffer_index(env, getting)
+ self.wrap_in_nonecheck_node(env)
+ return self
+
+ def analyse_buffer_index(self, env, getting):
if is_pythran_expr(self.base.type):
index_with_type_list = [(idx, idx.type) for idx in self.indices]
self.type = PythranExpr(pythran_indexing_type(self.base.type, index_with_type_list))
else:
self.base = self.base.coerce_to_simple(env)
self.type = self.base.type.dtype
- self.buffer_type = self.base.type
-
+ self.buffer_type = self.base.type
+
if getting and (self.type.is_pyobject or self.type.is_pythran_expr):
- self.is_temp = True
-
- def analyse_assignment(self, rhs):
- """
- Called by IndexNode when this node is assigned to,
- with the rhs of the assignment
- """
-
- def wrap_in_nonecheck_node(self, env):
- if not env.directives['nonecheck'] or not self.base.may_be_none():
- return
- self.base = self.base.as_none_safe_node(self.none_error_message)
-
- def nogil_check(self, env):
- if self.is_buffer_access or self.is_memview_index:
- if self.type.is_pyobject:
- error(self.pos, "Cannot access buffer with object dtype without gil")
- self.type = error_type
-
- def calculate_result_code(self):
- return "(*%s)" % self.buffer_ptr_code
-
+ self.is_temp = True
+
+ def analyse_assignment(self, rhs):
+ """
+ Called by IndexNode when this node is assigned to,
+ with the rhs of the assignment
+ """
+
+ def wrap_in_nonecheck_node(self, env):
+ if not env.directives['nonecheck'] or not self.base.may_be_none():
+ return
+ self.base = self.base.as_none_safe_node(self.none_error_message)
+
+ def nogil_check(self, env):
+ if self.is_buffer_access or self.is_memview_index:
+ if self.type.is_pyobject:
+ error(self.pos, "Cannot access buffer with object dtype without gil")
+ self.type = error_type
+
+ def calculate_result_code(self):
+ return "(*%s)" % self.buffer_ptr_code
+
def buffer_entry(self):
base = self.base
if self.base.is_nonecheck:
base = base.arg
- return base.type.get_entry(base)
+ return base.type.get_entry(base)
def get_index_in_temp(self, code, ivar):
ret = code.funcstate.allocate_temp(
@@ -4285,15 +4285,15 @@ class BufferIndexNode(_IndexingBaseNode):
return ret
def buffer_lookup_code(self, code):
- """
- ndarray[1, 2, 3] and memslice[1, 2, 3]
- """
+ """
+ ndarray[1, 2, 3] and memslice[1, 2, 3]
+ """
if self.in_nogil_context:
if self.is_buffer_access or self.is_memview_index:
if code.globalstate.directives['boundscheck']:
warning(self.pos, "Use boundscheck(False) for faster access", level=1)
- # Assign indices to temps of at least (s)size_t to allow further index calculations.
+ # Assign indices to temps of at least (s)size_t to allow further index calculations.
self.index_temps = index_temps = [self.get_index_in_temp(code,ivar) for ivar in self.indices]
# Generate buffer access code using these temps
@@ -4305,23 +4305,23 @@ class BufferIndexNode(_IndexingBaseNode):
negative_indices = Buffer.buffer_defaults['negative_indices']
return buffer_entry, Buffer.put_buffer_lookup_code(
- entry=buffer_entry,
- index_signeds=[ivar.type.signed for ivar in self.indices],
- index_cnames=index_temps,
- directives=code.globalstate.directives,
- pos=self.pos, code=code,
- negative_indices=negative_indices,
- in_nogil_context=self.in_nogil_context)
-
- def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
- self.generate_subexpr_evaluation_code(code)
- self.generate_buffer_setitem_code(rhs, code)
- self.generate_subexpr_disposal_code(code)
- self.free_subexpr_temps(code)
- rhs.generate_disposal_code(code)
- rhs.free_temps(code)
-
- def generate_buffer_setitem_code(self, rhs, code, op=""):
+ entry=buffer_entry,
+ index_signeds=[ivar.type.signed for ivar in self.indices],
+ index_cnames=index_temps,
+ directives=code.globalstate.directives,
+ pos=self.pos, code=code,
+ negative_indices=negative_indices,
+ in_nogil_context=self.in_nogil_context)
+
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
+ self.generate_subexpr_evaluation_code(code)
+ self.generate_buffer_setitem_code(rhs, code)
+ self.generate_subexpr_disposal_code(code)
+ self.free_subexpr_temps(code)
+ rhs.generate_disposal_code(code)
+ rhs.free_temps(code)
+
+ def generate_buffer_setitem_code(self, rhs, code, op=""):
base_type = self.base.type
if is_pythran_expr(base_type) and is_pythran_supported_type(rhs.type):
obj = code.funcstate.allocate_temp(PythranExpr(pythran_type(self.base.type)), manage_ref=False)
@@ -4343,27 +4343,27 @@ class BufferIndexNode(_IndexingBaseNode):
code.funcstate.release_temp(obj)
return
- # Used from generate_assignment_code and InPlaceAssignmentNode
- buffer_entry, ptrexpr = self.buffer_lookup_code(code)
-
- if self.buffer_type.dtype.is_pyobject:
- # Must manage refcounts. Decref what is already there
- # and incref what we put in.
- ptr = code.funcstate.allocate_temp(buffer_entry.buf_ptr_type,
- manage_ref=False)
- rhs_code = rhs.result()
- code.putln("%s = %s;" % (ptr, ptrexpr))
- code.put_gotref("*%s" % ptr)
- code.putln("__Pyx_INCREF(%s); __Pyx_DECREF(*%s);" % (
- rhs_code, ptr))
- code.putln("*%s %s= %s;" % (ptr, op, rhs_code))
- code.put_giveref("*%s" % ptr)
- code.funcstate.release_temp(ptr)
- else:
- # Simple case
- code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result()))
-
- def generate_result_code(self, code):
+ # Used from generate_assignment_code and InPlaceAssignmentNode
+ buffer_entry, ptrexpr = self.buffer_lookup_code(code)
+
+ if self.buffer_type.dtype.is_pyobject:
+ # Must manage refcounts. Decref what is already there
+ # and incref what we put in.
+ ptr = code.funcstate.allocate_temp(buffer_entry.buf_ptr_type,
+ manage_ref=False)
+ rhs_code = rhs.result()
+ code.putln("%s = %s;" % (ptr, ptrexpr))
+ code.put_gotref("*%s" % ptr)
+ code.putln("__Pyx_INCREF(%s); __Pyx_DECREF(*%s);" % (
+ rhs_code, ptr))
+ code.putln("*%s %s= %s;" % (ptr, op, rhs_code))
+ code.put_giveref("*%s" % ptr)
+ code.funcstate.release_temp(ptr)
+ else:
+ # Simple case
+ code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result()))
+
+ def generate_result_code(self, code):
if is_pythran_expr(self.base.type):
res = self.result()
code.putln("__Pyx_call_destructor(%s);" % res)
@@ -4373,187 +4373,187 @@ class BufferIndexNode(_IndexingBaseNode):
self.base.pythran_result(),
pythran_indexing_code(self.indices)))
return
- buffer_entry, self.buffer_ptr_code = self.buffer_lookup_code(code)
- if self.type.is_pyobject:
- # is_temp is True, so must pull out value and incref it.
- # NOTE: object temporary results for nodes are declared
- # as PyObject *, so we need a cast
- code.putln("%s = (PyObject *) *%s;" % (self.result(), self.buffer_ptr_code))
- code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result())
-
+ buffer_entry, self.buffer_ptr_code = self.buffer_lookup_code(code)
+ if self.type.is_pyobject:
+ # is_temp is True, so must pull out value and incref it.
+ # NOTE: object temporary results for nodes are declared
+ # as PyObject *, so we need a cast
+ code.putln("%s = (PyObject *) *%s;" % (self.result(), self.buffer_ptr_code))
+ code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result())
+
def free_subexpr_temps(self, code):
for temp in self.index_temps:
code.funcstate.release_temp(temp)
self.index_temps = ()
super(BufferIndexNode, self).free_subexpr_temps(code)
-
-
-class MemoryViewIndexNode(BufferIndexNode):
-
- is_memview_index = True
- is_buffer_access = False
- warned_untyped_idx = False
-
- def analyse_types(self, env, getting=True):
- # memoryviewslice indexing or slicing
- from . import MemoryView
-
+
+
+class MemoryViewIndexNode(BufferIndexNode):
+
+ is_memview_index = True
+ is_buffer_access = False
+ warned_untyped_idx = False
+
+ def analyse_types(self, env, getting=True):
+ # memoryviewslice indexing or slicing
+ from . import MemoryView
+
self.is_pythran_mode = has_np_pythran(env)
- indices = self.indices
- have_slices, indices, newaxes = MemoryView.unellipsify(indices, self.base.type.ndim)
-
+ indices = self.indices
+ have_slices, indices, newaxes = MemoryView.unellipsify(indices, self.base.type.ndim)
+
if not getting:
self.writable_needed = True
if self.base.is_name or self.base.is_attribute:
self.base.entry.type.writable_needed = True
- self.memslice_index = (not newaxes and len(indices) == self.base.type.ndim)
- axes = []
-
- index_type = PyrexTypes.c_py_ssize_t_type
- new_indices = []
-
- if len(indices) - len(newaxes) > self.base.type.ndim:
- self.type = error_type
- error(indices[self.base.type.ndim].pos,
- "Too many indices specified for type %s" % self.base.type)
- return self
-
- axis_idx = 0
- for i, index in enumerate(indices[:]):
- index = index.analyse_types(env)
- if index.is_none:
- self.is_memview_slice = True
- new_indices.append(index)
- axes.append(('direct', 'strided'))
- continue
-
- access, packing = self.base.type.axes[axis_idx]
- axis_idx += 1
-
- if index.is_slice:
- self.is_memview_slice = True
- if index.step.is_none:
- axes.append((access, packing))
- else:
- axes.append((access, 'strided'))
-
- # Coerce start, stop and step to temps of the right type
- for attr in ('start', 'stop', 'step'):
- value = getattr(index, attr)
- if not value.is_none:
- value = value.coerce_to(index_type, env)
- #value = value.coerce_to_temp(env)
- setattr(index, attr, value)
- new_indices.append(value)
-
- elif index.type.is_int or index.type.is_pyobject:
- if index.type.is_pyobject and not self.warned_untyped_idx:
- warning(index.pos, "Index should be typed for more efficient access", level=2)
- MemoryViewIndexNode.warned_untyped_idx = True
-
- self.is_memview_index = True
- index = index.coerce_to(index_type, env)
- indices[i] = index
- new_indices.append(index)
-
- else:
- self.type = error_type
- error(index.pos, "Invalid index for memoryview specified, type %s" % index.type)
- return self
-
- ### FIXME: replace by MemoryViewSliceNode if is_memview_slice ?
- self.is_memview_index = self.is_memview_index and not self.is_memview_slice
- self.indices = new_indices
- # All indices with all start/stop/step for slices.
- # We need to keep this around.
- self.original_indices = indices
- self.nogil = env.nogil
-
- self.analyse_operation(env, getting, axes)
- self.wrap_in_nonecheck_node(env)
- return self
-
- def analyse_operation(self, env, getting, axes):
- self.none_error_message = "Cannot index None memoryview slice"
- self.analyse_buffer_index(env, getting)
-
- def analyse_broadcast_operation(self, rhs):
- """
- Support broadcasting for slice assignment.
- E.g.
- m_2d[...] = m_1d # or,
- m_1d[...] = m_2d # if the leading dimension has extent 1
- """
- if self.type.is_memoryviewslice:
- lhs = self
- if lhs.is_memview_broadcast or rhs.is_memview_broadcast:
- lhs.is_memview_broadcast = True
- rhs.is_memview_broadcast = True
-
- def analyse_as_memview_scalar_assignment(self, rhs):
- lhs = self.analyse_assignment(rhs)
- if lhs:
- rhs.is_memview_copy_assignment = lhs.is_memview_copy_assignment
- return lhs
- return self
-
-
-class MemoryViewSliceNode(MemoryViewIndexNode):
-
- is_memview_slice = True
-
- # No-op slicing operation, this node will be replaced
- is_ellipsis_noop = False
- is_memview_scalar_assignment = False
- is_memview_index = False
- is_memview_broadcast = False
-
- def analyse_ellipsis_noop(self, env, getting):
- """Slicing operations needing no evaluation, i.e. m[...] or m[:, :]"""
- ### FIXME: replace directly
- self.is_ellipsis_noop = all(
- index.is_slice and index.start.is_none and index.stop.is_none and index.step.is_none
- for index in self.indices)
-
- if self.is_ellipsis_noop:
- self.type = self.base.type
-
- def analyse_operation(self, env, getting, axes):
- from . import MemoryView
-
- if not getting:
- self.is_memview_broadcast = True
- self.none_error_message = "Cannot assign to None memoryview slice"
- else:
- self.none_error_message = "Cannot slice None memoryview slice"
-
- self.analyse_ellipsis_noop(env, getting)
- if self.is_ellipsis_noop:
- return
-
- self.index = None
- self.is_temp = True
- self.use_managed_ref = True
-
- if not MemoryView.validate_axes(self.pos, axes):
- self.type = error_type
- return
-
- self.type = PyrexTypes.MemoryViewSliceType(self.base.type.dtype, axes)
-
- if not (self.base.is_simple() or self.base.result_in_temp()):
- self.base = self.base.coerce_to_temp(env)
-
- def analyse_assignment(self, rhs):
- if not rhs.type.is_memoryviewslice and (
- self.type.dtype.assignable_from(rhs.type) or
- rhs.type.is_pyobject):
- # scalar assignment
- return MemoryCopyScalar(self.pos, self)
- else:
- return MemoryCopySlice(self.pos, self)
-
+ self.memslice_index = (not newaxes and len(indices) == self.base.type.ndim)
+ axes = []
+
+ index_type = PyrexTypes.c_py_ssize_t_type
+ new_indices = []
+
+ if len(indices) - len(newaxes) > self.base.type.ndim:
+ self.type = error_type
+ error(indices[self.base.type.ndim].pos,
+ "Too many indices specified for type %s" % self.base.type)
+ return self
+
+ axis_idx = 0
+ for i, index in enumerate(indices[:]):
+ index = index.analyse_types(env)
+ if index.is_none:
+ self.is_memview_slice = True
+ new_indices.append(index)
+ axes.append(('direct', 'strided'))
+ continue
+
+ access, packing = self.base.type.axes[axis_idx]
+ axis_idx += 1
+
+ if index.is_slice:
+ self.is_memview_slice = True
+ if index.step.is_none:
+ axes.append((access, packing))
+ else:
+ axes.append((access, 'strided'))
+
+ # Coerce start, stop and step to temps of the right type
+ for attr in ('start', 'stop', 'step'):
+ value = getattr(index, attr)
+ if not value.is_none:
+ value = value.coerce_to(index_type, env)
+ #value = value.coerce_to_temp(env)
+ setattr(index, attr, value)
+ new_indices.append(value)
+
+ elif index.type.is_int or index.type.is_pyobject:
+ if index.type.is_pyobject and not self.warned_untyped_idx:
+ warning(index.pos, "Index should be typed for more efficient access", level=2)
+ MemoryViewIndexNode.warned_untyped_idx = True
+
+ self.is_memview_index = True
+ index = index.coerce_to(index_type, env)
+ indices[i] = index
+ new_indices.append(index)
+
+ else:
+ self.type = error_type
+ error(index.pos, "Invalid index for memoryview specified, type %s" % index.type)
+ return self
+
+ ### FIXME: replace by MemoryViewSliceNode if is_memview_slice ?
+ self.is_memview_index = self.is_memview_index and not self.is_memview_slice
+ self.indices = new_indices
+ # All indices with all start/stop/step for slices.
+ # We need to keep this around.
+ self.original_indices = indices
+ self.nogil = env.nogil
+
+ self.analyse_operation(env, getting, axes)
+ self.wrap_in_nonecheck_node(env)
+ return self
+
+ def analyse_operation(self, env, getting, axes):
+ self.none_error_message = "Cannot index None memoryview slice"
+ self.analyse_buffer_index(env, getting)
+
+ def analyse_broadcast_operation(self, rhs):
+ """
+ Support broadcasting for slice assignment.
+ E.g.
+ m_2d[...] = m_1d # or,
+ m_1d[...] = m_2d # if the leading dimension has extent 1
+ """
+ if self.type.is_memoryviewslice:
+ lhs = self
+ if lhs.is_memview_broadcast or rhs.is_memview_broadcast:
+ lhs.is_memview_broadcast = True
+ rhs.is_memview_broadcast = True
+
+ def analyse_as_memview_scalar_assignment(self, rhs):
+ lhs = self.analyse_assignment(rhs)
+ if lhs:
+ rhs.is_memview_copy_assignment = lhs.is_memview_copy_assignment
+ return lhs
+ return self
+
+
+class MemoryViewSliceNode(MemoryViewIndexNode):
+
+ is_memview_slice = True
+
+ # No-op slicing operation, this node will be replaced
+ is_ellipsis_noop = False
+ is_memview_scalar_assignment = False
+ is_memview_index = False
+ is_memview_broadcast = False
+
+ def analyse_ellipsis_noop(self, env, getting):
+ """Slicing operations needing no evaluation, i.e. m[...] or m[:, :]"""
+ ### FIXME: replace directly
+ self.is_ellipsis_noop = all(
+ index.is_slice and index.start.is_none and index.stop.is_none and index.step.is_none
+ for index in self.indices)
+
+ if self.is_ellipsis_noop:
+ self.type = self.base.type
+
+ def analyse_operation(self, env, getting, axes):
+ from . import MemoryView
+
+ if not getting:
+ self.is_memview_broadcast = True
+ self.none_error_message = "Cannot assign to None memoryview slice"
+ else:
+ self.none_error_message = "Cannot slice None memoryview slice"
+
+ self.analyse_ellipsis_noop(env, getting)
+ if self.is_ellipsis_noop:
+ return
+
+ self.index = None
+ self.is_temp = True
+ self.use_managed_ref = True
+
+ if not MemoryView.validate_axes(self.pos, axes):
+ self.type = error_type
+ return
+
+ self.type = PyrexTypes.MemoryViewSliceType(self.base.type.dtype, axes)
+
+ if not (self.base.is_simple() or self.base.result_in_temp()):
+ self.base = self.base.coerce_to_temp(env)
+
+ def analyse_assignment(self, rhs):
+ if not rhs.type.is_memoryviewslice and (
+ self.type.dtype.assignable_from(rhs.type) or
+ rhs.type.is_pyobject):
+ # scalar assignment
+ return MemoryCopyScalar(self.pos, self)
+ else:
+ return MemoryCopySlice(self.pos, self)
+
def merged_indices(self, indices):
"""Return a new list of indices/slices with 'indices' merged into the current ones
according to slicing rules.
@@ -4585,29 +4585,29 @@ class MemoryViewSliceNode(MemoryViewIndexNode):
new_indices += indices
return new_indices
- def is_simple(self):
- if self.is_ellipsis_noop:
- # TODO: fix SimpleCallNode.is_simple()
- return self.base.is_simple() or self.base.result_in_temp()
-
- return self.result_in_temp()
-
- def calculate_result_code(self):
- """This is called in case this is a no-op slicing node"""
- return self.base.result()
-
- def generate_result_code(self, code):
- if self.is_ellipsis_noop:
- return ### FIXME: remove
+ def is_simple(self):
+ if self.is_ellipsis_noop:
+ # TODO: fix SimpleCallNode.is_simple()
+ return self.base.is_simple() or self.base.result_in_temp()
+
+ return self.result_in_temp()
+
+ def calculate_result_code(self):
+ """This is called in case this is a no-op slicing node"""
+ return self.base.result()
+
+ def generate_result_code(self, code):
+ if self.is_ellipsis_noop:
+ return ### FIXME: remove
buffer_entry = self.buffer_entry()
have_gil = not self.in_nogil_context
- # TODO Mark: this is insane, do it better
+ # TODO Mark: this is insane, do it better
have_slices = False
it = iter(self.indices)
for index in self.original_indices:
- if index.is_slice:
- have_slices = True
+ if index.is_slice:
+ have_slices = True
if not index.start.is_none:
index.start = next(it)
if not index.stop.is_none:
@@ -4619,126 +4619,126 @@ class MemoryViewSliceNode(MemoryViewIndexNode):
assert not list(it)
- buffer_entry.generate_buffer_slice_code(
- code, self.original_indices, self.result(),
- have_gil=have_gil, have_slices=have_slices,
- directives=code.globalstate.directives)
-
- def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
- if self.is_ellipsis_noop:
- self.generate_subexpr_evaluation_code(code)
- else:
- self.generate_evaluation_code(code)
-
- if self.is_memview_scalar_assignment:
- self.generate_memoryviewslice_assign_scalar_code(rhs, code)
- else:
- self.generate_memoryviewslice_setslice_code(rhs, code)
-
- if self.is_ellipsis_noop:
- self.generate_subexpr_disposal_code(code)
- else:
- self.generate_disposal_code(code)
-
- rhs.generate_disposal_code(code)
- rhs.free_temps(code)
-
-
-class MemoryCopyNode(ExprNode):
- """
- Wraps a memoryview slice for slice assignment.
-
- dst: destination mememoryview slice
- """
-
- subexprs = ['dst']
-
- def __init__(self, pos, dst):
- super(MemoryCopyNode, self).__init__(pos)
- self.dst = dst
- self.type = dst.type
-
- def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
- self.dst.generate_evaluation_code(code)
- self._generate_assignment_code(rhs, code)
- self.dst.generate_disposal_code(code)
+ buffer_entry.generate_buffer_slice_code(
+ code, self.original_indices, self.result(),
+ have_gil=have_gil, have_slices=have_slices,
+ directives=code.globalstate.directives)
+
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
+ if self.is_ellipsis_noop:
+ self.generate_subexpr_evaluation_code(code)
+ else:
+ self.generate_evaluation_code(code)
+
+ if self.is_memview_scalar_assignment:
+ self.generate_memoryviewslice_assign_scalar_code(rhs, code)
+ else:
+ self.generate_memoryviewslice_setslice_code(rhs, code)
+
+ if self.is_ellipsis_noop:
+ self.generate_subexpr_disposal_code(code)
+ else:
+ self.generate_disposal_code(code)
+
+ rhs.generate_disposal_code(code)
+ rhs.free_temps(code)
+
+
+class MemoryCopyNode(ExprNode):
+ """
+ Wraps a memoryview slice for slice assignment.
+
+ dst: destination mememoryview slice
+ """
+
+ subexprs = ['dst']
+
+ def __init__(self, pos, dst):
+ super(MemoryCopyNode, self).__init__(pos)
+ self.dst = dst
+ self.type = dst.type
+
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
+ self.dst.generate_evaluation_code(code)
+ self._generate_assignment_code(rhs, code)
+ self.dst.generate_disposal_code(code)
self.dst.free_temps(code)
- rhs.generate_disposal_code(code)
- rhs.free_temps(code)
-
-
-class MemoryCopySlice(MemoryCopyNode):
- """
- Copy the contents of slice src to slice dst. Does not support indirect
- slices.
-
- memslice1[...] = memslice2
- memslice1[:] = memslice2
- """
-
- is_memview_copy_assignment = True
- copy_slice_cname = "__pyx_memoryview_copy_contents"
-
- def _generate_assignment_code(self, src, code):
- dst = self.dst
-
- src.type.assert_direct_dims(src.pos)
- dst.type.assert_direct_dims(dst.pos)
-
- code.putln(code.error_goto_if_neg(
- "%s(%s, %s, %d, %d, %d)" % (self.copy_slice_cname,
- src.result(), dst.result(),
- src.type.ndim, dst.type.ndim,
- dst.type.dtype.is_pyobject),
- dst.pos))
-
-
-class MemoryCopyScalar(MemoryCopyNode):
- """
- Assign a scalar to a slice. dst must be simple, scalar will be assigned
- to a correct type and not just something assignable.
-
- memslice1[...] = 0.0
- memslice1[:] = 0.0
- """
-
- def __init__(self, pos, dst):
- super(MemoryCopyScalar, self).__init__(pos, dst)
- self.type = dst.type.dtype
-
- def _generate_assignment_code(self, scalar, code):
+ rhs.generate_disposal_code(code)
+ rhs.free_temps(code)
+
+
+class MemoryCopySlice(MemoryCopyNode):
+ """
+ Copy the contents of slice src to slice dst. Does not support indirect
+ slices.
+
+ memslice1[...] = memslice2
+ memslice1[:] = memslice2
+ """
+
+ is_memview_copy_assignment = True
+ copy_slice_cname = "__pyx_memoryview_copy_contents"
+
+ def _generate_assignment_code(self, src, code):
+ dst = self.dst
+
+ src.type.assert_direct_dims(src.pos)
+ dst.type.assert_direct_dims(dst.pos)
+
+ code.putln(code.error_goto_if_neg(
+ "%s(%s, %s, %d, %d, %d)" % (self.copy_slice_cname,
+ src.result(), dst.result(),
+ src.type.ndim, dst.type.ndim,
+ dst.type.dtype.is_pyobject),
+ dst.pos))
+
+
+class MemoryCopyScalar(MemoryCopyNode):
+ """
+ Assign a scalar to a slice. dst must be simple, scalar will be assigned
+ to a correct type and not just something assignable.
+
+ memslice1[...] = 0.0
+ memslice1[:] = 0.0
+ """
+
+ def __init__(self, pos, dst):
+ super(MemoryCopyScalar, self).__init__(pos, dst)
+ self.type = dst.type.dtype
+
+ def _generate_assignment_code(self, scalar, code):
from . import MemoryView
- self.dst.type.assert_direct_dims(self.dst.pos)
-
- dtype = self.dst.type.dtype
- type_decl = dtype.declaration_code("")
- slice_decl = self.dst.type.declaration_code("")
-
- code.begin_block()
- code.putln("%s __pyx_temp_scalar = %s;" % (type_decl, scalar.result()))
- if self.dst.result_in_temp() or self.dst.is_simple():
- dst_temp = self.dst.result()
- else:
- code.putln("%s __pyx_temp_slice = %s;" % (slice_decl, self.dst.result()))
- dst_temp = "__pyx_temp_slice"
-
- slice_iter_obj = MemoryView.slice_iter(self.dst.type, dst_temp,
- self.dst.type.ndim, code)
- p = slice_iter_obj.start_loops()
-
- if dtype.is_pyobject:
- code.putln("Py_DECREF(*(PyObject **) %s);" % p)
-
- code.putln("*((%s *) %s) = __pyx_temp_scalar;" % (type_decl, p))
-
- if dtype.is_pyobject:
- code.putln("Py_INCREF(__pyx_temp_scalar);")
-
- slice_iter_obj.end_loops()
- code.end_block()
-
-
+ self.dst.type.assert_direct_dims(self.dst.pos)
+
+ dtype = self.dst.type.dtype
+ type_decl = dtype.declaration_code("")
+ slice_decl = self.dst.type.declaration_code("")
+
+ code.begin_block()
+ code.putln("%s __pyx_temp_scalar = %s;" % (type_decl, scalar.result()))
+ if self.dst.result_in_temp() or self.dst.is_simple():
+ dst_temp = self.dst.result()
+ else:
+ code.putln("%s __pyx_temp_slice = %s;" % (slice_decl, self.dst.result()))
+ dst_temp = "__pyx_temp_slice"
+
+ slice_iter_obj = MemoryView.slice_iter(self.dst.type, dst_temp,
+ self.dst.type.ndim, code)
+ p = slice_iter_obj.start_loops()
+
+ if dtype.is_pyobject:
+ code.putln("Py_DECREF(*(PyObject **) %s);" % p)
+
+ code.putln("*((%s *) %s) = __pyx_temp_scalar;" % (type_decl, p))
+
+ if dtype.is_pyobject:
+ code.putln("Py_INCREF(__pyx_temp_scalar);")
+
+ slice_iter_obj.end_loops()
+ code.end_block()
+
+
class SliceIndexNode(ExprNode):
# 2-element slice indexing
#
@@ -4764,15 +4764,15 @@ class SliceIndexNode(ExprNode):
return PyrexTypes.c_array_type(base_type.base_type, None)
return py_object_type
- def inferable_item_node(self, index=0):
- # slicing shouldn't change the result type of the base, but the index might
- if index is not not_a_constant and self.start:
- if self.start.has_constant_result():
- index += self.start.constant_result
- else:
- index = not_a_constant
- return self.base.inferable_item_node(index)
-
+ def inferable_item_node(self, index=0):
+ # slicing shouldn't change the result type of the base, but the index might
+ if index is not not_a_constant and self.start:
+ if self.start.has_constant_result():
+ index += self.start.constant_result
+ else:
+ index = not_a_constant
+ return self.base.inferable_item_node(index)
+
def may_be_none(self):
base_type = self.base.type
if base_type:
@@ -4806,7 +4806,7 @@ class SliceIndexNode(ExprNode):
stop = self.stop.compile_time_value(denv)
try:
return base[start:stop]
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def analyse_target_declaration(self, env):
@@ -4842,13 +4842,13 @@ class SliceIndexNode(ExprNode):
check_negative_indices(self.start, self.stop)
base_type = self.base.type
- if base_type.is_array and not getting:
- # cannot assign directly to C array => try to assign by making a copy
- if not self.start and not self.stop:
- self.type = base_type
- else:
- self.type = PyrexTypes.CPtrType(base_type.base_type)
- elif base_type.is_string or base_type.is_cpp_string:
+ if base_type.is_array and not getting:
+ # cannot assign directly to C array => try to assign by making a copy
+ if not self.start and not self.stop:
+ self.type = base_type
+ else:
+ self.type = PyrexTypes.CPtrType(base_type.base_type)
+ elif base_type.is_string or base_type.is_cpp_string:
self.type = default_str_type(env)
elif base_type.is_pyunicode_ptr:
self.type = unicode_type
@@ -4880,59 +4880,59 @@ class SliceIndexNode(ExprNode):
).analyse_types(env)
else:
c_int = PyrexTypes.c_py_ssize_t_type
-
- def allow_none(node, default_value, env):
- # Coerce to Py_ssize_t, but allow None as meaning the default slice bound.
- from .UtilNodes import EvalWithTempExprNode, ResultRefNode
-
- node_ref = ResultRefNode(node)
- new_expr = CondExprNode(
- node.pos,
- true_val=IntNode(
- node.pos,
- type=c_int,
- value=default_value,
- constant_result=int(default_value) if default_value.isdigit() else not_a_constant,
- ),
- false_val=node_ref.coerce_to(c_int, env),
- test=PrimaryCmpNode(
- node.pos,
- operand1=node_ref,
- operator='is',
- operand2=NoneNode(node.pos),
- ).analyse_types(env)
- ).analyse_result_type(env)
- return EvalWithTempExprNode(node_ref, new_expr)
-
+
+ def allow_none(node, default_value, env):
+ # Coerce to Py_ssize_t, but allow None as meaning the default slice bound.
+ from .UtilNodes import EvalWithTempExprNode, ResultRefNode
+
+ node_ref = ResultRefNode(node)
+ new_expr = CondExprNode(
+ node.pos,
+ true_val=IntNode(
+ node.pos,
+ type=c_int,
+ value=default_value,
+ constant_result=int(default_value) if default_value.isdigit() else not_a_constant,
+ ),
+ false_val=node_ref.coerce_to(c_int, env),
+ test=PrimaryCmpNode(
+ node.pos,
+ operand1=node_ref,
+ operator='is',
+ operand2=NoneNode(node.pos),
+ ).analyse_types(env)
+ ).analyse_result_type(env)
+ return EvalWithTempExprNode(node_ref, new_expr)
+
if self.start:
- if self.start.type.is_pyobject:
- self.start = allow_none(self.start, '0', env)
+ if self.start.type.is_pyobject:
+ self.start = allow_none(self.start, '0', env)
self.start = self.start.coerce_to(c_int, env)
if self.stop:
- if self.stop.type.is_pyobject:
- self.stop = allow_none(self.stop, 'PY_SSIZE_T_MAX', env)
+ if self.stop.type.is_pyobject:
+ self.stop = allow_none(self.stop, 'PY_SSIZE_T_MAX', env)
self.stop = self.stop.coerce_to(c_int, env)
self.is_temp = 1
return self
- def analyse_as_type(self, env):
- base_type = self.base.analyse_as_type(env)
- if base_type and not base_type.is_pyobject:
- if not self.start and not self.stop:
- # memory view
- from . import MemoryView
- env.use_utility_code(MemoryView.view_utility_code)
- none_node = NoneNode(self.pos)
- slice_node = SliceNode(
- self.pos,
- start=none_node,
- stop=none_node,
- step=none_node,
- )
- return PyrexTypes.MemoryViewSliceType(
- base_type, MemoryView.get_axes_specs(env, [slice_node]))
- return None
-
+ def analyse_as_type(self, env):
+ base_type = self.base.analyse_as_type(env)
+ if base_type and not base_type.is_pyobject:
+ if not self.start and not self.stop:
+ # memory view
+ from . import MemoryView
+ env.use_utility_code(MemoryView.view_utility_code)
+ none_node = NoneNode(self.pos)
+ slice_node = SliceNode(
+ self.pos,
+ start=none_node,
+ stop=none_node,
+ step=none_node,
+ )
+ return PyrexTypes.MemoryViewSliceType(
+ base_type, MemoryView.get_axes_specs(env, [slice_node]))
+ return None
+
nogil_check = Node.gil_error
gil_message = "Slicing Python object"
@@ -4951,11 +4951,11 @@ class SliceIndexNode(ExprNode):
"default encoding required for conversion from '%s' to '%s'" %
(self.base.type, dst_type))
self.type = dst_type
- if dst_type.is_array and self.base.type.is_array:
- if not self.start and not self.stop:
- # redundant slice building, copy C arrays directly
- return self.base.coerce_to(dst_type, env)
- # else: check array size if possible
+ if dst_type.is_array and self.base.type.is_array:
+ if not self.start and not self.stop:
+ # redundant slice building, copy C arrays directly
+ return self.base.coerce_to(dst_type, env)
+ # else: check array size if possible
return super(SliceIndexNode, self).coerce_to(dst_type, env)
def generate_result_code(self, code):
@@ -4970,7 +4970,7 @@ class SliceIndexNode(ExprNode):
stop_code = self.stop_code()
if self.base.type.is_string:
base_result = self.base.result()
- if self.base.type not in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_const_char_ptr_type):
+ if self.base.type not in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_const_char_ptr_type):
base_result = '((const char*)%s)' % base_result
if self.type is bytearray_type:
type_name = 'ByteArray'
@@ -5059,8 +5059,8 @@ class SliceIndexNode(ExprNode):
code.error_goto_if_null(result, self.pos)))
code.put_gotref(self.py_result())
- def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
- exception_check=None, exception_value=None):
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
+ exception_check=None, exception_value=None):
self.generate_subexpr_evaluation_code(code)
if self.type.is_pyobject:
code.globalstate.use_utility_code(self.set_slice_utility_code)
@@ -5075,20 +5075,20 @@ class SliceIndexNode(ExprNode):
has_c_start, has_c_stop,
bool(code.globalstate.directives['wraparound'])))
else:
- start_offset = self.start_code() if self.start else '0'
+ start_offset = self.start_code() if self.start else '0'
if rhs.type.is_array:
array_length = rhs.type.size
self.generate_slice_guard_code(code, array_length)
else:
- array_length = '%s - %s' % (self.stop_code(), start_offset)
-
- code.globalstate.use_utility_code(UtilityCode.load_cached("IncludeStringH", "StringTools.c"))
- code.putln("memcpy(&(%s[%s]), %s, sizeof(%s[0]) * (%s));" % (
- self.base.result(), start_offset,
- rhs.result(),
- self.base.result(), array_length
- ))
-
+ array_length = '%s - %s' % (self.stop_code(), start_offset)
+
+ code.globalstate.use_utility_code(UtilityCode.load_cached("IncludeStringH", "StringTools.c"))
+ code.putln("memcpy(&(%s[%s]), %s, sizeof(%s[0]) * (%s));" % (
+ self.base.result(), start_offset,
+ rhs.result(),
+ self.base.result(), array_length
+ ))
+
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
rhs.generate_disposal_code(code)
@@ -5136,77 +5136,77 @@ class SliceIndexNode(ExprNode):
if not self.base.type.is_array:
return
slice_size = self.base.type.size
- try:
- total_length = slice_size = int(slice_size)
- except ValueError:
- total_length = None
-
+ try:
+ total_length = slice_size = int(slice_size)
+ except ValueError:
+ total_length = None
+
start = stop = None
if self.stop:
stop = self.stop.result()
try:
stop = int(stop)
if stop < 0:
- if total_length is None:
- slice_size = '%s + %d' % (slice_size, stop)
- else:
- slice_size += stop
+ if total_length is None:
+ slice_size = '%s + %d' % (slice_size, stop)
+ else:
+ slice_size += stop
else:
slice_size = stop
stop = None
except ValueError:
pass
-
+
if self.start:
start = self.start.result()
try:
start = int(start)
if start < 0:
- if total_length is None:
- start = '%s + %d' % (self.base.type.size, start)
- else:
- start += total_length
- if isinstance(slice_size, _py_int_types):
- slice_size -= start
- else:
- slice_size = '%s - (%s)' % (slice_size, start)
+ if total_length is None:
+ start = '%s + %d' % (self.base.type.size, start)
+ else:
+ start += total_length
+ if isinstance(slice_size, _py_int_types):
+ slice_size -= start
+ else:
+ slice_size = '%s - (%s)' % (slice_size, start)
start = None
except ValueError:
pass
-
- runtime_check = None
- compile_time_check = False
- try:
- int_target_size = int(target_size)
- except ValueError:
- int_target_size = None
- else:
- compile_time_check = isinstance(slice_size, _py_int_types)
-
- if compile_time_check and slice_size < 0:
- if int_target_size > 0:
+
+ runtime_check = None
+ compile_time_check = False
+ try:
+ int_target_size = int(target_size)
+ except ValueError:
+ int_target_size = None
+ else:
+ compile_time_check = isinstance(slice_size, _py_int_types)
+
+ if compile_time_check and slice_size < 0:
+ if int_target_size > 0:
error(self.pos, "Assignment to empty slice.")
- elif compile_time_check and start is None and stop is None:
+ elif compile_time_check and start is None and stop is None:
# we know the exact slice length
- if int_target_size != slice_size:
- error(self.pos, "Assignment to slice of wrong length, expected %s, got %s" % (
- slice_size, target_size))
+ if int_target_size != slice_size:
+ error(self.pos, "Assignment to slice of wrong length, expected %s, got %s" % (
+ slice_size, target_size))
elif start is not None:
if stop is None:
stop = slice_size
- runtime_check = "(%s)-(%s)" % (stop, start)
- elif stop is not None:
- runtime_check = stop
- else:
- runtime_check = slice_size
-
- if runtime_check:
- code.putln("if (unlikely((%s) != (%s))) {" % (runtime_check, target_size))
- code.putln(
- 'PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length,'
- ' expected %%" CYTHON_FORMAT_SSIZE_T "d, got %%" CYTHON_FORMAT_SSIZE_T "d",'
- ' (Py_ssize_t)(%s), (Py_ssize_t)(%s));' % (
- target_size, runtime_check))
+ runtime_check = "(%s)-(%s)" % (stop, start)
+ elif stop is not None:
+ runtime_check = stop
+ else:
+ runtime_check = slice_size
+
+ if runtime_check:
+ code.putln("if (unlikely((%s) != (%s))) {" % (runtime_check, target_size))
+ code.putln(
+ 'PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length,'
+ ' expected %%" CYTHON_FORMAT_SSIZE_T "d, got %%" CYTHON_FORMAT_SSIZE_T "d",'
+ ' (Py_ssize_t)(%s), (Py_ssize_t)(%s));' % (
+ target_size, runtime_check))
code.putln(code.error_goto(self.pos))
code.putln("}")
@@ -5237,7 +5237,7 @@ class SliceNode(ExprNode):
# step ExprNode
subexprs = ['start', 'stop', 'step']
- is_slice = True
+ is_slice = True
type = slice_type
is_temp = 1
@@ -5253,7 +5253,7 @@ class SliceNode(ExprNode):
step = self.step.compile_time_value(denv)
try:
return slice(start, stop, step)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def may_be_none(self):
@@ -5278,11 +5278,11 @@ class SliceNode(ExprNode):
def generate_result_code(self, code):
if self.is_literal:
- dedup_key = make_dedup_key(self.type, (self,))
- self.result_code = code.get_py_const(py_object_type, 'slice', cleanup_level=2, dedup_key=dedup_key)
- code = code.get_cached_constants_writer(self.result_code)
- if code is None:
- return # already initialised
+ dedup_key = make_dedup_key(self.type, (self,))
+ self.result_code = code.get_py_const(py_object_type, 'slice', cleanup_level=2, dedup_key=dedup_key)
+ code = code.get_cached_constants_writer(self.result_code)
+ if code is None:
+ return # already initialised
code.mark_pos(self.pos)
code.putln(
@@ -5357,7 +5357,7 @@ class CallNode(ExprNode):
may_return_none = None
def infer_type(self, env):
- # TODO(robertwb): Reduce redundancy with analyse_types.
+ # TODO(robertwb): Reduce redundancy with analyse_types.
function = self.function
func_type = function.infer_type(env)
if isinstance(function, NewExprNode):
@@ -5371,15 +5371,15 @@ class CallNode(ExprNode):
if func_type.is_ptr:
func_type = func_type.base_type
if func_type.is_cfunction:
- if getattr(self.function, 'entry', None) and hasattr(self, 'args'):
- alternatives = self.function.entry.all_alternatives()
- arg_types = [arg.infer_type(env) for arg in self.args]
- func_entry = PyrexTypes.best_match(arg_types, alternatives)
- if func_entry:
- func_type = func_entry.type
- if func_type.is_ptr:
- func_type = func_type.base_type
- return func_type.return_type
+ if getattr(self.function, 'entry', None) and hasattr(self, 'args'):
+ alternatives = self.function.entry.all_alternatives()
+ arg_types = [arg.infer_type(env) for arg in self.args]
+ func_entry = PyrexTypes.best_match(arg_types, alternatives)
+ if func_entry:
+ func_type = func_entry.type
+ if func_type.is_ptr:
+ func_type = func_type.base_type
+ return func_type.return_type
return func_type.return_type
elif func_type is type_type:
if function.is_name and function.entry and function.entry.type:
@@ -5467,7 +5467,7 @@ class CallNode(ExprNode):
return self
self.function = RawCNameExprNode(self.function.pos, constructor.type)
self.function.entry = constructor
- self.function.set_cname(type.empty_declaration_code())
+ self.function.set_cname(type.empty_declaration_code())
self.analyse_c_function_call(env)
self.type = type
return True
@@ -5513,7 +5513,7 @@ class SimpleCallNode(CallNode):
args = [arg.compile_time_value(denv) for arg in self.args]
try:
return function(*args)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def analyse_as_type(self, env):
@@ -5554,8 +5554,8 @@ class SimpleCallNode(CallNode):
func_type = self.function_type()
self.is_numpy_call_with_exprs = False
- if (has_np_pythran(env) and function.is_numpy_attribute and
- pythran_is_numpy_func_supported(function)):
+ if (has_np_pythran(env) and function.is_numpy_attribute and
+ pythran_is_numpy_func_supported(function)):
has_pythran_args = True
self.arg_tuple = TupleNode(self.pos, args = self.args)
self.arg_tuple = self.arg_tuple.analyse_types(env)
@@ -5563,24 +5563,24 @@ class SimpleCallNode(CallNode):
has_pythran_args &= is_pythran_supported_node_or_none(arg)
self.is_numpy_call_with_exprs = bool(has_pythran_args)
if self.is_numpy_call_with_exprs:
- env.add_include_file(pythran_get_func_include_file(function))
+ env.add_include_file(pythran_get_func_include_file(function))
return NumPyMethodCallNode.from_node(
self,
function_cname=pythran_functor(function),
arg_tuple=self.arg_tuple,
- type=PythranExpr(pythran_func_type(function, self.arg_tuple.args)),
+ type=PythranExpr(pythran_func_type(function, self.arg_tuple.args)),
)
elif func_type.is_pyobject:
self.arg_tuple = TupleNode(self.pos, args = self.args)
- self.arg_tuple = self.arg_tuple.analyse_types(env).coerce_to_pyobject(env)
+ self.arg_tuple = self.arg_tuple.analyse_types(env).coerce_to_pyobject(env)
self.args = None
self.set_py_result_type(function, func_type)
self.is_temp = 1
else:
self.args = [ arg.analyse_types(env) for arg in self.args ]
self.analyse_c_function_call(env)
- if func_type.exception_check == '+':
- self.is_temp = True
+ if func_type.exception_check == '+':
+ self.is_temp = True
return self
def function_type(self):
@@ -5620,7 +5620,7 @@ class SimpleCallNode(CallNode):
return
elif hasattr(self.function, 'entry'):
overloaded_entry = self.function.entry
- elif self.function.is_subscript and self.function.is_fused_index:
+ elif self.function.is_subscript and self.function.is_fused_index:
overloaded_entry = self.function.type.entry
else:
overloaded_entry = None
@@ -5632,8 +5632,8 @@ class SimpleCallNode(CallNode):
else:
alternatives = overloaded_entry.all_alternatives()
- entry = PyrexTypes.best_match(
- [arg.type for arg in args], alternatives, self.pos, env, args)
+ entry = PyrexTypes.best_match(
+ [arg.type for arg in args], alternatives, self.pos, env, args)
if not entry:
self.type = PyrexTypes.error_type
@@ -5641,8 +5641,8 @@ class SimpleCallNode(CallNode):
return
entry.used = True
- if not func_type.is_cpp_class:
- self.function.entry = entry
+ if not func_type.is_cpp_class:
+ self.function.entry = entry
self.function.type = entry.type
func_type = self.function_type()
else:
@@ -5692,7 +5692,7 @@ class SimpleCallNode(CallNode):
# Coerce arguments
some_args_in_temps = False
- for i in range(min(max_nargs, actual_nargs)):
+ for i in range(min(max_nargs, actual_nargs)):
formal_arg = func_type.args[i]
formal_type = formal_arg.type
arg = args[i].coerce_to(formal_type, env)
@@ -5722,13 +5722,13 @@ class SimpleCallNode(CallNode):
args[i] = arg
# handle additional varargs parameters
- for i in range(max_nargs, actual_nargs):
+ for i in range(max_nargs, actual_nargs):
arg = args[i]
if arg.type.is_pyobject:
- if arg.type is str_type:
- arg_ctype = PyrexTypes.c_char_ptr_type
- else:
- arg_ctype = arg.type.default_coerced_ctype()
+ if arg.type is str_type:
+ arg_ctype = PyrexTypes.c_char_ptr_type
+ else:
+ arg_ctype = arg.type.default_coerced_ctype()
if arg_ctype is None:
error(self.args[i].pos,
"Python object cannot be passed as a varargs parameter")
@@ -5743,7 +5743,7 @@ class SimpleCallNode(CallNode):
# sure they are either all temps or all not temps (except
# for the last argument, which is evaluated last in any
# case)
- for i in range(actual_nargs-1):
+ for i in range(actual_nargs-1):
if i == 0 and self.self is not None:
continue # self is ok
arg = args[i]
@@ -5774,22 +5774,22 @@ class SimpleCallNode(CallNode):
self.type = func_type.return_type
if self.function.is_name or self.function.is_attribute:
- func_entry = self.function.entry
- if func_entry and (func_entry.utility_code or func_entry.utility_code_definition):
- self.is_temp = 1 # currently doesn't work for self.calculate_result_code()
+ func_entry = self.function.entry
+ if func_entry and (func_entry.utility_code or func_entry.utility_code_definition):
+ self.is_temp = 1 # currently doesn't work for self.calculate_result_code()
if self.type.is_pyobject:
self.result_ctype = py_object_type
self.is_temp = 1
- elif func_type.exception_value is not None or func_type.exception_check:
+ elif func_type.exception_value is not None or func_type.exception_check:
self.is_temp = 1
elif self.type.is_memoryviewslice:
self.is_temp = 1
# func_type.exception_check = True
- if self.is_temp and self.type.is_reference:
- self.type = PyrexTypes.CFakeReferenceType(self.type.ref_base_type)
-
+ if self.is_temp and self.type.is_reference:
+ self.type = PyrexTypes.CFakeReferenceType(self.type.ref_base_type)
+
# Called in 'nogil' context?
self.nogil = env.nogil
if (self.nogil and
@@ -5836,12 +5836,12 @@ class SimpleCallNode(CallNode):
result = "%s(%s)" % (self.function.result(), ', '.join(arg_list_code))
return result
- def is_c_result_required(self):
- func_type = self.function_type()
- if not func_type.exception_value or func_type.exception_check == '+':
- return False # skip allocation of unused result temp
- return True
-
+ def is_c_result_required(self):
+ func_type = self.function_type()
+ if not func_type.exception_value or func_type.exception_check == '+':
+ return False # skip allocation of unused result temp
+ return True
+
def generate_evaluation_code(self, code):
function = self.function
if function.is_name or function.is_attribute:
@@ -5934,7 +5934,7 @@ class SimpleCallNode(CallNode):
elif self.type.is_memoryviewslice:
assert self.is_temp
exc_checks.append(self.type.error_condition(self.result()))
- elif func_type.exception_check != '+':
+ elif func_type.exception_check != '+':
exc_val = func_type.exception_value
exc_check = func_type.exception_check
if exc_val is not None:
@@ -5956,9 +5956,9 @@ class SimpleCallNode(CallNode):
else:
lhs = ""
if func_type.exception_check == '+':
- translate_cpp_exception(code, self.pos, '%s%s;' % (lhs, rhs),
- self.result() if self.type.is_pyobject else None,
- func_type.exception_value, self.nogil)
+ translate_cpp_exception(code, self.pos, '%s%s;' % (lhs, rhs),
+ self.result() if self.type.is_pyobject else None,
+ func_type.exception_value, self.nogil)
else:
if exc_checks:
goto_error = code.error_goto_if(" && ".join(exc_checks), self.pos)
@@ -5992,7 +5992,7 @@ class NumPyMethodCallNode(ExprNode):
code.putln("// function evaluation code for numpy function")
code.putln("__Pyx_call_destructor(%s);" % self.result())
- code.putln("new (&%s) decltype(%s){%s{}(%s)};" % (
+ code.putln("new (&%s) decltype(%s){%s{}(%s)};" % (
self.result(),
self.result(),
self.function_cname,
@@ -6034,7 +6034,7 @@ class PyMethodCallNode(SimpleCallNode):
code.putln("%s = NULL;" % self_arg)
arg_offset_cname = None
if len(args) > 1:
- arg_offset_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
+ arg_offset_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
code.putln("%s = 0;" % arg_offset_cname)
def attribute_is_likely_method(attr):
@@ -6058,7 +6058,7 @@ class PyMethodCallNode(SimpleCallNode):
else:
likely_method = 'unlikely'
- code.putln("if (CYTHON_UNPACK_METHODS && %s(PyMethod_Check(%s))) {" % (likely_method, function))
+ code.putln("if (CYTHON_UNPACK_METHODS && %s(PyMethod_Check(%s))) {" % (likely_method, function))
code.putln("%s = PyMethod_GET_SELF(%s);" % (self_arg, function))
# the following is always true in Py3 (kept only for safety),
# but is false for unbound methods in Py2
@@ -6076,85 +6076,85 @@ class PyMethodCallNode(SimpleCallNode):
if not args:
# fastest special case: try to avoid tuple creation
code.globalstate.use_utility_code(
- UtilityCode.load_cached("PyObjectCallNoArg", "ObjectHandling.c"))
- code.globalstate.use_utility_code(
+ UtilityCode.load_cached("PyObjectCallNoArg", "ObjectHandling.c"))
+ code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectCallOneArg", "ObjectHandling.c"))
code.putln(
- "%s = (%s) ? __Pyx_PyObject_CallOneArg(%s, %s) : __Pyx_PyObject_CallNoArg(%s);" % (
- self.result(), self_arg,
+ "%s = (%s) ? __Pyx_PyObject_CallOneArg(%s, %s) : __Pyx_PyObject_CallNoArg(%s);" % (
+ self.result(), self_arg,
function, self_arg,
- function))
- code.put_xdecref_clear(self_arg, py_object_type)
+ function))
+ code.put_xdecref_clear(self_arg, py_object_type)
code.funcstate.release_temp(self_arg)
- code.putln(code.error_goto_if_null(self.result(), self.pos))
- code.put_gotref(self.py_result())
- elif len(args) == 1:
- # fastest special case: try to avoid tuple creation
+ code.putln(code.error_goto_if_null(self.result(), self.pos))
+ code.put_gotref(self.py_result())
+ elif len(args) == 1:
+ # fastest special case: try to avoid tuple creation
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached("PyObjectCall2Args", "ObjectHandling.c"))
code.globalstate.use_utility_code(
- UtilityCode.load_cached("PyObjectCall2Args", "ObjectHandling.c"))
- code.globalstate.use_utility_code(
- UtilityCode.load_cached("PyObjectCallOneArg", "ObjectHandling.c"))
- arg = args[0]
+ UtilityCode.load_cached("PyObjectCallOneArg", "ObjectHandling.c"))
+ arg = args[0]
code.putln(
- "%s = (%s) ? __Pyx_PyObject_Call2Args(%s, %s, %s) : __Pyx_PyObject_CallOneArg(%s, %s);" % (
- self.result(), self_arg,
- function, self_arg, arg.py_result(),
- function, arg.py_result()))
- code.put_xdecref_clear(self_arg, py_object_type)
- code.funcstate.release_temp(self_arg)
- arg.generate_disposal_code(code)
- arg.free_temps(code)
- code.putln(code.error_goto_if_null(self.result(), self.pos))
+ "%s = (%s) ? __Pyx_PyObject_Call2Args(%s, %s, %s) : __Pyx_PyObject_CallOneArg(%s, %s);" % (
+ self.result(), self_arg,
+ function, self_arg, arg.py_result(),
+ function, arg.py_result()))
+ code.put_xdecref_clear(self_arg, py_object_type)
+ code.funcstate.release_temp(self_arg)
+ arg.generate_disposal_code(code)
+ arg.free_temps(code)
+ code.putln(code.error_goto_if_null(self.result(), self.pos))
code.put_gotref(self.py_result())
else:
- code.globalstate.use_utility_code(
- UtilityCode.load_cached("PyFunctionFastCall", "ObjectHandling.c"))
- code.globalstate.use_utility_code(
- UtilityCode.load_cached("PyCFunctionFastCall", "ObjectHandling.c"))
- for test_func, call_prefix in [('PyFunction_Check', 'Py'), ('__Pyx_PyFastCFunction_Check', 'PyC')]:
- code.putln("#if CYTHON_FAST_%sCALL" % call_prefix.upper())
- code.putln("if (%s(%s)) {" % (test_func, function))
- code.putln("PyObject *%s[%d] = {%s, %s};" % (
- Naming.quick_temp_cname,
- len(args)+1,
- self_arg,
- ', '.join(arg.py_result() for arg in args)))
- code.putln("%s = __Pyx_%sFunction_FastCall(%s, %s+1-%s, %d+%s); %s" % (
- self.result(),
- call_prefix,
- function,
- Naming.quick_temp_cname,
- arg_offset_cname,
- len(args),
- arg_offset_cname,
- code.error_goto_if_null(self.result(), self.pos)))
- code.put_xdecref_clear(self_arg, py_object_type)
- code.put_gotref(self.py_result())
- for arg in args:
- arg.generate_disposal_code(code)
- code.putln("} else")
- code.putln("#endif")
-
- code.putln("{")
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached("PyFunctionFastCall", "ObjectHandling.c"))
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached("PyCFunctionFastCall", "ObjectHandling.c"))
+ for test_func, call_prefix in [('PyFunction_Check', 'Py'), ('__Pyx_PyFastCFunction_Check', 'PyC')]:
+ code.putln("#if CYTHON_FAST_%sCALL" % call_prefix.upper())
+ code.putln("if (%s(%s)) {" % (test_func, function))
+ code.putln("PyObject *%s[%d] = {%s, %s};" % (
+ Naming.quick_temp_cname,
+ len(args)+1,
+ self_arg,
+ ', '.join(arg.py_result() for arg in args)))
+ code.putln("%s = __Pyx_%sFunction_FastCall(%s, %s+1-%s, %d+%s); %s" % (
+ self.result(),
+ call_prefix,
+ function,
+ Naming.quick_temp_cname,
+ arg_offset_cname,
+ len(args),
+ arg_offset_cname,
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_xdecref_clear(self_arg, py_object_type)
+ code.put_gotref(self.py_result())
+ for arg in args:
+ arg.generate_disposal_code(code)
+ code.putln("} else")
+ code.putln("#endif")
+
+ code.putln("{")
args_tuple = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
code.putln("%s = PyTuple_New(%d+%s); %s" % (
- args_tuple, len(args), arg_offset_cname,
+ args_tuple, len(args), arg_offset_cname,
code.error_goto_if_null(args_tuple, self.pos)))
code.put_gotref(args_tuple)
if len(args) > 1:
code.putln("if (%s) {" % self_arg)
- code.putln("__Pyx_GIVEREF(%s); PyTuple_SET_ITEM(%s, 0, %s); %s = NULL;" % (
- self_arg, args_tuple, self_arg, self_arg)) # stealing owned ref in this case
+ code.putln("__Pyx_GIVEREF(%s); PyTuple_SET_ITEM(%s, 0, %s); %s = NULL;" % (
+ self_arg, args_tuple, self_arg, self_arg)) # stealing owned ref in this case
code.funcstate.release_temp(self_arg)
if len(args) > 1:
code.putln("}")
for i, arg in enumerate(args):
arg.make_owned_reference(code)
- code.put_giveref(arg.py_result())
+ code.put_giveref(arg.py_result())
code.putln("PyTuple_SET_ITEM(%s, %d+%s, %s);" % (
- args_tuple, i, arg_offset_cname, arg.py_result()))
+ args_tuple, i, arg_offset_cname, arg.py_result()))
if len(args) > 1:
code.funcstate.release_temp(arg_offset_cname)
@@ -6176,7 +6176,7 @@ class PyMethodCallNode(SimpleCallNode):
if len(args) == 1:
code.putln("}")
- code.putln("}") # !CYTHON_FAST_PYCALL
+ code.putln("}") # !CYTHON_FAST_PYCALL
if reuse_function_temp:
self.function.generate_disposal_code(code)
@@ -6205,8 +6205,8 @@ class InlinedDefNodeCallNode(CallNode):
return False
if len(func_type.args) != len(self.args):
return False
- if func_type.num_kwonly_args:
- return False # actually wrong number of arguments
+ if func_type.num_kwonly_args:
+ return False # actually wrong number of arguments
return True
def analyse_types(self, env):
@@ -6218,7 +6218,7 @@ class InlinedDefNodeCallNode(CallNode):
# Coerce arguments
some_args_in_temps = False
- for i in range(actual_nargs):
+ for i in range(actual_nargs):
formal_type = func_type.args[i].type
arg = self.args[i].coerce_to(formal_type, env)
if arg.is_temp:
@@ -6245,7 +6245,7 @@ class InlinedDefNodeCallNode(CallNode):
# sure they are either all temps or all not temps (except
# for the last argument, which is evaluated last in any
# case)
- for i in range(actual_nargs-1):
+ for i in range(actual_nargs-1):
arg = self.args[i]
if arg.nonlocally_immutable():
# locals, C functions, unassignable types are safe.
@@ -6374,12 +6374,12 @@ class GeneralCallNode(CallNode):
keyword_args = self.keyword_args.compile_time_value(denv)
try:
return function(*positional_args, **keyword_args)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def explicit_args_kwds(self):
- if (self.keyword_args and not self.keyword_args.is_dict_literal or
- not self.positional_args.is_sequence_constructor):
+ if (self.keyword_args and not self.keyword_args.is_dict_literal or
+ not self.positional_args.is_sequence_constructor):
raise CompileError(self.pos,
'Compile-time keyword arguments must be explicit.')
return self.positional_args.args, self.keyword_args
@@ -6425,7 +6425,7 @@ class GeneralCallNode(CallNode):
if not isinstance(self.positional_args, TupleNode):
# has starred argument
return self
- if not self.keyword_args.is_dict_literal:
+ if not self.keyword_args.is_dict_literal:
# keywords come from arbitrary expression => nothing to do here
return self
function = self.function
@@ -6588,13 +6588,13 @@ class AsTupleNode(ExprNode):
arg = self.arg.compile_time_value(denv)
try:
return tuple(arg)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def analyse_types(self, env):
- self.arg = self.arg.analyse_types(env).coerce_to_pyobject(env)
- if self.arg.type is tuple_type:
- return self.arg.as_none_safe_node("'NoneType' object is not iterable")
+ self.arg = self.arg.analyse_types(env).coerce_to_pyobject(env)
+ if self.arg.type is tuple_type:
+ return self.arg.as_none_safe_node("'NoneType' object is not iterable")
self.type = tuple_type
return self
@@ -6614,159 +6614,159 @@ class AsTupleNode(ExprNode):
code.put_gotref(self.py_result())
-class MergedDictNode(ExprNode):
- # Helper class for keyword arguments and other merged dicts.
- #
- # keyword_args [DictNode or other ExprNode]
-
- subexprs = ['keyword_args']
- is_temp = 1
- type = dict_type
- reject_duplicates = True
-
- def calculate_constant_result(self):
- result = {}
- reject_duplicates = self.reject_duplicates
- for item in self.keyword_args:
- if item.is_dict_literal:
- # process items in order
- items = ((key.constant_result, value.constant_result)
- for key, value in item.key_value_pairs)
- else:
- items = item.constant_result.iteritems()
-
- for key, value in items:
- if reject_duplicates and key in result:
- raise ValueError("duplicate keyword argument found: %s" % key)
- result[key] = value
-
- self.constant_result = result
-
- def compile_time_value(self, denv):
- result = {}
- reject_duplicates = self.reject_duplicates
- for item in self.keyword_args:
- if item.is_dict_literal:
- # process items in order
- items = [(key.compile_time_value(denv), value.compile_time_value(denv))
- for key, value in item.key_value_pairs]
- else:
- items = item.compile_time_value(denv).iteritems()
-
- try:
- for key, value in items:
- if reject_duplicates and key in result:
- raise ValueError("duplicate keyword argument found: %s" % key)
- result[key] = value
- except Exception as e:
- self.compile_time_value_error(e)
- return result
-
- def type_dependencies(self, env):
- return ()
-
- def infer_type(self, env):
- return dict_type
-
- def analyse_types(self, env):
+class MergedDictNode(ExprNode):
+ # Helper class for keyword arguments and other merged dicts.
+ #
+ # keyword_args [DictNode or other ExprNode]
+
+ subexprs = ['keyword_args']
+ is_temp = 1
+ type = dict_type
+ reject_duplicates = True
+
+ def calculate_constant_result(self):
+ result = {}
+ reject_duplicates = self.reject_duplicates
+ for item in self.keyword_args:
+ if item.is_dict_literal:
+ # process items in order
+ items = ((key.constant_result, value.constant_result)
+ for key, value in item.key_value_pairs)
+ else:
+ items = item.constant_result.iteritems()
+
+ for key, value in items:
+ if reject_duplicates and key in result:
+ raise ValueError("duplicate keyword argument found: %s" % key)
+ result[key] = value
+
+ self.constant_result = result
+
+ def compile_time_value(self, denv):
+ result = {}
+ reject_duplicates = self.reject_duplicates
+ for item in self.keyword_args:
+ if item.is_dict_literal:
+ # process items in order
+ items = [(key.compile_time_value(denv), value.compile_time_value(denv))
+ for key, value in item.key_value_pairs]
+ else:
+ items = item.compile_time_value(denv).iteritems()
+
+ try:
+ for key, value in items:
+ if reject_duplicates and key in result:
+ raise ValueError("duplicate keyword argument found: %s" % key)
+ result[key] = value
+ except Exception as e:
+ self.compile_time_value_error(e)
+ return result
+
+ def type_dependencies(self, env):
+ return ()
+
+ def infer_type(self, env):
+ return dict_type
+
+ def analyse_types(self, env):
self.keyword_args = [
- arg.analyse_types(env).coerce_to_pyobject(env).as_none_safe_node(
- # FIXME: CPython's error message starts with the runtime function name
- 'argument after ** must be a mapping, not NoneType')
- for arg in self.keyword_args
- ]
-
- return self
-
- def may_be_none(self):
- return False
-
- gil_message = "Constructing Python dict"
-
- def generate_evaluation_code(self, code):
- code.mark_pos(self.pos)
- self.allocate_temp_result(code)
-
- args = iter(self.keyword_args)
- item = next(args)
- item.generate_evaluation_code(code)
- if item.type is not dict_type:
- # CPython supports calling functions with non-dicts, so do we
- code.putln('if (likely(PyDict_CheckExact(%s))) {' %
- item.py_result())
-
- if item.is_dict_literal:
- item.make_owned_reference(code)
- code.putln("%s = %s;" % (self.result(), item.py_result()))
- item.generate_post_assignment_code(code)
- else:
- code.putln("%s = PyDict_Copy(%s); %s" % (
- self.result(),
- item.py_result(),
- code.error_goto_if_null(self.result(), item.pos)))
- code.put_gotref(self.result())
- item.generate_disposal_code(code)
-
- if item.type is not dict_type:
- code.putln('} else {')
- code.putln("%s = PyObject_CallFunctionObjArgs((PyObject*)&PyDict_Type, %s, NULL); %s" % (
- self.result(),
- item.py_result(),
- code.error_goto_if_null(self.result(), self.pos)))
- code.put_gotref(self.py_result())
- item.generate_disposal_code(code)
- code.putln('}')
- item.free_temps(code)
-
- helpers = set()
- for item in args:
- if item.is_dict_literal:
- # inline update instead of creating an intermediate dict
- for arg in item.key_value_pairs:
- arg.generate_evaluation_code(code)
- if self.reject_duplicates:
- code.putln("if (unlikely(PyDict_Contains(%s, %s))) {" % (
- self.result(),
- arg.key.py_result()))
- helpers.add("RaiseDoubleKeywords")
- # FIXME: find out function name at runtime!
- code.putln('__Pyx_RaiseDoubleKeywordsError("function", %s); %s' % (
- arg.key.py_result(),
- code.error_goto(self.pos)))
- code.putln("}")
- code.put_error_if_neg(arg.key.pos, "PyDict_SetItem(%s, %s, %s)" % (
- self.result(),
- arg.key.py_result(),
- arg.value.py_result()))
- arg.generate_disposal_code(code)
- arg.free_temps(code)
- else:
- item.generate_evaluation_code(code)
- if self.reject_duplicates:
- # merge mapping into kwdict one by one as we need to check for duplicates
- helpers.add("MergeKeywords")
- code.put_error_if_neg(item.pos, "__Pyx_MergeKeywords(%s, %s)" % (
- self.result(), item.py_result()))
- else:
- # simple case, just add all entries
- helpers.add("RaiseMappingExpected")
- code.putln("if (unlikely(PyDict_Update(%s, %s) < 0)) {" % (
- self.result(), item.py_result()))
- code.putln("if (PyErr_ExceptionMatches(PyExc_AttributeError)) "
- "__Pyx_RaiseMappingExpectedError(%s);" % item.py_result())
- code.putln(code.error_goto(item.pos))
- code.putln("}")
- item.generate_disposal_code(code)
- item.free_temps(code)
-
- for helper in sorted(helpers):
- code.globalstate.use_utility_code(UtilityCode.load_cached(helper, "FunctionArguments.c"))
-
- def annotate(self, code):
- for item in self.keyword_args:
- item.annotate(code)
-
-
+ arg.analyse_types(env).coerce_to_pyobject(env).as_none_safe_node(
+ # FIXME: CPython's error message starts with the runtime function name
+ 'argument after ** must be a mapping, not NoneType')
+ for arg in self.keyword_args
+ ]
+
+ return self
+
+ def may_be_none(self):
+ return False
+
+ gil_message = "Constructing Python dict"
+
+ def generate_evaluation_code(self, code):
+ code.mark_pos(self.pos)
+ self.allocate_temp_result(code)
+
+ args = iter(self.keyword_args)
+ item = next(args)
+ item.generate_evaluation_code(code)
+ if item.type is not dict_type:
+ # CPython supports calling functions with non-dicts, so do we
+ code.putln('if (likely(PyDict_CheckExact(%s))) {' %
+ item.py_result())
+
+ if item.is_dict_literal:
+ item.make_owned_reference(code)
+ code.putln("%s = %s;" % (self.result(), item.py_result()))
+ item.generate_post_assignment_code(code)
+ else:
+ code.putln("%s = PyDict_Copy(%s); %s" % (
+ self.result(),
+ item.py_result(),
+ code.error_goto_if_null(self.result(), item.pos)))
+ code.put_gotref(self.result())
+ item.generate_disposal_code(code)
+
+ if item.type is not dict_type:
+ code.putln('} else {')
+ code.putln("%s = PyObject_CallFunctionObjArgs((PyObject*)&PyDict_Type, %s, NULL); %s" % (
+ self.result(),
+ item.py_result(),
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.py_result())
+ item.generate_disposal_code(code)
+ code.putln('}')
+ item.free_temps(code)
+
+ helpers = set()
+ for item in args:
+ if item.is_dict_literal:
+ # inline update instead of creating an intermediate dict
+ for arg in item.key_value_pairs:
+ arg.generate_evaluation_code(code)
+ if self.reject_duplicates:
+ code.putln("if (unlikely(PyDict_Contains(%s, %s))) {" % (
+ self.result(),
+ arg.key.py_result()))
+ helpers.add("RaiseDoubleKeywords")
+ # FIXME: find out function name at runtime!
+ code.putln('__Pyx_RaiseDoubleKeywordsError("function", %s); %s' % (
+ arg.key.py_result(),
+ code.error_goto(self.pos)))
+ code.putln("}")
+ code.put_error_if_neg(arg.key.pos, "PyDict_SetItem(%s, %s, %s)" % (
+ self.result(),
+ arg.key.py_result(),
+ arg.value.py_result()))
+ arg.generate_disposal_code(code)
+ arg.free_temps(code)
+ else:
+ item.generate_evaluation_code(code)
+ if self.reject_duplicates:
+ # merge mapping into kwdict one by one as we need to check for duplicates
+ helpers.add("MergeKeywords")
+ code.put_error_if_neg(item.pos, "__Pyx_MergeKeywords(%s, %s)" % (
+ self.result(), item.py_result()))
+ else:
+ # simple case, just add all entries
+ helpers.add("RaiseMappingExpected")
+ code.putln("if (unlikely(PyDict_Update(%s, %s) < 0)) {" % (
+ self.result(), item.py_result()))
+ code.putln("if (PyErr_ExceptionMatches(PyExc_AttributeError)) "
+ "__Pyx_RaiseMappingExpectedError(%s);" % item.py_result())
+ code.putln(code.error_goto(item.pos))
+ code.putln("}")
+ item.generate_disposal_code(code)
+ item.free_temps(code)
+
+ for helper in sorted(helpers):
+ code.globalstate.use_utility_code(UtilityCode.load_cached(helper, "FunctionArguments.c"))
+
+ def annotate(self, code):
+ for item in self.keyword_args:
+ item.annotate(code)
+
+
class AttributeNode(ExprNode):
# obj.attribute
#
@@ -6791,7 +6791,7 @@ class AttributeNode(ExprNode):
needs_none_check = True
is_memslice_transpose = False
is_special_lookup = False
- is_py_attr = 0
+ is_py_attr = 0
def as_cython_attribute(self):
if (isinstance(self.obj, NameNode) and
@@ -6832,7 +6832,7 @@ class AttributeNode(ExprNode):
obj = self.obj.compile_time_value(denv)
try:
return getattr(obj, attr)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def type_dependencies(self, env):
@@ -6847,7 +6847,7 @@ class AttributeNode(ExprNode):
return PyrexTypes.CPtrType(node.entry.type)
else:
return node.entry.type
- node = self.analyse_as_type_attribute(env)
+ node = self.analyse_as_type_attribute(env)
if node is not None:
return node.entry.type
obj_type = self.obj.infer_type(env)
@@ -6857,10 +6857,10 @@ class AttributeNode(ExprNode):
# builtin types cannot be inferred as C functions as
# that would prevent their use as bound methods
return py_object_type
- elif self.entry and self.entry.is_cmethod:
- # special case: bound methods should not be inferred
- # as their unbound method types
- return py_object_type
+ elif self.entry and self.entry.is_cmethod:
+ # special case: bound methods should not be inferred
+ # as their unbound method types
+ return py_object_type
return self.type
def analyse_target_declaration(self, env):
@@ -6878,7 +6878,7 @@ class AttributeNode(ExprNode):
self.initialized_check = env.directives['initializedcheck']
node = self.analyse_as_cimported_attribute_node(env, target)
if node is None and not target:
- node = self.analyse_as_type_attribute(env)
+ node = self.analyse_as_type_attribute(env)
if node is None:
node = self.analyse_as_ordinary_attribute_node(env, target)
assert node is not None
@@ -6905,7 +6905,7 @@ class AttributeNode(ExprNode):
return self
return None
- def analyse_as_type_attribute(self, env):
+ def analyse_as_type_attribute(self, env):
# Try to interpret this as a reference to an unbound
# C method of an extension type or builtin type. If successful,
# creates a corresponding NameNode and returns it, otherwise
@@ -6913,49 +6913,49 @@ class AttributeNode(ExprNode):
if self.obj.is_string_literal:
return
type = self.obj.analyse_as_type(env)
- if type:
- if type.is_extension_type or type.is_builtin_type or type.is_cpp_class:
- entry = type.scope.lookup_here(self.attribute)
- if entry and (entry.is_cmethod or type.is_cpp_class and entry.type.is_cfunction):
- if type.is_builtin_type:
- if not self.is_called:
- # must handle this as Python object
- return None
- ubcm_entry = entry
- else:
- # Create a temporary entry describing the C method
- # as an ordinary function.
- if entry.func_cname and not hasattr(entry.type, 'op_arg_struct'):
- cname = entry.func_cname
- if entry.type.is_static_method or (
- env.parent_scope and env.parent_scope.is_cpp_class_scope):
- ctype = entry.type
- elif type.is_cpp_class:
- error(self.pos, "%s not a static member of %s" % (entry.name, type))
- ctype = PyrexTypes.error_type
- else:
- # Fix self type.
- ctype = copy.copy(entry.type)
- ctype.args = ctype.args[:]
- ctype.args[0] = PyrexTypes.CFuncTypeArg('self', type, 'self', None)
- else:
- cname = "%s->%s" % (type.vtabptr_cname, entry.cname)
+ if type:
+ if type.is_extension_type or type.is_builtin_type or type.is_cpp_class:
+ entry = type.scope.lookup_here(self.attribute)
+ if entry and (entry.is_cmethod or type.is_cpp_class and entry.type.is_cfunction):
+ if type.is_builtin_type:
+ if not self.is_called:
+ # must handle this as Python object
+ return None
+ ubcm_entry = entry
+ else:
+ # Create a temporary entry describing the C method
+ # as an ordinary function.
+ if entry.func_cname and not hasattr(entry.type, 'op_arg_struct'):
+ cname = entry.func_cname
+ if entry.type.is_static_method or (
+ env.parent_scope and env.parent_scope.is_cpp_class_scope):
+ ctype = entry.type
+ elif type.is_cpp_class:
+ error(self.pos, "%s not a static member of %s" % (entry.name, type))
+ ctype = PyrexTypes.error_type
+ else:
+ # Fix self type.
+ ctype = copy.copy(entry.type)
+ ctype.args = ctype.args[:]
+ ctype.args[0] = PyrexTypes.CFuncTypeArg('self', type, 'self', None)
+ else:
+ cname = "%s->%s" % (type.vtabptr_cname, entry.cname)
ctype = entry.type
- ubcm_entry = Symtab.Entry(entry.name, cname, ctype)
- ubcm_entry.is_cfunction = 1
- ubcm_entry.func_cname = entry.func_cname
- ubcm_entry.is_unbound_cmethod = 1
- ubcm_entry.scope = entry.scope
- return self.as_name_node(env, ubcm_entry, target=False)
- elif type.is_enum:
- if self.attribute in type.values:
- for entry in type.entry.enum_values:
- if entry.name == self.attribute:
- return self.as_name_node(env, entry, target=False)
+ ubcm_entry = Symtab.Entry(entry.name, cname, ctype)
+ ubcm_entry.is_cfunction = 1
+ ubcm_entry.func_cname = entry.func_cname
+ ubcm_entry.is_unbound_cmethod = 1
+ ubcm_entry.scope = entry.scope
+ return self.as_name_node(env, ubcm_entry, target=False)
+ elif type.is_enum:
+ if self.attribute in type.values:
+ for entry in type.entry.enum_values:
+ if entry.name == self.attribute:
+ return self.as_name_node(env, entry, target=False)
else:
- error(self.pos, "%s not a known value of %s" % (self.attribute, type))
- else:
- error(self.pos, "%s not a known value of %s" % (self.attribute, type))
+ error(self.pos, "%s not a known value of %s" % (self.attribute, type))
+ else:
+ error(self.pos, "%s not a known value of %s" % (self.attribute, type))
return None
def analyse_as_type(self, env):
@@ -7036,23 +7036,23 @@ class AttributeNode(ExprNode):
self.op = "->"
elif obj_type.is_extension_type or obj_type.is_builtin_type:
self.op = "->"
- elif obj_type.is_reference and obj_type.is_fake_reference:
- self.op = "->"
+ elif obj_type.is_reference and obj_type.is_fake_reference:
+ self.op = "->"
else:
self.op = "."
if obj_type.has_attributes:
if obj_type.attributes_known():
- entry = obj_type.scope.lookup_here(self.attribute)
- if obj_type.is_memoryviewslice and not entry:
+ entry = obj_type.scope.lookup_here(self.attribute)
+ if obj_type.is_memoryviewslice and not entry:
if self.attribute == 'T':
self.is_memslice_transpose = True
self.is_temp = True
self.use_managed_ref = True
- self.type = self.obj.type.transpose(self.pos)
+ self.type = self.obj.type.transpose(self.pos)
return
else:
obj_type.declare_attribute(self.attribute, env, self.pos)
- entry = obj_type.scope.lookup_here(self.attribute)
+ entry = obj_type.scope.lookup_here(self.attribute)
if entry and entry.is_member:
entry = None
else:
@@ -7156,7 +7156,7 @@ class AttributeNode(ExprNode):
def is_lvalue(self):
if self.obj:
- return True
+ return True
else:
return NameNode.is_lvalue(self)
@@ -7231,7 +7231,7 @@ class AttributeNode(ExprNode):
return
code.putln("%s = %s;" % (self.result(), self.obj.result()))
- code.put_incref_memoryviewslice(self.result(), have_gil=True)
+ code.put_incref_memoryviewslice(self.result(), have_gil=True)
T = "__pyx_memslice_transpose(&%s) == 0"
code.putln(code.error_goto_if(T % self.result(), self.pos))
@@ -7245,24 +7245,24 @@ class AttributeNode(ExprNode):
else:
# result_code contains what is needed, but we may need to insert
# a check and raise an exception
- if self.obj.type and self.obj.type.is_extension_type:
+ if self.obj.type and self.obj.type.is_extension_type:
pass
- elif self.entry and self.entry.is_cmethod:
+ elif self.entry and self.entry.is_cmethod:
# C method implemented as function call with utility code
- code.globalstate.use_entry_utility_code(self.entry)
+ code.globalstate.use_entry_utility_code(self.entry)
def generate_disposal_code(self, code):
if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose:
# mirror condition for putting the memview incref here:
- code.put_xdecref_memoryviewslice(
- self.result(), have_gil=True)
- code.putln("%s.memview = NULL;" % self.result())
- code.putln("%s.data = NULL;" % self.result())
+ code.put_xdecref_memoryviewslice(
+ self.result(), have_gil=True)
+ code.putln("%s.memview = NULL;" % self.result())
+ code.putln("%s.data = NULL;" % self.result())
else:
ExprNode.generate_disposal_code(self, code)
- def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
- exception_check=None, exception_value=None):
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
+ exception_check=None, exception_value=None):
self.obj.generate_evaluation_code(code)
if self.is_py_attr:
code.globalstate.use_utility_code(
@@ -7333,14 +7333,14 @@ class AttributeNode(ExprNode):
#
#-------------------------------------------------------------------
-class StarredUnpackingNode(ExprNode):
+class StarredUnpackingNode(ExprNode):
# A starred expression like "*a"
#
- # This is only allowed in sequence assignment or construction such as
+ # This is only allowed in sequence assignment or construction such as
#
# a, *b = (1,2,3,4) => a = 1 ; b = [2,3,4]
#
- # and will be special cased during type analysis (or generate an error
+ # and will be special cased during type analysis (or generate an error
# if it's found at unexpected places).
#
# target ExprNode
@@ -7349,22 +7349,22 @@ class StarredUnpackingNode(ExprNode):
is_starred = 1
type = py_object_type
is_temp = 1
- starred_expr_allowed_here = False
+ starred_expr_allowed_here = False
def __init__(self, pos, target):
- ExprNode.__init__(self, pos, target=target)
+ ExprNode.__init__(self, pos, target=target)
def analyse_declarations(self, env):
- if not self.starred_expr_allowed_here:
- error(self.pos, "starred expression is not allowed here")
+ if not self.starred_expr_allowed_here:
+ error(self.pos, "starred expression is not allowed here")
self.target.analyse_declarations(env)
- def infer_type(self, env):
- return self.target.infer_type(env)
-
+ def infer_type(self, env):
+ return self.target.infer_type(env)
+
def analyse_types(self, env):
- if not self.starred_expr_allowed_here:
- error(self.pos, "starred expression is not allowed here")
+ if not self.starred_expr_allowed_here:
+ error(self.pos, "starred expression is not allowed here")
self.target = self.target.analyse_types(env)
self.type = self.target.type
return self
@@ -7423,9 +7423,9 @@ class SequenceNode(ExprNode):
arg.analyse_target_declaration(env)
def analyse_types(self, env, skip_children=False):
- for i, arg in enumerate(self.args):
- if not skip_children:
- arg = arg.analyse_types(env)
+ for i, arg in enumerate(self.args):
+ if not skip_children:
+ arg = arg.analyse_types(env)
self.args[i] = arg.coerce_to_pyobject(env)
if self.mult_factor:
self.mult_factor = self.mult_factor.analyse_types(env)
@@ -7435,49 +7435,49 @@ class SequenceNode(ExprNode):
# not setting self.type here, subtypes do this
return self
- def coerce_to_ctuple(self, dst_type, env):
- if self.type == dst_type:
- return self
- assert not self.mult_factor
- if len(self.args) != dst_type.size:
- error(self.pos, "trying to coerce sequence to ctuple of wrong length, expected %d, got %d" % (
- dst_type.size, len(self.args)))
- coerced_args = [arg.coerce_to(type, env) for arg, type in zip(self.args, dst_type.components)]
- return TupleNode(self.pos, args=coerced_args, type=dst_type, is_temp=True)
-
- def _create_merge_node_if_necessary(self, env):
- self._flatten_starred_args()
- if not any(arg.is_starred for arg in self.args):
- return self
- # convert into MergedSequenceNode by building partial sequences
- args = []
- values = []
- for arg in self.args:
- if arg.is_starred:
- if values:
- args.append(TupleNode(values[0].pos, args=values).analyse_types(env, skip_children=True))
- values = []
- args.append(arg.target)
- else:
- values.append(arg)
- if values:
- args.append(TupleNode(values[0].pos, args=values).analyse_types(env, skip_children=True))
- node = MergedSequenceNode(self.pos, args, self.type)
- if self.mult_factor:
- node = binop_node(
- self.pos, '*', node, self.mult_factor.coerce_to_pyobject(env),
- inplace=True, type=self.type, is_temp=True)
- return node
-
- def _flatten_starred_args(self):
- args = []
- for arg in self.args:
- if arg.is_starred and arg.target.is_sequence_constructor and not arg.target.mult_factor:
- args.extend(arg.target.args)
- else:
- args.append(arg)
- self.args[:] = args
-
+ def coerce_to_ctuple(self, dst_type, env):
+ if self.type == dst_type:
+ return self
+ assert not self.mult_factor
+ if len(self.args) != dst_type.size:
+ error(self.pos, "trying to coerce sequence to ctuple of wrong length, expected %d, got %d" % (
+ dst_type.size, len(self.args)))
+ coerced_args = [arg.coerce_to(type, env) for arg, type in zip(self.args, dst_type.components)]
+ return TupleNode(self.pos, args=coerced_args, type=dst_type, is_temp=True)
+
+ def _create_merge_node_if_necessary(self, env):
+ self._flatten_starred_args()
+ if not any(arg.is_starred for arg in self.args):
+ return self
+ # convert into MergedSequenceNode by building partial sequences
+ args = []
+ values = []
+ for arg in self.args:
+ if arg.is_starred:
+ if values:
+ args.append(TupleNode(values[0].pos, args=values).analyse_types(env, skip_children=True))
+ values = []
+ args.append(arg.target)
+ else:
+ values.append(arg)
+ if values:
+ args.append(TupleNode(values[0].pos, args=values).analyse_types(env, skip_children=True))
+ node = MergedSequenceNode(self.pos, args, self.type)
+ if self.mult_factor:
+ node = binop_node(
+ self.pos, '*', node, self.mult_factor.coerce_to_pyobject(env),
+ inplace=True, type=self.type, is_temp=True)
+ return node
+
+ def _flatten_starred_args(self):
+ args = []
+ for arg in self.args:
+ if arg.is_starred and arg.target.is_sequence_constructor and not arg.target.mult_factor:
+ args.extend(arg.target.args)
+ else:
+ args.append(arg)
+ self.args[:] = args
+
def may_be_none(self):
return False
@@ -7490,11 +7490,11 @@ class SequenceNode(ExprNode):
for i, arg in enumerate(self.args):
arg = self.args[i] = arg.analyse_target_types(env)
if arg.is_starred:
- if not arg.type.assignable_from(list_type):
+ if not arg.type.assignable_from(list_type):
error(arg.pos,
"starred target must have Python object (list) type")
if arg.type is py_object_type:
- arg.type = list_type
+ arg.type = list_type
unpacked_item = PyTempNode(self.pos, env)
coerced_unpacked_item = unpacked_item.coerce_to(arg.type, env)
if unpacked_item is not coerced_unpacked_item:
@@ -7517,31 +7517,31 @@ class SequenceNode(ExprNode):
mult_factor = self.mult_factor
if mult_factor.type.is_int:
c_mult = mult_factor.result()
- if (isinstance(mult_factor.constant_result, _py_int_types) and
- mult_factor.constant_result > 0):
+ if (isinstance(mult_factor.constant_result, _py_int_types) and
+ mult_factor.constant_result > 0):
size_factor = ' * %s' % mult_factor.constant_result
- elif mult_factor.type.signed:
- size_factor = ' * ((%s<0) ? 0:%s)' % (c_mult, c_mult)
+ elif mult_factor.type.signed:
+ size_factor = ' * ((%s<0) ? 0:%s)' % (c_mult, c_mult)
else:
- size_factor = ' * (%s)' % (c_mult,)
+ size_factor = ' * (%s)' % (c_mult,)
- if self.type is tuple_type and (self.is_literal or self.slow) and not c_mult:
+ if self.type is tuple_type and (self.is_literal or self.slow) and not c_mult:
# use PyTuple_Pack() to avoid generating huge amounts of one-time code
code.putln('%s = PyTuple_Pack(%d, %s); %s' % (
target,
len(self.args),
- ', '.join(arg.py_result() for arg in self.args),
+ ', '.join(arg.py_result() for arg in self.args),
code.error_goto_if_null(target, self.pos)))
code.put_gotref(target)
- elif self.type.is_ctuple:
- for i, arg in enumerate(self.args):
- code.putln("%s.f%s = %s;" % (
- target, i, arg.result()))
+ elif self.type.is_ctuple:
+ for i, arg in enumerate(self.args):
+ code.putln("%s.f%s = %s;" % (
+ target, i, arg.result()))
else:
# build the tuple/list step by step, potentially multiplying it as we go
- if self.type is list_type:
+ if self.type is list_type:
create_func, set_item_func = 'PyList_New', 'PyList_SET_ITEM'
- elif self.type is tuple_type:
+ elif self.type is tuple_type:
create_func, set_item_func = 'PyTuple_New', 'PyTuple_SET_ITEM'
else:
raise InternalError("sequence packing for unexpected type %s" % self.type)
@@ -7569,11 +7569,11 @@ class SequenceNode(ExprNode):
else:
offset = ''
- for i in range(arg_count):
+ for i in range(arg_count):
arg = self.args[i]
if c_mult or not arg.result_in_temp():
code.put_incref(arg.result(), arg.ctype())
- code.put_giveref(arg.py_result())
+ code.put_giveref(arg.py_result())
code.putln("%s(%s, %s, %s);" % (
set_item_func,
target,
@@ -7598,7 +7598,7 @@ class SequenceNode(ExprNode):
def generate_subexpr_disposal_code(self, code):
if self.mult_factor and self.mult_factor.type.is_int:
super(SequenceNode, self).generate_subexpr_disposal_code(code)
- elif self.type is tuple_type and (self.is_literal or self.slow):
+ elif self.type is tuple_type and (self.is_literal or self.slow):
super(SequenceNode, self).generate_subexpr_disposal_code(code)
else:
# We call generate_post_assignment_code here instead
@@ -7611,8 +7611,8 @@ class SequenceNode(ExprNode):
if self.mult_factor:
self.mult_factor.generate_disposal_code(code)
- def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
- exception_check=None, exception_value=None):
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
+ exception_check=None, exception_value=None):
if self.starred_assignment:
self.generate_starred_assignment_code(rhs, code)
else:
@@ -7685,7 +7685,7 @@ class SequenceNode(ExprNode):
code.putln(code.error_goto(self.pos))
code.putln("}")
- code.putln("#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS")
+ code.putln("#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS")
# unpack items from list/tuple in unrolled loop (can't fail)
if len(sequence_types) == 2:
code.putln("if (likely(Py%s_CheckExact(sequence))) {" % sequence_types[0])
@@ -7883,7 +7883,7 @@ class SequenceNode(ExprNode):
code.put_decref(target_list, py_object_type)
code.putln('%s = %s; %s = NULL;' % (target_list, sublist_temp, sublist_temp))
code.putln('#else')
- code.putln('(void)%s;' % sublist_temp) # avoid warning about unused variable
+ code.putln('(void)%s;' % sublist_temp) # avoid warning about unused variable
code.funcstate.release_temp(sublist_temp)
code.putln('#endif')
@@ -7908,82 +7908,82 @@ class TupleNode(SequenceNode):
gil_message = "Constructing Python tuple"
- def infer_type(self, env):
- if self.mult_factor or not self.args:
- return tuple_type
- arg_types = [arg.infer_type(env) for arg in self.args]
+ def infer_type(self, env):
+ if self.mult_factor or not self.args:
+ return tuple_type
+ arg_types = [arg.infer_type(env) for arg in self.args]
if any(type.is_pyobject or type.is_memoryviewslice or type.is_unspecified or type.is_fused
for type in arg_types):
- return tuple_type
+ return tuple_type
return env.declare_tuple_type(self.pos, arg_types).type
-
+
def analyse_types(self, env, skip_children=False):
if len(self.args) == 0:
- self.is_temp = False
- self.is_literal = True
- return self
-
- if not skip_children:
- for i, arg in enumerate(self.args):
- if arg.is_starred:
- arg.starred_expr_allowed_here = True
- self.args[i] = arg.analyse_types(env)
- if (not self.mult_factor and
+ self.is_temp = False
+ self.is_literal = True
+ return self
+
+ if not skip_children:
+ for i, arg in enumerate(self.args):
+ if arg.is_starred:
+ arg.starred_expr_allowed_here = True
+ self.args[i] = arg.analyse_types(env)
+ if (not self.mult_factor and
not any((arg.is_starred or arg.type.is_pyobject or arg.type.is_memoryviewslice or arg.type.is_fused)
for arg in self.args)):
- self.type = env.declare_tuple_type(self.pos, (arg.type for arg in self.args)).type
- self.is_temp = 1
- return self
-
- node = SequenceNode.analyse_types(self, env, skip_children=True)
- node = node._create_merge_node_if_necessary(env)
- if not node.is_sequence_constructor:
- return node
-
- if not all(child.is_literal for child in node.args):
- return node
- if not node.mult_factor or (
- node.mult_factor.is_literal and
- isinstance(node.mult_factor.constant_result, _py_int_types)):
+ self.type = env.declare_tuple_type(self.pos, (arg.type for arg in self.args)).type
+ self.is_temp = 1
+ return self
+
+ node = SequenceNode.analyse_types(self, env, skip_children=True)
+ node = node._create_merge_node_if_necessary(env)
+ if not node.is_sequence_constructor:
+ return node
+
+ if not all(child.is_literal for child in node.args):
+ return node
+ if not node.mult_factor or (
+ node.mult_factor.is_literal and
+ isinstance(node.mult_factor.constant_result, _py_int_types)):
node.is_temp = False
node.is_literal = True
else:
- if not node.mult_factor.type.is_pyobject:
- node.mult_factor = node.mult_factor.coerce_to_pyobject(env)
- node.is_temp = True
- node.is_partly_literal = True
+ if not node.mult_factor.type.is_pyobject:
+ node.mult_factor = node.mult_factor.coerce_to_pyobject(env)
+ node.is_temp = True
+ node.is_partly_literal = True
return node
- def analyse_as_type(self, env):
- # ctuple type
- if not self.args:
- return None
- item_types = [arg.analyse_as_type(env) for arg in self.args]
- if any(t is None for t in item_types):
- return None
- entry = env.declare_tuple_type(self.pos, item_types)
- return entry.type
-
- def coerce_to(self, dst_type, env):
- if self.type.is_ctuple:
- if dst_type.is_ctuple and self.type.size == dst_type.size:
- return self.coerce_to_ctuple(dst_type, env)
- elif dst_type is tuple_type or dst_type is py_object_type:
- coerced_args = [arg.coerce_to_pyobject(env) for arg in self.args]
- return TupleNode(self.pos, args=coerced_args, type=tuple_type, is_temp=1).analyse_types(env, skip_children=True)
- else:
- return self.coerce_to_pyobject(env).coerce_to(dst_type, env)
- elif dst_type.is_ctuple and not self.mult_factor:
- return self.coerce_to_ctuple(dst_type, env)
- else:
- return SequenceNode.coerce_to(self, dst_type, env)
-
- def as_list(self):
- t = ListNode(self.pos, args=self.args, mult_factor=self.mult_factor)
- if isinstance(self.constant_result, tuple):
- t.constant_result = list(self.constant_result)
- return t
-
+ def analyse_as_type(self, env):
+ # ctuple type
+ if not self.args:
+ return None
+ item_types = [arg.analyse_as_type(env) for arg in self.args]
+ if any(t is None for t in item_types):
+ return None
+ entry = env.declare_tuple_type(self.pos, item_types)
+ return entry.type
+
+ def coerce_to(self, dst_type, env):
+ if self.type.is_ctuple:
+ if dst_type.is_ctuple and self.type.size == dst_type.size:
+ return self.coerce_to_ctuple(dst_type, env)
+ elif dst_type is tuple_type or dst_type is py_object_type:
+ coerced_args = [arg.coerce_to_pyobject(env) for arg in self.args]
+ return TupleNode(self.pos, args=coerced_args, type=tuple_type, is_temp=1).analyse_types(env, skip_children=True)
+ else:
+ return self.coerce_to_pyobject(env).coerce_to(dst_type, env)
+ elif dst_type.is_ctuple and not self.mult_factor:
+ return self.coerce_to_ctuple(dst_type, env)
+ else:
+ return SequenceNode.coerce_to(self, dst_type, env)
+
+ def as_list(self):
+ t = ListNode(self.pos, args=self.args, mult_factor=self.mult_factor)
+ if isinstance(self.constant_result, tuple):
+ t.constant_result = list(self.constant_result)
+ return t
+
def is_simple(self):
# either temp or constant => always simple
return True
@@ -8006,7 +8006,7 @@ class TupleNode(SequenceNode):
values = self.compile_time_value_list(denv)
try:
return tuple(values)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def generate_operation_code(self, code):
@@ -8015,16 +8015,16 @@ class TupleNode(SequenceNode):
return
if self.is_literal or self.is_partly_literal:
- # The "mult_factor" is part of the deduplication if it is also constant, i.e. when
- # we deduplicate the multiplied result. Otherwise, only deduplicate the constant part.
- dedup_key = make_dedup_key(self.type, [self.mult_factor if self.is_literal else None] + self.args)
- tuple_target = code.get_py_const(py_object_type, 'tuple', cleanup_level=2, dedup_key=dedup_key)
- const_code = code.get_cached_constants_writer(tuple_target)
- if const_code is not None:
- # constant is not yet initialised
- const_code.mark_pos(self.pos)
- self.generate_sequence_packing_code(const_code, tuple_target, plain=not self.is_literal)
- const_code.put_giveref(tuple_target)
+ # The "mult_factor" is part of the deduplication if it is also constant, i.e. when
+ # we deduplicate the multiplied result. Otherwise, only deduplicate the constant part.
+ dedup_key = make_dedup_key(self.type, [self.mult_factor if self.is_literal else None] + self.args)
+ tuple_target = code.get_py_const(py_object_type, 'tuple', cleanup_level=2, dedup_key=dedup_key)
+ const_code = code.get_cached_constants_writer(tuple_target)
+ if const_code is not None:
+ # constant is not yet initialised
+ const_code.mark_pos(self.pos)
+ self.generate_sequence_packing_code(const_code, tuple_target, plain=not self.is_literal)
+ const_code.put_giveref(tuple_target)
if self.is_literal:
self.result_code = tuple_target
else:
@@ -8034,7 +8034,7 @@ class TupleNode(SequenceNode):
))
code.put_gotref(self.py_result())
else:
- self.type.entry.used = True
+ self.type.entry.used = True
self.generate_sequence_packing_code(code)
@@ -8054,13 +8054,13 @@ class ListNode(SequenceNode):
return ()
def infer_type(self, env):
- # TODO: Infer non-object list arrays.
+ # TODO: Infer non-object list arrays.
return list_type
def analyse_expressions(self, env):
- for arg in self.args:
- if arg.is_starred:
- arg.starred_expr_allowed_here = True
+ for arg in self.args:
+ if arg.is_starred:
+ arg.starred_expr_allowed_here = True
node = SequenceNode.analyse_expressions(self, env)
return node.coerce_to_pyobject(env)
@@ -8071,7 +8071,7 @@ class ListNode(SequenceNode):
node.obj_conversion_errors = errors
if env.is_module_scope:
self.in_module_scope = True
- node = node._create_merge_node_if_necessary(env)
+ node = node._create_merge_node_if_necessary(env)
return node
def coerce_to(self, dst_type, env):
@@ -8081,31 +8081,31 @@ class ListNode(SequenceNode):
self.obj_conversion_errors = []
if not self.type.subtype_of(dst_type):
error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
- elif (dst_type.is_array or dst_type.is_ptr) and dst_type.base_type is not PyrexTypes.c_void_type:
- array_length = len(self.args)
- if self.mult_factor:
- if isinstance(self.mult_factor.constant_result, _py_int_types):
- if self.mult_factor.constant_result <= 0:
- error(self.pos, "Cannot coerce non-positively multiplied list to '%s'" % dst_type)
- else:
- array_length *= self.mult_factor.constant_result
- else:
- error(self.pos, "Cannot coerce dynamically multiplied list to '%s'" % dst_type)
+ elif (dst_type.is_array or dst_type.is_ptr) and dst_type.base_type is not PyrexTypes.c_void_type:
+ array_length = len(self.args)
+ if self.mult_factor:
+ if isinstance(self.mult_factor.constant_result, _py_int_types):
+ if self.mult_factor.constant_result <= 0:
+ error(self.pos, "Cannot coerce non-positively multiplied list to '%s'" % dst_type)
+ else:
+ array_length *= self.mult_factor.constant_result
+ else:
+ error(self.pos, "Cannot coerce dynamically multiplied list to '%s'" % dst_type)
base_type = dst_type.base_type
- self.type = PyrexTypes.CArrayType(base_type, array_length)
+ self.type = PyrexTypes.CArrayType(base_type, array_length)
for i in range(len(self.original_args)):
arg = self.args[i]
if isinstance(arg, CoerceToPyTypeNode):
arg = arg.arg
self.args[i] = arg.coerce_to(base_type, env)
- elif dst_type.is_cpp_class:
- # TODO(robertwb): Avoid object conversion for vector/list/set.
- return TypecastNode(self.pos, operand=self, type=PyrexTypes.py_object_type).coerce_to(dst_type, env)
- elif self.mult_factor:
- error(self.pos, "Cannot coerce multiplied list to '%s'" % dst_type)
+ elif dst_type.is_cpp_class:
+ # TODO(robertwb): Avoid object conversion for vector/list/set.
+ return TypecastNode(self.pos, operand=self, type=PyrexTypes.py_object_type).coerce_to(dst_type, env)
+ elif self.mult_factor:
+ error(self.pos, "Cannot coerce multiplied list to '%s'" % dst_type)
elif dst_type.is_struct:
if len(self.args) > len(dst_type.scope.var_entries):
- error(self.pos, "Too many members for '%s'" % dst_type)
+ error(self.pos, "Too many members for '%s'" % dst_type)
else:
if len(self.args) < len(dst_type.scope.var_entries):
warning(self.pos, "Too few members for '%s'" % dst_type, 1)
@@ -8114,16 +8114,16 @@ class ListNode(SequenceNode):
arg = arg.arg
self.args[i] = arg.coerce_to(member.type, env)
self.type = dst_type
- elif dst_type.is_ctuple:
- return self.coerce_to_ctuple(dst_type, env)
+ elif dst_type.is_ctuple:
+ return self.coerce_to_ctuple(dst_type, env)
else:
self.type = error_type
error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
return self
- def as_list(self): # dummy for compatibility with TupleNode
- return self
-
+ def as_list(self): # dummy for compatibility with TupleNode
+ return self
+
def as_tuple(self):
t = TupleNode(self.pos, args=self.args, mult_factor=self.mult_factor)
if isinstance(self.constant_result, list):
@@ -8146,7 +8146,7 @@ class ListNode(SequenceNode):
def calculate_constant_result(self):
if self.mult_factor:
- raise ValueError() # may exceed the compile time memory
+ raise ValueError() # may exceed the compile time memory
self.constant_result = [
arg.constant_result for arg in self.args]
@@ -8162,36 +8162,36 @@ class ListNode(SequenceNode):
report_error(err)
self.generate_sequence_packing_code(code)
elif self.type.is_array:
- if self.mult_factor:
- code.putln("{")
- code.putln("Py_ssize_t %s;" % Naming.quick_temp_cname)
- code.putln("for ({i} = 0; {i} < {count}; {i}++) {{".format(
- i=Naming.quick_temp_cname, count=self.mult_factor.result()))
- offset = '+ (%d * %s)' % (len(self.args), Naming.quick_temp_cname)
- else:
- offset = ''
+ if self.mult_factor:
+ code.putln("{")
+ code.putln("Py_ssize_t %s;" % Naming.quick_temp_cname)
+ code.putln("for ({i} = 0; {i} < {count}; {i}++) {{".format(
+ i=Naming.quick_temp_cname, count=self.mult_factor.result()))
+ offset = '+ (%d * %s)' % (len(self.args), Naming.quick_temp_cname)
+ else:
+ offset = ''
for i, arg in enumerate(self.args):
- if arg.type.is_array:
- code.globalstate.use_utility_code(UtilityCode.load_cached("IncludeStringH", "StringTools.c"))
- code.putln("memcpy(&(%s[%s%s]), %s, sizeof(%s[0]));" % (
- self.result(), i, offset,
- arg.result(), self.result()
- ))
- else:
- code.putln("%s[%s%s] = %s;" % (
- self.result(),
- i,
- offset,
- arg.result()))
- if self.mult_factor:
- code.putln("}")
- code.putln("}")
+ if arg.type.is_array:
+ code.globalstate.use_utility_code(UtilityCode.load_cached("IncludeStringH", "StringTools.c"))
+ code.putln("memcpy(&(%s[%s%s]), %s, sizeof(%s[0]));" % (
+ self.result(), i, offset,
+ arg.result(), self.result()
+ ))
+ else:
+ code.putln("%s[%s%s] = %s;" % (
+ self.result(),
+ i,
+ offset,
+ arg.result()))
+ if self.mult_factor:
+ code.putln("}")
+ code.putln("}")
elif self.type.is_struct:
for arg, member in zip(self.args, self.type.scope.var_entries):
code.putln("%s.%s = %s;" % (
- self.result(),
- member.cname,
- arg.result()))
+ self.result(),
+ member.cname,
+ arg.result()))
else:
raise InternalError("List type never specified")
@@ -8416,228 +8416,228 @@ class DictComprehensionAppendNode(ComprehensionAppendNode):
self.value_expr.annotate(code)
-class InlinedGeneratorExpressionNode(ExprNode):
- # An inlined generator expression for which the result is calculated
- # inside of the loop and returned as a single, first and only Generator
- # return value.
- # This will only be created by transforms when replacing safe builtin
- # calls on generator expressions.
+class InlinedGeneratorExpressionNode(ExprNode):
+ # An inlined generator expression for which the result is calculated
+ # inside of the loop and returned as a single, first and only Generator
+ # return value.
+ # This will only be created by transforms when replacing safe builtin
+ # calls on generator expressions.
#
- # gen GeneratorExpressionNode the generator, not containing any YieldExprNodes
- # orig_func String the name of the builtin function this node replaces
- # target ExprNode or None a 'target' for a ComprehensionAppend node
-
- subexprs = ["gen"]
- orig_func = None
- target = None
- is_temp = True
+ # gen GeneratorExpressionNode the generator, not containing any YieldExprNodes
+ # orig_func String the name of the builtin function this node replaces
+ # target ExprNode or None a 'target' for a ComprehensionAppend node
+
+ subexprs = ["gen"]
+ orig_func = None
+ target = None
+ is_temp = True
type = py_object_type
- def __init__(self, pos, gen, comprehension_type=None, **kwargs):
- gbody = gen.def_node.gbody
- gbody.is_inlined = True
- if comprehension_type is not None:
- assert comprehension_type in (list_type, set_type, dict_type), comprehension_type
- gbody.inlined_comprehension_type = comprehension_type
- kwargs.update(
- target=RawCNameExprNode(pos, comprehension_type, Naming.retval_cname),
- type=comprehension_type,
- )
- super(InlinedGeneratorExpressionNode, self).__init__(pos, gen=gen, **kwargs)
+ def __init__(self, pos, gen, comprehension_type=None, **kwargs):
+ gbody = gen.def_node.gbody
+ gbody.is_inlined = True
+ if comprehension_type is not None:
+ assert comprehension_type in (list_type, set_type, dict_type), comprehension_type
+ gbody.inlined_comprehension_type = comprehension_type
+ kwargs.update(
+ target=RawCNameExprNode(pos, comprehension_type, Naming.retval_cname),
+ type=comprehension_type,
+ )
+ super(InlinedGeneratorExpressionNode, self).__init__(pos, gen=gen, **kwargs)
def may_be_none(self):
- return self.orig_func not in ('any', 'all', 'sorted')
+ return self.orig_func not in ('any', 'all', 'sorted')
def infer_type(self, env):
- return self.type
+ return self.type
def analyse_types(self, env):
- self.gen = self.gen.analyse_expressions(env)
+ self.gen = self.gen.analyse_expressions(env)
return self
- def generate_result_code(self, code):
- code.putln("%s = __Pyx_Generator_Next(%s); %s" % (
- self.result(), self.gen.result(),
- code.error_goto_if_null(self.result(), self.pos)))
- code.put_gotref(self.result())
-
-
-class MergedSequenceNode(ExprNode):
- """
- Merge a sequence of iterables into a set/list/tuple.
-
- The target collection is determined by self.type, which must be set externally.
-
- args [ExprNode]
- """
- subexprs = ['args']
- is_temp = True
- gil_message = "Constructing Python collection"
-
- def __init__(self, pos, args, type):
- if type in (list_type, tuple_type) and args and args[0].is_sequence_constructor:
- # construct a list directly from the first argument that we can then extend
- if args[0].type is not list_type:
- args[0] = ListNode(args[0].pos, args=args[0].args, is_temp=True)
- ExprNode.__init__(self, pos, args=args, type=type)
-
- def calculate_constant_result(self):
- result = []
- for item in self.args:
- if item.is_sequence_constructor and item.mult_factor:
- if item.mult_factor.constant_result <= 0:
- continue
- # otherwise, adding each item once should be enough
- if item.is_set_literal or item.is_sequence_constructor:
- # process items in order
- items = (arg.constant_result for arg in item.args)
- else:
- items = item.constant_result
- result.extend(items)
- if self.type is set_type:
- result = set(result)
- elif self.type is tuple_type:
- result = tuple(result)
- else:
- assert self.type is list_type
- self.constant_result = result
-
- def compile_time_value(self, denv):
- result = []
- for item in self.args:
- if item.is_sequence_constructor and item.mult_factor:
- if item.mult_factor.compile_time_value(denv) <= 0:
- continue
- if item.is_set_literal or item.is_sequence_constructor:
- # process items in order
- items = (arg.compile_time_value(denv) for arg in item.args)
- else:
- items = item.compile_time_value(denv)
- result.extend(items)
- if self.type is set_type:
- try:
- result = set(result)
- except Exception as e:
- self.compile_time_value_error(e)
- elif self.type is tuple_type:
- result = tuple(result)
- else:
- assert self.type is list_type
- return result
-
- def type_dependencies(self, env):
- return ()
-
- def infer_type(self, env):
- return self.type
-
- def analyse_types(self, env):
- args = [
- arg.analyse_types(env).coerce_to_pyobject(env).as_none_safe_node(
- # FIXME: CPython's error message starts with the runtime function name
- 'argument after * must be an iterable, not NoneType')
- for arg in self.args
- ]
-
- if len(args) == 1 and args[0].type is self.type:
- # strip this intermediate node and use the bare collection
- return args[0]
-
- assert self.type in (set_type, list_type, tuple_type)
-
- self.args = args
+ def generate_result_code(self, code):
+ code.putln("%s = __Pyx_Generator_Next(%s); %s" % (
+ self.result(), self.gen.result(),
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.result())
+
+
+class MergedSequenceNode(ExprNode):
+ """
+ Merge a sequence of iterables into a set/list/tuple.
+
+ The target collection is determined by self.type, which must be set externally.
+
+ args [ExprNode]
+ """
+ subexprs = ['args']
+ is_temp = True
+ gil_message = "Constructing Python collection"
+
+ def __init__(self, pos, args, type):
+ if type in (list_type, tuple_type) and args and args[0].is_sequence_constructor:
+ # construct a list directly from the first argument that we can then extend
+ if args[0].type is not list_type:
+ args[0] = ListNode(args[0].pos, args=args[0].args, is_temp=True)
+ ExprNode.__init__(self, pos, args=args, type=type)
+
+ def calculate_constant_result(self):
+ result = []
+ for item in self.args:
+ if item.is_sequence_constructor and item.mult_factor:
+ if item.mult_factor.constant_result <= 0:
+ continue
+ # otherwise, adding each item once should be enough
+ if item.is_set_literal or item.is_sequence_constructor:
+ # process items in order
+ items = (arg.constant_result for arg in item.args)
+ else:
+ items = item.constant_result
+ result.extend(items)
+ if self.type is set_type:
+ result = set(result)
+ elif self.type is tuple_type:
+ result = tuple(result)
+ else:
+ assert self.type is list_type
+ self.constant_result = result
+
+ def compile_time_value(self, denv):
+ result = []
+ for item in self.args:
+ if item.is_sequence_constructor and item.mult_factor:
+ if item.mult_factor.compile_time_value(denv) <= 0:
+ continue
+ if item.is_set_literal or item.is_sequence_constructor:
+ # process items in order
+ items = (arg.compile_time_value(denv) for arg in item.args)
+ else:
+ items = item.compile_time_value(denv)
+ result.extend(items)
+ if self.type is set_type:
+ try:
+ result = set(result)
+ except Exception as e:
+ self.compile_time_value_error(e)
+ elif self.type is tuple_type:
+ result = tuple(result)
+ else:
+ assert self.type is list_type
+ return result
+
+ def type_dependencies(self, env):
+ return ()
+
+ def infer_type(self, env):
+ return self.type
+
+ def analyse_types(self, env):
+ args = [
+ arg.analyse_types(env).coerce_to_pyobject(env).as_none_safe_node(
+ # FIXME: CPython's error message starts with the runtime function name
+ 'argument after * must be an iterable, not NoneType')
+ for arg in self.args
+ ]
+
+ if len(args) == 1 and args[0].type is self.type:
+ # strip this intermediate node and use the bare collection
+ return args[0]
+
+ assert self.type in (set_type, list_type, tuple_type)
+
+ self.args = args
return self
- def may_be_none(self):
- return False
-
- def generate_evaluation_code(self, code):
- code.mark_pos(self.pos)
- self.allocate_temp_result(code)
-
- is_set = self.type is set_type
-
- args = iter(self.args)
- item = next(args)
- item.generate_evaluation_code(code)
- if (is_set and item.is_set_literal or
- not is_set and item.is_sequence_constructor and item.type is list_type):
- code.putln("%s = %s;" % (self.result(), item.py_result()))
- item.generate_post_assignment_code(code)
- else:
- code.putln("%s = %s(%s); %s" % (
- self.result(),
- 'PySet_New' if is_set else 'PySequence_List',
- item.py_result(),
- code.error_goto_if_null(self.result(), self.pos)))
- code.put_gotref(self.py_result())
- item.generate_disposal_code(code)
- item.free_temps(code)
-
- helpers = set()
- if is_set:
- add_func = "PySet_Add"
- extend_func = "__Pyx_PySet_Update"
- else:
- add_func = "__Pyx_ListComp_Append"
- extend_func = "__Pyx_PyList_Extend"
-
- for item in args:
- if (is_set and (item.is_set_literal or item.is_sequence_constructor) or
- (item.is_sequence_constructor and not item.mult_factor)):
- if not is_set and item.args:
- helpers.add(("ListCompAppend", "Optimize.c"))
- for arg in item.args:
- arg.generate_evaluation_code(code)
- code.put_error_if_neg(arg.pos, "%s(%s, %s)" % (
- add_func,
- self.result(),
- arg.py_result()))
- arg.generate_disposal_code(code)
- arg.free_temps(code)
- continue
-
- if is_set:
- helpers.add(("PySet_Update", "Builtins.c"))
- else:
- helpers.add(("ListExtend", "Optimize.c"))
-
- item.generate_evaluation_code(code)
- code.put_error_if_neg(item.pos, "%s(%s, %s)" % (
- extend_func,
- self.result(),
- item.py_result()))
- item.generate_disposal_code(code)
- item.free_temps(code)
-
- if self.type is tuple_type:
- code.putln("{")
- code.putln("PyObject *%s = PyList_AsTuple(%s);" % (
- Naming.quick_temp_cname,
- self.result()))
- code.put_decref(self.result(), py_object_type)
- code.putln("%s = %s; %s" % (
- self.result(),
- Naming.quick_temp_cname,
- code.error_goto_if_null(self.result(), self.pos)))
- code.put_gotref(self.result())
- code.putln("}")
-
- for helper in sorted(helpers):
- code.globalstate.use_utility_code(UtilityCode.load_cached(*helper))
-
- def annotate(self, code):
- for item in self.args:
- item.annotate(code)
-
-
-class SetNode(ExprNode):
- """
- Set constructor.
- """
+ def may_be_none(self):
+ return False
+
+ def generate_evaluation_code(self, code):
+ code.mark_pos(self.pos)
+ self.allocate_temp_result(code)
+
+ is_set = self.type is set_type
+
+ args = iter(self.args)
+ item = next(args)
+ item.generate_evaluation_code(code)
+ if (is_set and item.is_set_literal or
+ not is_set and item.is_sequence_constructor and item.type is list_type):
+ code.putln("%s = %s;" % (self.result(), item.py_result()))
+ item.generate_post_assignment_code(code)
+ else:
+ code.putln("%s = %s(%s); %s" % (
+ self.result(),
+ 'PySet_New' if is_set else 'PySequence_List',
+ item.py_result(),
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.py_result())
+ item.generate_disposal_code(code)
+ item.free_temps(code)
+
+ helpers = set()
+ if is_set:
+ add_func = "PySet_Add"
+ extend_func = "__Pyx_PySet_Update"
+ else:
+ add_func = "__Pyx_ListComp_Append"
+ extend_func = "__Pyx_PyList_Extend"
+
+ for item in args:
+ if (is_set and (item.is_set_literal or item.is_sequence_constructor) or
+ (item.is_sequence_constructor and not item.mult_factor)):
+ if not is_set and item.args:
+ helpers.add(("ListCompAppend", "Optimize.c"))
+ for arg in item.args:
+ arg.generate_evaluation_code(code)
+ code.put_error_if_neg(arg.pos, "%s(%s, %s)" % (
+ add_func,
+ self.result(),
+ arg.py_result()))
+ arg.generate_disposal_code(code)
+ arg.free_temps(code)
+ continue
+
+ if is_set:
+ helpers.add(("PySet_Update", "Builtins.c"))
+ else:
+ helpers.add(("ListExtend", "Optimize.c"))
+
+ item.generate_evaluation_code(code)
+ code.put_error_if_neg(item.pos, "%s(%s, %s)" % (
+ extend_func,
+ self.result(),
+ item.py_result()))
+ item.generate_disposal_code(code)
+ item.free_temps(code)
+
+ if self.type is tuple_type:
+ code.putln("{")
+ code.putln("PyObject *%s = PyList_AsTuple(%s);" % (
+ Naming.quick_temp_cname,
+ self.result()))
+ code.put_decref(self.result(), py_object_type)
+ code.putln("%s = %s; %s" % (
+ self.result(),
+ Naming.quick_temp_cname,
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.result())
+ code.putln("}")
+
+ for helper in sorted(helpers):
+ code.globalstate.use_utility_code(UtilityCode.load_cached(*helper))
+
+ def annotate(self, code):
+ for item in self.args:
+ item.annotate(code)
+
+
+class SetNode(ExprNode):
+ """
+ Set constructor.
+ """
subexprs = ['args']
- type = set_type
- is_set_literal = True
+ type = set_type
+ is_set_literal = True
gil_message = "Constructing Python set"
def analyse_types(self, env):
@@ -8659,7 +8659,7 @@ class SetNode(ExprNode):
values = [arg.compile_time_value(denv) for arg in self.args]
try:
return set(values)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def generate_evaluation_code(self, code):
@@ -8692,7 +8692,7 @@ class DictNode(ExprNode):
exclude_null_values = False
type = dict_type
is_dict_literal = True
- reject_duplicates = False
+ reject_duplicates = False
obj_conversion_errors = []
@@ -8710,14 +8710,14 @@ class DictNode(ExprNode):
for item in self.key_value_pairs]
try:
return dict(pairs)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def type_dependencies(self, env):
return ()
def infer_type(self, env):
- # TODO: Infer struct constructors.
+ # TODO: Infer struct constructors.
return dict_type
def analyse_types(self, env):
@@ -8735,13 +8735,13 @@ class DictNode(ExprNode):
def coerce_to(self, dst_type, env):
if dst_type.is_pyobject:
self.release_errors()
- if self.type.is_struct_or_union:
- if not dict_type.subtype_of(dst_type):
- error(self.pos, "Cannot interpret struct as non-dict type '%s'" % dst_type)
- return DictNode(self.pos, key_value_pairs=[
- DictItemNode(item.pos, key=item.key.coerce_to_pyobject(env),
- value=item.value.coerce_to_pyobject(env))
- for item in self.key_value_pairs])
+ if self.type.is_struct_or_union:
+ if not dict_type.subtype_of(dst_type):
+ error(self.pos, "Cannot interpret struct as non-dict type '%s'" % dst_type)
+ return DictNode(self.pos, key_value_pairs=[
+ DictItemNode(item.pos, key=item.key.coerce_to_pyobject(env),
+ value=item.value.coerce_to_pyobject(env))
+ for item in self.key_value_pairs])
if not self.type.subtype_of(dst_type):
error(self.pos, "Cannot interpret dict as type '%s'" % dst_type)
elif dst_type.is_struct_or_union:
@@ -8783,9 +8783,9 @@ class DictNode(ExprNode):
# pairs are evaluated and used one at a time.
code.mark_pos(self.pos)
self.allocate_temp_result(code)
-
- is_dict = self.type.is_pyobject
- if is_dict:
+
+ is_dict = self.type.is_pyobject
+ if is_dict:
self.release_errors()
code.putln(
"%s = __Pyx_PyDict_NewPresized(%d); %s" % (
@@ -8793,51 +8793,51 @@ class DictNode(ExprNode):
len(self.key_value_pairs),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
-
- keys_seen = set()
- key_type = None
- needs_error_helper = False
-
+
+ keys_seen = set()
+ key_type = None
+ needs_error_helper = False
+
for item in self.key_value_pairs:
item.generate_evaluation_code(code)
- if is_dict:
+ if is_dict:
if self.exclude_null_values:
code.putln('if (%s) {' % item.value.py_result())
- key = item.key
- if self.reject_duplicates:
- if keys_seen is not None:
- # avoid runtime 'in' checks for literals that we can do at compile time
- if not key.is_string_literal:
- keys_seen = None
- elif key.value in keys_seen:
- # FIXME: this could be a compile time error, at least in Cython code
- keys_seen = None
- elif key_type is not type(key.value):
- if key_type is None:
- key_type = type(key.value)
- keys_seen.add(key.value)
- else:
- # different types => may not be able to compare at compile time
- keys_seen = None
- else:
- keys_seen.add(key.value)
-
- if keys_seen is None:
- code.putln('if (unlikely(PyDict_Contains(%s, %s))) {' % (
- self.result(), key.py_result()))
- # currently only used in function calls
- needs_error_helper = True
- code.putln('__Pyx_RaiseDoubleKeywordsError("function", %s); %s' % (
- key.py_result(),
- code.error_goto(item.pos)))
- code.putln("} else {")
-
- code.put_error_if_neg(self.pos, "PyDict_SetItem(%s, %s, %s)" % (
- self.result(),
- item.key.py_result(),
- item.value.py_result()))
- if self.reject_duplicates and keys_seen is None:
- code.putln('}')
+ key = item.key
+ if self.reject_duplicates:
+ if keys_seen is not None:
+ # avoid runtime 'in' checks for literals that we can do at compile time
+ if not key.is_string_literal:
+ keys_seen = None
+ elif key.value in keys_seen:
+ # FIXME: this could be a compile time error, at least in Cython code
+ keys_seen = None
+ elif key_type is not type(key.value):
+ if key_type is None:
+ key_type = type(key.value)
+ keys_seen.add(key.value)
+ else:
+ # different types => may not be able to compare at compile time
+ keys_seen = None
+ else:
+ keys_seen.add(key.value)
+
+ if keys_seen is None:
+ code.putln('if (unlikely(PyDict_Contains(%s, %s))) {' % (
+ self.result(), key.py_result()))
+ # currently only used in function calls
+ needs_error_helper = True
+ code.putln('__Pyx_RaiseDoubleKeywordsError("function", %s); %s' % (
+ key.py_result(),
+ code.error_goto(item.pos)))
+ code.putln("} else {")
+
+ code.put_error_if_neg(self.pos, "PyDict_SetItem(%s, %s, %s)" % (
+ self.result(),
+ item.key.py_result(),
+ item.value.py_result()))
+ if self.reject_duplicates and keys_seen is None:
+ code.putln('}')
if self.exclude_null_values:
code.putln('}')
else:
@@ -8848,15 +8848,15 @@ class DictNode(ExprNode):
item.generate_disposal_code(code)
item.free_temps(code)
- if needs_error_helper:
- code.globalstate.use_utility_code(
- UtilityCode.load_cached("RaiseDoubleKeywords", "FunctionArguments.c"))
-
+ if needs_error_helper:
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached("RaiseDoubleKeywords", "FunctionArguments.c"))
+
def annotate(self, code):
for item in self.key_value_pairs:
item.annotate(code)
-
+
class DictItemNode(ExprNode):
# Represents a single item in a DictNode
#
@@ -9239,16 +9239,16 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
default_args = []
default_kwargs = []
annotations = []
-
- # For global cpdef functions and def/cpdef methods in cdef classes, we must use global constants
- # for default arguments to avoid the dependency on the CyFunction object as 'self' argument
- # in the underlying C function. Basically, cpdef functions/methods are static C functions,
- # so their optional arguments must be static, too.
- # TODO: change CyFunction implementation to pass both function object and owning object for method calls
- must_use_constants = env.is_c_class_scope or (self.def_node.is_wrapper and env.is_module_scope)
-
+
+ # For global cpdef functions and def/cpdef methods in cdef classes, we must use global constants
+ # for default arguments to avoid the dependency on the CyFunction object as 'self' argument
+ # in the underlying C function. Basically, cpdef functions/methods are static C functions,
+ # so their optional arguments must be static, too.
+ # TODO: change CyFunction implementation to pass both function object and owning object for method calls
+ must_use_constants = env.is_c_class_scope or (self.def_node.is_wrapper and env.is_module_scope)
+
for arg in self.def_node.args:
- if arg.default and not must_use_constants:
+ if arg.default and not must_use_constants:
if not arg.default.is_literal:
arg.is_dynamic = True
if arg.type.is_pyobject:
@@ -9264,12 +9264,12 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
if arg.annotation:
arg.annotation = self.analyse_annotation(env, arg.annotation)
annotations.append((arg.pos, arg.name, arg.annotation))
-
- for arg in (self.def_node.star_arg, self.def_node.starstar_arg):
- if arg and arg.annotation:
+
+ for arg in (self.def_node.star_arg, self.def_node.starstar_arg):
+ if arg and arg.annotation:
arg.annotation = self.analyse_annotation(env, arg.annotation)
- annotations.append((arg.pos, arg.name, arg.annotation))
-
+ annotations.append((arg.pos, arg.name, arg.annotation))
+
annotation = self.def_node.return_type_annotation
if annotation:
annotation = self.analyse_annotation(env, annotation)
@@ -9305,7 +9305,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
if default_args:
defaults_tuple = TupleNode(self.pos, args=[
arg.default for arg in default_args])
- self.defaults_tuple = defaults_tuple.analyse_types(env).coerce_to_pyobject(env)
+ self.defaults_tuple = defaults_tuple.analyse_types(env).coerce_to_pyobject(env)
if default_kwargs:
defaults_kwdict = DictNode(self.pos, key_value_pairs=[
DictItemNode(
@@ -9334,10 +9334,10 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
self.pos, args=[defaults_tuple, defaults_kwdict])),
decorators=None,
name=StringEncoding.EncodedString("__defaults__"))
- # defaults getter must never live in class scopes, it's always a module function
- module_scope = env.global_scope()
- defaults_getter.analyse_declarations(module_scope)
- defaults_getter = defaults_getter.analyse_expressions(module_scope)
+ # defaults getter must never live in class scopes, it's always a module function
+ module_scope = env.global_scope()
+ defaults_getter.analyse_declarations(module_scope)
+ defaults_getter = defaults_getter.analyse_expressions(module_scope)
defaults_getter.body = defaults_getter.body.analyse_expressions(
defaults_getter.local_scope)
defaults_getter.py_wrapper_required = False
@@ -9421,7 +9421,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
elif def_node.is_classmethod:
flags.append('__Pyx_CYFUNCTION_CLASSMETHOD')
- if def_node.local_scope.parent_scope.is_c_class_scope and not def_node.entry.is_anonymous:
+ if def_node.local_scope.parent_scope.is_c_class_scope and not def_node.entry.is_anonymous:
flags.append('__Pyx_CYFUNCTION_CCLASS')
if flags:
@@ -9471,8 +9471,8 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
if self.defaults_kwdict:
code.putln('__Pyx_CyFunction_SetDefaultsKwDict(%s, %s);' % (
self.result(), self.defaults_kwdict.py_result()))
- if def_node.defaults_getter and not self.specialized_cpdefs:
- # Fused functions do not support dynamic defaults, only their specialisations can have them for now.
+ if def_node.defaults_getter and not self.specialized_cpdefs:
+ # Fused functions do not support dynamic defaults, only their specialisations can have them for now.
code.putln('__Pyx_CyFunction_SetDefaultsGetter(%s, %s);' % (
self.result(), def_node.defaults_getter.entry.pyfunc_cname))
if self.annotations_dict:
@@ -9501,7 +9501,7 @@ class CodeObjectNode(ExprNode):
subexprs = ['varnames']
is_temp = False
- result_code = None
+ result_code = None
def __init__(self, def_node):
ExprNode.__init__(self, def_node.pos, def_node=def_node)
@@ -9518,24 +9518,24 @@ class CodeObjectNode(ExprNode):
def may_be_none(self):
return False
- def calculate_result_code(self, code=None):
- if self.result_code is None:
- self.result_code = code.get_py_const(py_object_type, 'codeobj', cleanup_level=2)
+ def calculate_result_code(self, code=None):
+ if self.result_code is None:
+ self.result_code = code.get_py_const(py_object_type, 'codeobj', cleanup_level=2)
return self.result_code
def generate_result_code(self, code):
- if self.result_code is None:
- self.result_code = code.get_py_const(py_object_type, 'codeobj', cleanup_level=2)
+ if self.result_code is None:
+ self.result_code = code.get_py_const(py_object_type, 'codeobj', cleanup_level=2)
- code = code.get_cached_constants_writer(self.result_code)
- if code is None:
- return # already initialised
+ code = code.get_cached_constants_writer(self.result_code)
+ if code is None:
+ return # already initialised
code.mark_pos(self.pos)
func = self.def_node
func_name = code.get_py_string_const(
func.name, identifier=True, is_str=False, unicode_value=func.name)
# FIXME: better way to get the module file path at module init time? Encoding to use?
- file_path = StringEncoding.bytes_literal(func.pos[0].get_filenametable_entry().encode('utf8'), 'utf8')
+ file_path = StringEncoding.bytes_literal(func.pos[0].get_filenametable_entry().encode('utf8'), 'utf8')
# XXX Use get_description() to set arcadia root relative filename
file_path = StringEncoding.bytes_literal(func.pos[0].get_description().encode('utf8'), 'utf8')
file_path_const = code.get_py_string_const(file_path, identifier=False, is_str=True)
@@ -9635,10 +9635,10 @@ class DefaultsTupleNode(TupleNode):
args.append(arg)
super(DefaultsTupleNode, self).__init__(pos, args=args)
- def analyse_types(self, env, skip_children=False):
- return super(DefaultsTupleNode, self).analyse_types(env, skip_children).coerce_to_pyobject(env)
+ def analyse_types(self, env, skip_children=False):
+ return super(DefaultsTupleNode, self).analyse_types(env, skip_children).coerce_to_pyobject(env)
+
-
class DefaultsKwDictNode(DictNode):
# CyFunction's __kwdefaults__ dict
@@ -9669,7 +9669,7 @@ class LambdaNode(InnerFunctionNode):
name = StringEncoding.EncodedString('<lambda>')
def analyse_declarations(self, env):
- self.lambda_name = self.def_node.lambda_name = env.next_id('lambda')
+ self.lambda_name = self.def_node.lambda_name = env.next_id('lambda')
self.def_node.no_assignment_synthesis = True
self.def_node.pymethdef_required = True
self.def_node.analyse_declarations(env)
@@ -9698,7 +9698,7 @@ class GeneratorExpressionNode(LambdaNode):
binding = False
def analyse_declarations(self, env):
- self.genexpr_name = env.next_id('genexpr')
+ self.genexpr_name = env.next_id('genexpr')
super(GeneratorExpressionNode, self).analyse_declarations(env)
# No pymethdef required
self.def_node.pymethdef_required = False
@@ -9728,13 +9728,13 @@ class YieldExprNode(ExprNode):
type = py_object_type
label_num = 0
is_yield_from = False
- is_await = False
+ is_await = False
in_async_gen = False
- expr_keyword = 'yield'
+ expr_keyword = 'yield'
def analyse_types(self, env):
if not self.label_num or (self.is_yield_from and self.in_async_gen):
- error(self.pos, "'%s' not supported here" % self.expr_keyword)
+ error(self.pos, "'%s' not supported here" % self.expr_keyword)
self.is_temp = 1
if self.arg is not None:
self.arg = self.arg.analyse_types(env)
@@ -9820,22 +9820,22 @@ class YieldExprNode(ExprNode):
class _YieldDelegationExprNode(YieldExprNode):
- def yield_from_func(self, code):
+ def yield_from_func(self, code):
raise NotImplementedError()
- def generate_evaluation_code(self, code, source_cname=None, decref_source=False):
- if source_cname is None:
- self.arg.generate_evaluation_code(code)
- code.putln("%s = %s(%s, %s);" % (
+ def generate_evaluation_code(self, code, source_cname=None, decref_source=False):
+ if source_cname is None:
+ self.arg.generate_evaluation_code(code)
+ code.putln("%s = %s(%s, %s);" % (
Naming.retval_cname,
- self.yield_from_func(code),
+ self.yield_from_func(code),
Naming.generator_cname,
- self.arg.py_result() if source_cname is None else source_cname))
- if source_cname is None:
- self.arg.generate_disposal_code(code)
- self.arg.free_temps(code)
- elif decref_source:
- code.put_decref_clear(source_cname, py_object_type)
+ self.arg.py_result() if source_cname is None else source_cname))
+ if source_cname is None:
+ self.arg.generate_disposal_code(code)
+ self.arg.free_temps(code)
+ elif decref_source:
+ code.put_decref_clear(source_cname, py_object_type)
code.put_xgotref(Naming.retval_cname)
code.putln("if (likely(%s)) {" % Naming.retval_cname)
@@ -9843,26 +9843,26 @@ class _YieldDelegationExprNode(YieldExprNode):
code.putln("} else {")
# either error or sub-generator has normally terminated: return value => node result
if self.result_is_used:
- self.fetch_iteration_result(code)
+ self.fetch_iteration_result(code)
else:
- self.handle_iteration_exception(code)
+ self.handle_iteration_exception(code)
code.putln("}")
- def fetch_iteration_result(self, code):
- # YieldExprNode has allocated the result temp for us
- code.putln("%s = NULL;" % self.result())
- code.put_error_if_neg(self.pos, "__Pyx_PyGen_FetchStopIterationValue(&%s)" % self.result())
- code.put_gotref(self.result())
-
- def handle_iteration_exception(self, code):
+ def fetch_iteration_result(self, code):
+ # YieldExprNode has allocated the result temp for us
+ code.putln("%s = NULL;" % self.result())
+ code.put_error_if_neg(self.pos, "__Pyx_PyGen_FetchStopIterationValue(&%s)" % self.result())
+ code.put_gotref(self.result())
+
+ def handle_iteration_exception(self, code):
code.putln("PyObject* exc_type = __Pyx_PyErr_Occurred();")
- code.putln("if (exc_type) {")
+ code.putln("if (exc_type) {")
code.putln("if (likely(exc_type == PyExc_StopIteration || (exc_type != PyExc_GeneratorExit &&"
" __Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration)))) PyErr_Clear();")
- code.putln("else %s" % code.error_goto(self.pos))
- code.putln("}")
-
-
+ code.putln("else %s" % code.error_goto(self.pos))
+ code.putln("}")
+
+
class YieldFromExprNode(_YieldDelegationExprNode):
# "yield from GEN" expression
is_yield_from = True
@@ -9880,44 +9880,44 @@ class YieldFromExprNode(_YieldDelegationExprNode):
class AwaitExprNode(_YieldDelegationExprNode):
- # 'await' expression node
- #
- # arg ExprNode the Awaitable value to await
- # label_num integer yield label number
-
- is_await = True
- expr_keyword = 'await'
-
- def coerce_yield_argument(self, env):
- if self.arg is not None:
- # FIXME: use same check as in YieldFromExprNode.coerce_yield_argument() ?
- self.arg = self.arg.coerce_to_pyobject(env)
-
- def yield_from_func(self, code):
- code.globalstate.use_utility_code(UtilityCode.load_cached("CoroutineYieldFrom", "Coroutine.c"))
- return "__Pyx_Coroutine_Yield_From"
-
-
-class AwaitIterNextExprNode(AwaitExprNode):
- # 'await' expression node as part of 'async for' iteration
- #
- # Breaks out of loop on StopAsyncIteration exception.
-
+ # 'await' expression node
+ #
+ # arg ExprNode the Awaitable value to await
+ # label_num integer yield label number
+
+ is_await = True
+ expr_keyword = 'await'
+
+ def coerce_yield_argument(self, env):
+ if self.arg is not None:
+ # FIXME: use same check as in YieldFromExprNode.coerce_yield_argument() ?
+ self.arg = self.arg.coerce_to_pyobject(env)
+
+ def yield_from_func(self, code):
+ code.globalstate.use_utility_code(UtilityCode.load_cached("CoroutineYieldFrom", "Coroutine.c"))
+ return "__Pyx_Coroutine_Yield_From"
+
+
+class AwaitIterNextExprNode(AwaitExprNode):
+ # 'await' expression node as part of 'async for' iteration
+ #
+ # Breaks out of loop on StopAsyncIteration exception.
+
def _generate_break(self, code):
- code.globalstate.use_utility_code(UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c"))
+ code.globalstate.use_utility_code(UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c"))
code.putln("PyObject* exc_type = __Pyx_PyErr_Occurred();")
code.putln("if (unlikely(exc_type && (exc_type == __Pyx_PyExc_StopAsyncIteration || ("
" exc_type != PyExc_StopIteration && exc_type != PyExc_GeneratorExit &&"
" __Pyx_PyErr_GivenExceptionMatches(exc_type, __Pyx_PyExc_StopAsyncIteration))))) {")
- code.putln("PyErr_Clear();")
- code.putln("break;")
- code.putln("}")
+ code.putln("PyErr_Clear();")
+ code.putln("break;")
+ code.putln("}")
def fetch_iteration_result(self, code):
assert code.break_label, "AwaitIterNextExprNode outside of 'async for' loop"
self._generate_break(code)
- super(AwaitIterNextExprNode, self).fetch_iteration_result(code)
-
+ super(AwaitIterNextExprNode, self).fetch_iteration_result(code)
+
def generate_sent_value_handling_code(self, code, value_cname):
assert code.break_label, "AwaitIterNextExprNode outside of 'async for' loop"
code.putln("if (unlikely(!%s)) {" % value_cname)
@@ -9925,7 +9925,7 @@ class AwaitIterNextExprNode(AwaitExprNode):
# all non-break exceptions are errors, as in parent class
code.putln(code.error_goto(self.pos))
code.putln("}")
-
+
class GlobalsExprNode(AtomicExprNode):
type = dict_type
@@ -10046,7 +10046,7 @@ class UnopNode(ExprNode):
operand = self.operand.compile_time_value(denv)
try:
return func(operand)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def infer_type(self, env):
@@ -10088,7 +10088,7 @@ class UnopNode(ExprNode):
return self.operand.check_const()
def is_py_operation(self):
- return self.operand.type.is_pyobject or self.operand.type.is_ctuple
+ return self.operand.type.is_pyobject or self.operand.type.is_ctuple
def is_pythran_operation(self, env):
np_pythran = has_np_pythran(env)
@@ -10117,14 +10117,14 @@ class UnopNode(ExprNode):
self.operand.pythran_result()))
elif self.operand.type.is_pyobject:
self.generate_py_operation_code(code)
- elif self.is_temp:
- if self.is_cpp_operation() and self.exception_check == '+':
- translate_cpp_exception(code, self.pos,
- "%s = %s %s;" % (self.result(), self.operator, self.operand.result()),
- self.result() if self.type.is_pyobject else None,
- self.exception_value, self.in_nogil_context)
- else:
- code.putln("%s = %s %s;" % (self.result(), self.operator, self.operand.result()))
+ elif self.is_temp:
+ if self.is_cpp_operation() and self.exception_check == '+':
+ translate_cpp_exception(code, self.pos,
+ "%s = %s %s;" % (self.result(), self.operator, self.operand.result()),
+ self.result() if self.type.is_pyobject else None,
+ self.exception_value, self.in_nogil_context)
+ else:
+ code.putln("%s = %s %s;" % (self.result(), self.operator, self.operand.result()))
def generate_py_operation_code(self, code):
function = self.py_operation_function(code)
@@ -10142,23 +10142,23 @@ class UnopNode(ExprNode):
(self.operator, self.operand.type))
self.type = PyrexTypes.error_type
- def analyse_cpp_operation(self, env, overload_check=True):
- entry = env.lookup_operator(self.operator, [self.operand])
- if overload_check and not entry:
- self.type_error()
- return
- if entry:
- self.exception_check = entry.type.exception_check
- self.exception_value = entry.type.exception_value
- if self.exception_check == '+':
- self.is_temp = True
- if self.exception_value is None:
- env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
- else:
- self.exception_check = ''
- self.exception_value = ''
+ def analyse_cpp_operation(self, env, overload_check=True):
+ entry = env.lookup_operator(self.operator, [self.operand])
+ if overload_check and not entry:
+ self.type_error()
+ return
+ if entry:
+ self.exception_check = entry.type.exception_check
+ self.exception_value = entry.type.exception_value
+ if self.exception_check == '+':
+ self.is_temp = True
+ if self.exception_value is None:
+ env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
+ else:
+ self.exception_check = ''
+ self.exception_value = ''
cpp_type = self.operand.type.find_cpp_operation_type(self.operator)
- if overload_check and cpp_type is None:
+ if overload_check and cpp_type is None:
error(self.pos, "'%s' operator not defined for %s" % (
self.operator, type))
self.type_error()
@@ -10181,7 +10181,7 @@ class NotNode(UnopNode):
operand = self.operand.compile_time_value(denv)
try:
return not operand
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def infer_unop_type(self, env, operand_type):
@@ -10191,7 +10191,7 @@ class NotNode(UnopNode):
self.operand = self.operand.analyse_types(env)
operand_type = self.operand.type
if operand_type.is_cpp_class:
- self.analyse_cpp_operation(env)
+ self.analyse_cpp_operation(env)
else:
self.operand = self.operand.coerce_to_boolean(env)
return self
@@ -10329,12 +10329,12 @@ class AmpersandNode(CUnopNode):
self.operand = self.operand.analyse_types(env)
argtype = self.operand.type
if argtype.is_cpp_class:
- self.analyse_cpp_operation(env, overload_check=False)
+ self.analyse_cpp_operation(env, overload_check=False)
if not (argtype.is_cfunction or argtype.is_reference or self.operand.is_addressable()):
if argtype.is_memoryviewslice:
self.error("Cannot take address of memoryview slice")
else:
- self.error("Taking address of non-lvalue (type %s)" % argtype)
+ self.error("Taking address of non-lvalue (type %s)" % argtype)
return self
if argtype.is_pyobject:
self.error("Cannot take address of Python %s" % (
@@ -10342,8 +10342,8 @@ class AmpersandNode(CUnopNode):
"object attribute '%s'" % self.operand.attribute if self.operand.is_attribute else
"object"))
return self
- if not argtype.is_cpp_class or not self.type:
- self.type = PyrexTypes.c_ptr_type(argtype)
+ if not argtype.is_cpp_class or not self.type:
+ self.type = PyrexTypes.c_ptr_type(argtype)
return self
def check_const(self):
@@ -10358,11 +10358,11 @@ class AmpersandNode(CUnopNode):
return "(&%s)" % self.operand.result()
def generate_result_code(self, code):
- if (self.operand.type.is_cpp_class and self.exception_check == '+'):
- translate_cpp_exception(code, self.pos,
- "%s = %s %s;" % (self.result(), self.operator, self.operand.result()),
- self.result() if self.type.is_pyobject else None,
- self.exception_value, self.in_nogil_context)
+ if (self.operand.type.is_cpp_class and self.exception_check == '+'):
+ translate_cpp_exception(code, self.pos,
+ "%s = %s %s;" % (self.result(), self.operator, self.operand.result()),
+ self.result() if self.type.is_pyobject else None,
+ self.exception_value, self.in_nogil_context)
unop_node_classes = {
@@ -10432,15 +10432,15 @@ class TypecastNode(ExprNode):
return CoerceIntToBytesNode(self.operand, env)
elif self.operand.type.can_coerce_to_pyobject(env):
self.result_ctype = py_object_type
- self.operand = self.operand.coerce_to(self.type, env)
+ self.operand = self.operand.coerce_to(self.type, env)
else:
if self.operand.type.is_ptr:
if not (self.operand.type.base_type.is_void or self.operand.type.base_type.is_struct):
error(self.pos, "Python objects cannot be cast from pointers of primitive types")
else:
# Should this be an error?
- warning(self.pos, "No conversion from %s to %s, python object pointer used." % (
- self.operand.type, self.type))
+ warning(self.pos, "No conversion from %s to %s, python object pointer used." % (
+ self.operand.type, self.type))
self.operand = self.operand.coerce_to_simple(env)
elif from_py and not to_py:
if self.type.create_from_py_utility_code(env):
@@ -10449,8 +10449,8 @@ class TypecastNode(ExprNode):
if not (self.type.base_type.is_void or self.type.base_type.is_struct):
error(self.pos, "Python objects cannot be cast to pointers of primitive types")
else:
- warning(self.pos, "No conversion from %s to %s, python object pointer used." % (
- self.type, self.operand.type))
+ warning(self.pos, "No conversion from %s to %s, python object pointer used." % (
+ self.type, self.operand.type))
elif from_py and to_py:
if self.typecheck:
self.operand = PyTypeTestNode(self.operand, self.type, env, notnone=True)
@@ -10462,13 +10462,13 @@ class TypecastNode(ExprNode):
elif self.operand.type.is_fused:
self.operand = self.operand.coerce_to(self.type, env)
#self.type = self.operand.type
- if self.type.is_ptr and self.type.base_type.is_cfunction and self.type.base_type.nogil:
- op_type = self.operand.type
- if op_type.is_ptr:
- op_type = op_type.base_type
- if op_type.is_cfunction and not op_type.nogil:
- warning(self.pos,
- "Casting a GIL-requiring function into a nogil function circumvents GIL validation", 1)
+ if self.type.is_ptr and self.type.base_type.is_cfunction and self.type.base_type.nogil:
+ op_type = self.operand.type
+ if op_type.is_ptr:
+ op_type = op_type.base_type
+ if op_type.is_cfunction and not op_type.nogil:
+ warning(self.pos,
+ "Casting a GIL-requiring function into a nogil function circumvents GIL validation", 1)
return self
def is_simple(self):
@@ -10538,7 +10538,7 @@ ERR_STEPS = ("Strides may only be given to indicate contiguity. "
ERR_NOT_POINTER = "Can only create cython.array from pointer or array"
ERR_BASE_TYPE = "Pointer base type does not match cython.array base type"
-
+
class CythonArrayNode(ExprNode):
"""
Used when a pointer of base_type is cast to a memoryviewslice with that
@@ -10667,7 +10667,7 @@ class CythonArrayNode(ExprNode):
axes[-1] = ('direct', 'contig')
self.coercion_type = PyrexTypes.MemoryViewSliceType(array_dtype, axes)
- self.coercion_type.validate_memslice_dtype(self.pos)
+ self.coercion_type.validate_memslice_dtype(self.pos)
self.type = self.get_cython_array_type(env)
MemoryView.use_cython_array_utility_code(env)
env.use_utility_code(MemoryView.typeinfo_to_format_code)
@@ -10697,7 +10697,7 @@ class CythonArrayNode(ExprNode):
shapes_temp = code.funcstate.allocate_temp(py_object_type, True)
format_temp = code.funcstate.allocate_temp(py_object_type, True)
- itemsize = "sizeof(%s)" % dtype.empty_declaration_code()
+ itemsize = "sizeof(%s)" % dtype.empty_declaration_code()
type_info = Buffer.get_type_information_cname(code, dtype)
if self.operand.type.is_ptr:
@@ -10805,8 +10805,8 @@ class SizeofTypeNode(SizeofNode):
def check_type(self):
arg_type = self.arg_type
- if not arg_type:
- return
+ if not arg_type:
+ return
if arg_type.is_pyobject and not arg_type.is_extension_type:
error(self.pos, "Cannot take sizeof Python object")
elif arg_type.is_void:
@@ -10820,7 +10820,7 @@ class SizeofTypeNode(SizeofNode):
# we want the size of the actual struct
arg_code = self.arg_type.declaration_code("", deref=1)
else:
- arg_code = self.arg_type.empty_declaration_code()
+ arg_code = self.arg_type.empty_declaration_code()
return "(sizeof(%s))" % arg_code
@@ -10851,78 +10851,78 @@ class SizeofVarNode(SizeofNode):
def generate_result_code(self, code):
pass
-
-class TypeidNode(ExprNode):
- # C++ typeid operator applied to a type or variable
- #
- # operand ExprNode
- # arg_type ExprNode
- # is_variable boolean
-
- type = PyrexTypes.error_type
-
- subexprs = ['operand']
-
- arg_type = None
- is_variable = None
- is_temp = 1
-
- def get_type_info_type(self, env):
- env_module = env
- while not env_module.is_module_scope:
- env_module = env_module.outer_scope
- typeinfo_module = env_module.find_module('libcpp.typeinfo', self.pos)
- typeinfo_entry = typeinfo_module.lookup('type_info')
- return PyrexTypes.CFakeReferenceType(PyrexTypes.c_const_type(typeinfo_entry.type))
-
+
+class TypeidNode(ExprNode):
+ # C++ typeid operator applied to a type or variable
+ #
+ # operand ExprNode
+ # arg_type ExprNode
+ # is_variable boolean
+
+ type = PyrexTypes.error_type
+
+ subexprs = ['operand']
+
+ arg_type = None
+ is_variable = None
+ is_temp = 1
+
+ def get_type_info_type(self, env):
+ env_module = env
+ while not env_module.is_module_scope:
+ env_module = env_module.outer_scope
+ typeinfo_module = env_module.find_module('libcpp.typeinfo', self.pos)
+ typeinfo_entry = typeinfo_module.lookup('type_info')
+ return PyrexTypes.CFakeReferenceType(PyrexTypes.c_const_type(typeinfo_entry.type))
+
cpp_message = 'typeid operator'
- def analyse_types(self, env):
+ def analyse_types(self, env):
self.cpp_check(env)
- type_info = self.get_type_info_type(env)
- if not type_info:
- self.error("The 'libcpp.typeinfo' module must be cimported to use the typeid() operator")
- return self
- self.type = type_info
- as_type = self.operand.analyse_as_type(env)
- if as_type:
- self.arg_type = as_type
- self.is_type = True
- else:
- self.arg_type = self.operand.analyse_types(env)
- self.is_type = False
- if self.arg_type.type.is_pyobject:
- self.error("Cannot use typeid on a Python object")
- return self
- elif self.arg_type.type.is_void:
- self.error("Cannot use typeid on void")
- return self
- elif not self.arg_type.type.is_complete():
- self.error("Cannot use typeid on incomplete type '%s'" % self.arg_type.type)
- return self
- env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
- return self
-
- def error(self, mess):
- error(self.pos, mess)
- self.type = PyrexTypes.error_type
- self.result_code = "<error>"
-
- def check_const(self):
- return True
-
- def calculate_result_code(self):
- return self.temp_code
-
- def generate_result_code(self, code):
- if self.is_type:
- arg_code = self.arg_type.empty_declaration_code()
- else:
- arg_code = self.arg_type.result()
- translate_cpp_exception(code, self.pos,
- "%s = typeid(%s);" % (self.temp_code, arg_code),
- None, None, self.in_nogil_context)
-
+ type_info = self.get_type_info_type(env)
+ if not type_info:
+ self.error("The 'libcpp.typeinfo' module must be cimported to use the typeid() operator")
+ return self
+ self.type = type_info
+ as_type = self.operand.analyse_as_type(env)
+ if as_type:
+ self.arg_type = as_type
+ self.is_type = True
+ else:
+ self.arg_type = self.operand.analyse_types(env)
+ self.is_type = False
+ if self.arg_type.type.is_pyobject:
+ self.error("Cannot use typeid on a Python object")
+ return self
+ elif self.arg_type.type.is_void:
+ self.error("Cannot use typeid on void")
+ return self
+ elif not self.arg_type.type.is_complete():
+ self.error("Cannot use typeid on incomplete type '%s'" % self.arg_type.type)
+ return self
+ env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
+ return self
+
+ def error(self, mess):
+ error(self.pos, mess)
+ self.type = PyrexTypes.error_type
+ self.result_code = "<error>"
+
+ def check_const(self):
+ return True
+
+ def calculate_result_code(self):
+ return self.temp_code
+
+ def generate_result_code(self, code):
+ if self.is_type:
+ arg_code = self.arg_type.empty_declaration_code()
+ else:
+ arg_code = self.arg_type.result()
+ translate_cpp_exception(code, self.pos,
+ "%s = typeid(%s);" % (self.temp_code, arg_code),
+ None, None, self.in_nogil_context)
+
class TypeofNode(ExprNode):
# Compile-time type of an expression, as a string.
#
@@ -11034,7 +11034,7 @@ class BinopNode(ExprNode):
operand2 = self.operand2.compile_time_value(denv)
try:
return func(operand1, operand2)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
def infer_type(self, env):
@@ -11068,7 +11068,7 @@ class BinopNode(ExprNode):
return self.is_py_operation_types(self.operand1.type, self.operand2.type)
def is_py_operation_types(self, type1, type2):
- return type1.is_pyobject or type2.is_pyobject or type1.is_ctuple or type2.is_ctuple
+ return type1.is_pyobject or type2.is_pyobject or type1.is_ctuple or type2.is_ctuple
def is_pythran_operation(self, env):
return self.is_pythran_operation_types(self.operand1.type, self.operand2.type, env)
@@ -11089,14 +11089,14 @@ class BinopNode(ExprNode):
self.type_error()
return
func_type = entry.type
- self.exception_check = func_type.exception_check
- self.exception_value = func_type.exception_value
- if self.exception_check == '+':
- # Used by NumBinopNodes to break up expressions involving multiple
- # operators so that exceptions can be handled properly.
- self.is_temp = 1
- if self.exception_value is None:
- env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
+ self.exception_check = func_type.exception_check
+ self.exception_value = func_type.exception_value
+ if self.exception_check == '+':
+ # Used by NumBinopNodes to break up expressions involving multiple
+ # operators so that exceptions can be handled properly.
+ self.is_temp = 1
+ if self.exception_value is None:
+ env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
if func_type.is_ptr:
func_type = func_type.base_type
if len(func_type.args) == 1:
@@ -11153,19 +11153,19 @@ class BinopNode(ExprNode):
if self.type.is_pythran_expr:
code.putln("// Pythran binop")
code.putln("__Pyx_call_destructor(%s);" % self.result())
- if self.operator == '**':
- code.putln("new (&%s) decltype(%s){pythonic::numpy::functor::power{}(%s, %s)};" % (
- self.result(),
- self.result(),
- self.operand1.pythran_result(),
- self.operand2.pythran_result()))
- else:
- code.putln("new (&%s) decltype(%s){%s %s %s};" % (
- self.result(),
- self.result(),
- self.operand1.pythran_result(),
- self.operator,
- self.operand2.pythran_result()))
+ if self.operator == '**':
+ code.putln("new (&%s) decltype(%s){pythonic::numpy::functor::power{}(%s, %s)};" % (
+ self.result(),
+ self.result(),
+ self.operand1.pythran_result(),
+ self.operand2.pythran_result()))
+ else:
+ code.putln("new (&%s) decltype(%s){%s %s %s};" % (
+ self.result(),
+ self.result(),
+ self.operand1.pythran_result(),
+ self.operator,
+ self.operand2.pythran_result()))
elif self.operand1.type.is_pyobject:
function = self.py_operation_function(code)
if self.operator == '**':
@@ -11182,15 +11182,15 @@ class BinopNode(ExprNode):
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
elif self.is_temp:
- # C++ overloaded operators with exception values are currently all
- # handled through temporaries.
- if self.is_cpp_operation() and self.exception_check == '+':
- translate_cpp_exception(code, self.pos,
- "%s = %s;" % (self.result(), self.calculate_result_code()),
- self.result() if self.type.is_pyobject else None,
- self.exception_value, self.in_nogil_context)
- else:
- code.putln("%s = %s;" % (self.result(), self.calculate_result_code()))
+ # C++ overloaded operators with exception values are currently all
+ # handled through temporaries.
+ if self.is_cpp_operation() and self.exception_check == '+':
+ translate_cpp_exception(code, self.pos,
+ "%s = %s;" % (self.result(), self.calculate_result_code()),
+ self.result() if self.type.is_pyobject else None,
+ self.exception_value, self.in_nogil_context)
+ else:
+ code.putln("%s = %s;" % (self.result(), self.calculate_result_code()))
def type_error(self):
if not (self.operand1.type.is_error
@@ -11222,8 +11222,8 @@ class CBinopNode(BinopNode):
cpp_type = None
if type1.is_cpp_class or type1.is_ptr:
cpp_type = type1.find_cpp_operation_type(self.operator, type2)
- if cpp_type is None and (type2.is_cpp_class or type2.is_ptr):
- cpp_type = type2.find_cpp_operation_type(self.operator, type1)
+ if cpp_type is None and (type2.is_cpp_class or type2.is_ptr):
+ cpp_type = type2.find_cpp_operation_type(self.operator, type1)
# FIXME: do we need to handle other cases here?
return cpp_type
@@ -11327,7 +11327,7 @@ class NumBinopNode(BinopNode):
self.operand1.result(),
self.operand2.result(),
self.overflow_bit_node.overflow_bit)
- elif self.type.is_cpp_class or self.infix:
+ elif self.type.is_cpp_class or self.infix:
if is_pythran_expr(self.type):
result1, result2 = self.operand1.pythran_result(), self.operand2.pythran_result()
else:
@@ -11416,14 +11416,14 @@ class AddNode(NumBinopNode):
def py_operation_function(self, code):
type1, type2 = self.operand1.type, self.operand2.type
-
+
if type1 is unicode_type or type2 is unicode_type:
if type1 in (unicode_type, str_type) and type2 in (unicode_type, str_type):
is_unicode_concat = True
elif isinstance(self.operand1, FormattedValueNode) or isinstance(self.operand2, FormattedValueNode):
# Assume that even if we don't know the second type, it's going to be a string.
is_unicode_concat = True
- else:
+ else:
# Operation depends on the second type.
is_unicode_concat = False
@@ -11500,7 +11500,7 @@ class DivNode(NumBinopNode):
func = compile_time_binary_operators[self.operator]
if self.operator == '/' and self.truedivision is None:
# => true div for floats, floor div for integers
- if isinstance(op1, _py_int_types) and isinstance(op2, _py_int_types):
+ if isinstance(op1, _py_int_types) and isinstance(op2, _py_int_types):
func = compile_time_binary_operators['//']
return func
@@ -11519,23 +11519,23 @@ class DivNode(NumBinopNode):
func = self.find_compile_time_binary_operator(
operand1, operand2)
return func(operand1, operand2)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
- def _check_truedivision(self, env):
+ def _check_truedivision(self, env):
if self.cdivision or env.directives['cdivision']:
self.ctruedivision = False
else:
self.ctruedivision = self.truedivision
-
- def infer_type(self, env):
- self._check_truedivision(env)
- return self.result_type(
- self.operand1.infer_type(env),
+
+ def infer_type(self, env):
+ self._check_truedivision(env)
+ return self.result_type(
+ self.operand1.infer_type(env),
self.operand2.infer_type(env), env)
-
- def analyse_operation(self, env):
- self._check_truedivision(env)
+
+ def analyse_operation(self, env):
+ self._check_truedivision(env)
NumBinopNode.analyse_operation(self, env)
if self.is_cpp_operation():
self.cdivision = True
@@ -11550,7 +11550,7 @@ class DivNode(NumBinopNode):
self.operand2 = self.operand2.coerce_to_simple(env)
def compute_c_result_type(self, type1, type2):
- if self.operator == '/' and self.ctruedivision and not type1.is_cpp_class and not type2.is_cpp_class:
+ if self.operator == '/' and self.ctruedivision and not type1.is_cpp_class and not type2.is_cpp_class:
if not type1.is_float and not type2.is_float:
widest_type = PyrexTypes.widest_numeric_type(type1, PyrexTypes.c_double_type)
widest_type = PyrexTypes.widest_numeric_type(type2, widest_type)
@@ -11566,19 +11566,19 @@ class DivNode(NumBinopNode):
def generate_evaluation_code(self, code):
if not self.type.is_pyobject and not self.type.is_complex:
if self.cdivision is None:
- self.cdivision = (
- code.globalstate.directives['cdivision']
- or self.type.is_float
- or ((self.type.is_numeric or self.type.is_enum) and not self.type.signed)
- )
+ self.cdivision = (
+ code.globalstate.directives['cdivision']
+ or self.type.is_float
+ or ((self.type.is_numeric or self.type.is_enum) and not self.type.signed)
+ )
if not self.cdivision:
- code.globalstate.use_utility_code(
- UtilityCode.load_cached("DivInt", "CMath.c").specialize(self.type))
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached("DivInt", "CMath.c").specialize(self.type))
NumBinopNode.generate_evaluation_code(self, code)
self.generate_div_warning_code(code)
def generate_div_warning_code(self, code):
- in_nogil = self.in_nogil_context
+ in_nogil = self.in_nogil_context
if not self.type.is_pyobject:
if self.zerodivision_check:
if not self.infix:
@@ -11586,62 +11586,62 @@ class DivNode(NumBinopNode):
else:
zero_test = "%s == 0" % self.operand2.result()
code.putln("if (unlikely(%s)) {" % zero_test)
- if in_nogil:
- code.put_ensure_gil()
+ if in_nogil:
+ code.put_ensure_gil()
code.putln('PyErr_SetString(PyExc_ZeroDivisionError, "%s");' % self.zero_division_message())
- if in_nogil:
- code.put_release_ensured_gil()
+ if in_nogil:
+ code.put_release_ensured_gil()
code.putln(code.error_goto(self.pos))
code.putln("}")
if self.type.is_int and self.type.signed and self.operator != '%':
- code.globalstate.use_utility_code(UtilityCode.load_cached("UnaryNegOverflows", "Overflow.c"))
+ code.globalstate.use_utility_code(UtilityCode.load_cached("UnaryNegOverflows", "Overflow.c"))
if self.operand2.type.signed == 2:
# explicitly signed, no runtime check needed
minus1_check = 'unlikely(%s == -1)' % self.operand2.result()
else:
- type_of_op2 = self.operand2.type.empty_declaration_code()
+ type_of_op2 = self.operand2.type.empty_declaration_code()
minus1_check = '(!(((%s)-1) > 0)) && unlikely(%s == (%s)-1)' % (
type_of_op2, self.operand2.result(), type_of_op2)
code.putln("else if (sizeof(%s) == sizeof(long) && %s "
" && unlikely(UNARY_NEG_WOULD_OVERFLOW(%s))) {" % (
- self.type.empty_declaration_code(),
+ self.type.empty_declaration_code(),
minus1_check,
self.operand1.result()))
- if in_nogil:
- code.put_ensure_gil()
+ if in_nogil:
+ code.put_ensure_gil()
code.putln('PyErr_SetString(PyExc_OverflowError, "value too large to perform division");')
- if in_nogil:
- code.put_release_ensured_gil()
+ if in_nogil:
+ code.put_release_ensured_gil()
code.putln(code.error_goto(self.pos))
code.putln("}")
if code.globalstate.directives['cdivision_warnings'] and self.operator != '/':
- code.globalstate.use_utility_code(
- UtilityCode.load_cached("CDivisionWarning", "CMath.c"))
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached("CDivisionWarning", "CMath.c"))
code.putln("if (unlikely((%s < 0) ^ (%s < 0))) {" % (
self.operand1.result(),
self.operand2.result()))
- warning_code = "__Pyx_cdivision_warning(%(FILENAME)s, %(LINENO)s)" % {
+ warning_code = "__Pyx_cdivision_warning(%(FILENAME)s, %(LINENO)s)" % {
'FILENAME': Naming.filename_cname,
'LINENO': Naming.lineno_cname,
- }
-
- if in_nogil:
- result_code = 'result'
- code.putln("int %s;" % result_code)
- code.put_ensure_gil()
- code.putln(code.set_error_info(self.pos, used=True))
- code.putln("%s = %s;" % (result_code, warning_code))
- code.put_release_ensured_gil()
- else:
- result_code = warning_code
- code.putln(code.set_error_info(self.pos, used=True))
-
- code.put("if (unlikely(%s)) " % result_code)
+ }
+
+ if in_nogil:
+ result_code = 'result'
+ code.putln("int %s;" % result_code)
+ code.put_ensure_gil()
+ code.putln(code.set_error_info(self.pos, used=True))
+ code.putln("%s = %s;" % (result_code, warning_code))
+ code.put_release_ensured_gil()
+ else:
+ result_code = warning_code
+ code.putln(code.set_error_info(self.pos, used=True))
+
+ code.put("if (unlikely(%s)) " % result_code)
code.put_goto(code.error_label)
code.putln("}")
def calculate_result_code(self):
- if self.type.is_complex or self.is_cpp_operation():
+ if self.type.is_complex or self.is_cpp_operation():
return NumBinopNode.calculate_result_code(self)
elif self.type.is_float and self.operator == '//':
return "floor(%s / %s)" % (
@@ -11725,12 +11725,12 @@ class ModNode(DivNode):
if not self.type.is_pyobject and not self.cdivision:
if self.type.is_int:
code.globalstate.use_utility_code(
- UtilityCode.load_cached("ModInt", "CMath.c").specialize(self.type))
+ UtilityCode.load_cached("ModInt", "CMath.c").specialize(self.type))
else: # float
code.globalstate.use_utility_code(
- UtilityCode.load_cached("ModFloat", "CMath.c").specialize(
+ UtilityCode.load_cached("ModFloat", "CMath.c").specialize(
self.type, math_h_modifier=self.type.math_h_modifier))
- # NOTE: skipping over DivNode here
+ # NOTE: skipping over DivNode here
NumBinopNode.generate_evaluation_code(self, code)
self.generate_div_warning_code(code)
@@ -11752,19 +11752,19 @@ class ModNode(DivNode):
self.operand2.result())
def py_operation_function(self, code):
- type1, type2 = self.operand1.type, self.operand2.type
- # ("..." % x) must call "x.__rmod__()" for string subtypes.
- if type1 is unicode_type:
- if self.operand1.may_be_none() or (
- type2.is_extension_type and type2.subtype_of(type1) or
- type2 is py_object_type and not isinstance(self.operand2, CoerceToPyTypeNode)):
+ type1, type2 = self.operand1.type, self.operand2.type
+ # ("..." % x) must call "x.__rmod__()" for string subtypes.
+ if type1 is unicode_type:
+ if self.operand1.may_be_none() or (
+ type2.is_extension_type and type2.subtype_of(type1) or
+ type2 is py_object_type and not isinstance(self.operand2, CoerceToPyTypeNode)):
return '__Pyx_PyUnicode_FormatSafe'
else:
return 'PyUnicode_Format'
- elif type1 is str_type:
- if self.operand1.may_be_none() or (
- type2.is_extension_type and type2.subtype_of(type1) or
- type2 is py_object_type and not isinstance(self.operand2, CoerceToPyTypeNode)):
+ elif type1 is str_type:
+ if self.operand1.may_be_none() or (
+ type2.is_extension_type and type2.subtype_of(type1) or
+ type2 is py_object_type and not isinstance(self.operand2, CoerceToPyTypeNode)):
return '__Pyx_PyString_FormatSafe'
else:
return '__Pyx_PyString_Format'
@@ -11780,18 +11780,18 @@ class PowNode(NumBinopNode):
if self.type.real_type.is_float:
self.operand1 = self.operand1.coerce_to(self.type, env)
self.operand2 = self.operand2.coerce_to(self.type, env)
- self.pow_func = self.type.binary_op('**')
+ self.pow_func = self.type.binary_op('**')
else:
error(self.pos, "complex int powers not supported")
self.pow_func = "<error>"
elif self.type.is_float:
self.pow_func = "pow" + self.type.math_h_modifier
elif self.type.is_int:
- self.pow_func = "__Pyx_pow_%s" % self.type.empty_declaration_code().replace(' ', '_')
+ self.pow_func = "__Pyx_pow_%s" % self.type.empty_declaration_code().replace(' ', '_')
env.use_utility_code(
- UtilityCode.load_cached("IntPow", "CMath.c").specialize(
+ UtilityCode.load_cached("IntPow", "CMath.c").specialize(
func_name=self.pow_func,
- type=self.type.empty_declaration_code(),
+ type=self.type.empty_declaration_code(),
signed=self.type.signed and 1 or 0))
elif not self.type.is_error:
error(self.pos, "got unexpected types for C power operator: %s, %s" %
@@ -11812,7 +11812,7 @@ class PowNode(NumBinopNode):
def py_operation_function(self, code):
if (self.type.is_pyobject and
self.operand1.constant_result == 2 and
- isinstance(self.operand1.constant_result, _py_int_types) and
+ isinstance(self.operand1.constant_result, _py_int_types) and
self.operand2.type is py_object_type):
code.globalstate.use_utility_code(UtilityCode.load_cached('PyNumberPow2', 'Optimize.c'))
if self.inplace:
@@ -11913,13 +11913,13 @@ class BoolBinopNode(ExprNode):
my_label = and_label = code.new_label('next_and')
else:
my_label = or_label = code.new_label('next_or')
- self.operand1.generate_bool_evaluation_code(
+ self.operand1.generate_bool_evaluation_code(
code, final_result_temp, final_result_type, and_label, or_label, end_label, my_label)
and_label, or_label = outer_labels
code.put_label(my_label)
- self.operand2.generate_bool_evaluation_code(
+ self.operand2.generate_bool_evaluation_code(
code, final_result_temp, final_result_type, and_label, or_label, end_label, fall_through)
def generate_evaluation_code(self, code):
@@ -11928,7 +11928,7 @@ class BoolBinopNode(ExprNode):
or_label = and_label = None
end_label = code.new_label('bool_binop_done')
self.generate_bool_evaluation_code(code, self.result(), result_type, and_label, or_label, end_label, end_label)
- code.put_label(end_label)
+ code.put_label(end_label)
gil_message = "Truth-testing Python object"
@@ -12024,43 +12024,43 @@ class BoolBinopResultNode(ExprNode):
self.arg.generate_evaluation_code(code)
if and_label or or_label:
test_result, uses_temp = self.generate_operand_test(code)
- if uses_temp and (and_label and or_label):
- # cannot become final result => free early
- # disposal: uses_temp and (and_label and or_label)
- self.arg.generate_disposal_code(code)
+ if uses_temp and (and_label and or_label):
+ # cannot become final result => free early
+ # disposal: uses_temp and (and_label and or_label)
+ self.arg.generate_disposal_code(code)
sense = '!' if or_label else ''
code.putln("if (%s%s) {" % (sense, test_result))
if uses_temp:
code.funcstate.release_temp(test_result)
- if not uses_temp or not (and_label and or_label):
- # disposal: (not uses_temp) or {not (and_label and or_label) [if]}
- self.arg.generate_disposal_code(code)
+ if not uses_temp or not (and_label and or_label):
+ # disposal: (not uses_temp) or {not (and_label and or_label) [if]}
+ self.arg.generate_disposal_code(code)
- if or_label and or_label != fall_through:
+ if or_label and or_label != fall_through:
# value is false => short-circuit to next 'or'
code.put_goto(or_label)
if and_label:
# value is true => go to next 'and'
- if or_label:
+ if or_label:
code.putln("} else {")
- if not uses_temp:
- # disposal: (not uses_temp) and {(and_label and or_label) [else]}
- self.arg.generate_disposal_code(code)
- if and_label != fall_through:
- code.put_goto(and_label)
+ if not uses_temp:
+ # disposal: (not uses_temp) and {(and_label and or_label) [else]}
+ self.arg.generate_disposal_code(code)
+ if and_label != fall_through:
+ code.put_goto(and_label)
if not and_label or not or_label:
# if no next 'and' or 'or', we provide the result
- if and_label or or_label:
- code.putln("} else {")
+ if and_label or or_label:
+ code.putln("} else {")
self.value.generate_evaluation_code(code)
self.value.make_owned_reference(code)
code.putln("%s = %s;" % (final_result_temp, self.value.result_as(final_result_type)))
self.value.generate_post_assignment_code(code)
- # disposal: {not (and_label and or_label) [else]}
+ # disposal: {not (and_label and or_label) [else]}
self.arg.generate_disposal_code(code)
self.value.free_temps(code)
- if end_label != fall_through:
+ if end_label != fall_through:
code.put_goto(end_label)
if and_label or or_label:
@@ -12077,7 +12077,7 @@ class CondExprNode(ExprNode):
true_val = None
false_val = None
- is_temp = True
+ is_temp = True
subexprs = ['test', 'true_val', 'false_val']
@@ -12107,8 +12107,8 @@ class CondExprNode(ExprNode):
def analyse_result_type(self, env):
self.type = PyrexTypes.independent_spanning_type(
self.true_val.type, self.false_val.type)
- if self.type.is_reference:
- self.type = PyrexTypes.CFakeReferenceType(self.type.ref_base_type)
+ if self.type.is_reference:
+ self.type = PyrexTypes.CFakeReferenceType(self.type.ref_base_type)
if self.type.is_pyobject:
self.result_ctype = py_object_type
elif self.true_val.is_ephemeral() or self.false_val.is_ephemeral():
@@ -12116,16 +12116,16 @@ class CondExprNode(ExprNode):
if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject:
self.true_val = self.true_val.coerce_to(self.type, env)
self.false_val = self.false_val.coerce_to(self.type, env)
- if self.type.is_error:
+ if self.type.is_error:
self.type_error()
return self
- def coerce_to_integer(self, env):
- self.true_val = self.true_val.coerce_to_integer(env)
- self.false_val = self.false_val.coerce_to_integer(env)
- self.result_ctype = None
- return self.analyse_result_type(env)
-
+ def coerce_to_integer(self, env):
+ self.true_val = self.true_val.coerce_to_integer(env)
+ self.false_val = self.false_val.coerce_to_integer(env)
+ self.result_ctype = None
+ return self.analyse_result_type(env)
+
def coerce_to(self, dst_type, env):
self.true_val = self.true_val.coerce_to(dst_type, env)
self.false_val = self.false_val.coerce_to(dst_type, env)
@@ -12202,8 +12202,8 @@ class CmpNode(object):
def calculate_cascaded_constant_result(self, operand1_result):
func = compile_time_binary_operators[self.operator]
operand2_result = self.operand2.constant_result
- if (isinstance(operand1_result, any_string_type) and
- isinstance(operand2_result, any_string_type) and
+ if (isinstance(operand1_result, any_string_type) and
+ isinstance(operand2_result, any_string_type) and
type(operand1_result) != type(operand2_result)):
# string comparison of different types isn't portable
return
@@ -12228,7 +12228,7 @@ class CmpNode(object):
operand2 = self.operand2.compile_time_value(denv)
try:
result = func(operand1, operand2)
- except Exception as e:
+ except Exception as e:
self.compile_time_value_error(e)
result = None
if result:
@@ -12300,9 +12300,9 @@ class CmpNode(object):
if new_common_type is None:
# fall back to generic type compatibility tests
- if type1.is_ctuple or type2.is_ctuple:
- new_common_type = py_object_type
- elif type1 == type2:
+ if type1.is_ctuple or type2.is_ctuple:
+ new_common_type = py_object_type
+ elif type1 == type2:
new_common_type = type1
elif type1.is_pyobject or type2.is_pyobject:
if type2.is_numeric or type2.is_string:
@@ -12414,7 +12414,7 @@ class CmpNode(object):
if self.operand2.type is Builtin.dict_type:
self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable")
self.special_bool_cmp_utility_code = UtilityCode.load_cached("PyDictContains", "ObjectHandling.c")
- self.special_bool_cmp_function = "__Pyx_PyDict_ContainsTF"
+ self.special_bool_cmp_function = "__Pyx_PyDict_ContainsTF"
return True
elif self.operand2.type is Builtin.set_type:
self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable")
@@ -12424,13 +12424,13 @@ class CmpNode(object):
elif self.operand2.type is Builtin.unicode_type:
self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable")
self.special_bool_cmp_utility_code = UtilityCode.load_cached("PyUnicodeContains", "StringTools.c")
- self.special_bool_cmp_function = "__Pyx_PyUnicode_ContainsTF"
+ self.special_bool_cmp_function = "__Pyx_PyUnicode_ContainsTF"
return True
else:
if not self.operand2.type.is_pyobject:
self.operand2 = self.operand2.coerce_to_pyobject(env)
self.special_bool_cmp_utility_code = UtilityCode.load_cached("PySequenceContains", "ObjectHandling.c")
- self.special_bool_cmp_function = "__Pyx_PySequence_ContainsTF"
+ self.special_bool_cmp_function = "__Pyx_PySequence_ContainsTF"
return True
return False
@@ -12501,20 +12501,20 @@ class CmpNode(object):
common_type = type1
code1 = operand1.result_as(common_type)
code2 = operand2.result_as(common_type)
- statement = "%s = %s(%s %s %s);" % (
+ statement = "%s = %s(%s %s %s);" % (
result_code,
coerce_result,
code1,
self.c_operator(op),
- code2)
- if self.is_cpp_comparison() and self.exception_check == '+':
- translate_cpp_exception(
- code,
- self.pos,
- statement,
- result_code if self.type.is_pyobject else None,
- self.exception_value,
- self.in_nogil_context)
+ code2)
+ if self.is_cpp_comparison() and self.exception_check == '+':
+ translate_cpp_exception(
+ code,
+ self.pos,
+ statement,
+ result_code if self.type.is_pyobject else None,
+ self.exception_value,
+ self.in_nogil_context)
else:
code.putln(statement)
@@ -12658,7 +12658,7 @@ class PrimaryCmpNode(ExprNode, CmpNode):
def analyse_cpp_comparison(self, env):
type1 = self.operand1.type
type2 = self.operand2.type
- self.is_pycmp = False
+ self.is_pycmp = False
entry = env.lookup_operator(self.operator, [self.operand1, self.operand2])
if entry is None:
error(self.pos, "Invalid types for '%s' (%s, %s)" %
@@ -12669,12 +12669,12 @@ class PrimaryCmpNode(ExprNode, CmpNode):
func_type = entry.type
if func_type.is_ptr:
func_type = func_type.base_type
- self.exception_check = func_type.exception_check
- self.exception_value = func_type.exception_value
- if self.exception_check == '+':
- self.is_temp = True
- if self.exception_value is None:
- env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
+ self.exception_check = func_type.exception_check
+ self.exception_value = func_type.exception_value
+ if self.exception_check == '+':
+ self.is_temp = True
+ if self.exception_value is None:
+ env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
if len(func_type.args) == 1:
self.operand2 = self.operand2.coerce_to(func_type.args[0].type, env)
else:
@@ -12836,10 +12836,10 @@ class CascadedCmpNode(Node, CmpNode):
def has_python_operands(self):
return self.operand2.type.is_pyobject
- def is_cpp_comparison(self):
- # cascaded comparisons aren't currently implemented for c++ classes.
- return False
-
+ def is_cpp_comparison(self):
+ # cascaded comparisons aren't currently implemented for c++ classes.
+ return False
+
def optimise_comparison(self, operand1, env, result_is_bool=False):
if self.find_special_bool_compare_function(env, operand1, result_is_bool):
self.is_pycmp = False
@@ -12912,19 +12912,19 @@ binop_node_classes = {
"**": PowNode,
}
-
-def binop_node(pos, operator, operand1, operand2, inplace=False, **kwargs):
+
+def binop_node(pos, operator, operand1, operand2, inplace=False, **kwargs):
# Construct binop node of appropriate class for
# given operator.
- return binop_node_classes[operator](
- pos,
- operator=operator,
- operand1=operand1,
- operand2=operand2,
- inplace=inplace,
- **kwargs)
-
-
+ return binop_node_classes[operator](
+ pos,
+ operator=operator,
+ operand1=operand1,
+ operand2=operand2,
+ inplace=inplace,
+ **kwargs)
+
+
#-------------------------------------------------------------------
#
# Coercion nodes
@@ -12961,7 +12961,7 @@ class CoercionNode(ExprNode):
code.annotate((file, line, col-1), AnnotationItem(
style='coerce', tag='coerce', text='[%s] to [%s]' % (self.arg.type, self.type)))
-
+
class CoerceToMemViewSliceNode(CoercionNode):
"""
Coerce an object to a memoryview slice. This holds a new reference in
@@ -13190,7 +13190,7 @@ class CoerceToPyTypeNode(CoercionNode):
# to a Python object.
type = py_object_type
- target_type = py_object_type
+ target_type = py_object_type
is_temp = 1
def __init__(self, arg, env, type=py_object_type):
@@ -13210,17 +13210,17 @@ class CoerceToPyTypeNode(CoercionNode):
self.type = unicode_type
elif arg.type.is_complex:
self.type = Builtin.complex_type
- self.target_type = self.type
+ self.target_type = self.type
elif arg.type.is_string or arg.type.is_cpp_string:
if (type not in (bytes_type, bytearray_type)
and not env.directives['c_string_encoding']):
error(arg.pos,
"default encoding required for conversion from '%s' to '%s'" %
(arg.type, type))
- self.type = self.target_type = type
+ self.type = self.target_type = type
else:
# FIXME: check that the target type and the resulting type are compatible
- self.target_type = type
+ self.target_type = type
gil_message = "Converting to Python object"
@@ -13248,11 +13248,11 @@ class CoerceToPyTypeNode(CoercionNode):
return self
def generate_result_code(self, code):
- code.putln('%s; %s' % (
- self.arg.type.to_py_call_code(
- self.arg.result(),
- self.result(),
- self.target_type),
+ code.putln('%s; %s' % (
+ self.arg.type.to_py_call_code(
+ self.arg.result(),
+ self.result(),
+ self.target_type),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
@@ -13320,7 +13320,7 @@ class CoerceFromPyTypeNode(CoercionNode):
return self
def is_ephemeral(self):
- return (self.type.is_ptr and not self.type.is_array) and self.arg.is_ephemeral()
+ return (self.type.is_ptr and not self.type.is_array) and self.arg.is_ephemeral()
def generate_result_code(self, code):
from_py_function = None
@@ -13330,7 +13330,7 @@ class CoerceFromPyTypeNode(CoercionNode):
from_py_function = '__Pyx_PyBytes' + self.type.from_py_function[len('__Pyx_PyObject'):]
NoneCheckNode.generate_if_needed(self.arg, code, "expected bytes, NoneType found")
- code.putln(self.type.from_py_call_code(
+ code.putln(self.type.from_py_call_code(
self.arg.py_result(), self.result(), self.pos, code, from_py_function=from_py_function))
if self.type.is_pyobject:
code.put_gotref(self.py_result())
@@ -13346,14 +13346,14 @@ class CoerceToBooleanNode(CoercionNode):
type = PyrexTypes.c_bint_type
_special_builtins = {
- Builtin.list_type: 'PyList_GET_SIZE',
- Builtin.tuple_type: 'PyTuple_GET_SIZE',
- Builtin.set_type: 'PySet_GET_SIZE',
- Builtin.frozenset_type: 'PySet_GET_SIZE',
- Builtin.bytes_type: 'PyBytes_GET_SIZE',
+ Builtin.list_type: 'PyList_GET_SIZE',
+ Builtin.tuple_type: 'PyTuple_GET_SIZE',
+ Builtin.set_type: 'PySet_GET_SIZE',
+ Builtin.frozenset_type: 'PySet_GET_SIZE',
+ Builtin.bytes_type: 'PyBytes_GET_SIZE',
Builtin.bytearray_type: 'PyByteArray_GET_SIZE',
- Builtin.unicode_type: '__Pyx_PyUnicode_IS_TRUE',
- }
+ Builtin.unicode_type: '__Pyx_PyUnicode_IS_TRUE',
+ }
def __init__(self, arg, env):
CoercionNode.__init__(self, arg)
@@ -13390,7 +13390,7 @@ class CoerceToBooleanNode(CoercionNode):
self.arg.py_result(),
code.error_goto_if_neg(self.result(), self.pos)))
-
+
class CoerceToComplexNode(CoercionNode):
def __init__(self, arg, dst_type, env):