summaryrefslogtreecommitdiffstats
path: root/debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/ExprNodes.py
diff options
context:
space:
mode:
authorSlávek Banko <slavek.banko@axis.cz>2021-03-26 13:52:33 +0100
committerSlávek Banko <slavek.banko@axis.cz>2021-03-26 13:52:33 +0100
commit0f27805eedcc40ae34009aa31a4dc08cb949f867 (patch)
tree8b1c8995d7fdab97acde4bd7c63f96d378c34d02 /debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/ExprNodes.py
parentbad411472a12b93f8bfca6b7ca52d89488a8d8ce (diff)
downloadextra-dependencies-0f27805eedcc40ae34009aa31a4dc08cb949f867.tar.gz
extra-dependencies-0f27805eedcc40ae34009aa31a4dc08cb949f867.zip
DEB pyrex: Added to repository.
Signed-off-by: Slávek Banko <slavek.banko@axis.cz>
Diffstat (limited to 'debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/ExprNodes.py')
-rw-r--r--debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/ExprNodes.py3954
1 files changed, 3954 insertions, 0 deletions
diff --git a/debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/ExprNodes.py b/debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/ExprNodes.py
new file mode 100644
index 00000000..c2848286
--- /dev/null
+++ b/debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/ExprNodes.py
@@ -0,0 +1,3954 @@
+#
+# Pyrex - Parse tree nodes for expressions
+#
+
+import operator
+from string import join
+
+from Errors import error, InternalError
+import Naming
+from Nodes import Node
+import PyrexTypes
+from PyrexTypes import py_object_type, c_long_type, typecast, error_type, \
+ CPtrType, CFuncType, COverloadedFuncType
+import Symtab
+import Options
+
+from Pyrex.Debugging import print_call_chain
+from DebugFlags import debug_disposal_code, debug_temp_alloc, \
+ debug_coercion
+
+class ExprNode(Node):
+ # subexprs [string] Class var holding names of subexpr node attrs
+ # type PyrexType Type of the result
+ # result_code string Code fragment
+ # result_ctype string C type of result_code if different from type
+ # inplace_result string Temp var holding in-place operation result
+ # is_temp boolean Result is in a temporary variable
+ # is_sequence_constructor
+ # boolean Is a list or tuple constructor expression
+ # saved_subexpr_nodes
+ # [ExprNode or [ExprNode or None] or None]
+ # Cached result of subexpr_nodes()
+
+ result_ctype = None
+
+ # The Analyse Expressions phase for expressions is split
+ # into two sub-phases:
+ #
+ # Analyse Types
+ # Determines the result type of the expression based
+ # on the types of its sub-expressions, and inserts
+ # coercion nodes into the expression tree where needed.
+ # Marks nodes which will need to have temporary variables
+ # allocated.
+ #
+ # Allocate Temps
+ # Allocates temporary variables where needed, and fills
+ # in the result_code field of each node.
+ #
+ # ExprNode provides some convenience routines which
+ # perform both of the above phases. These should only
+ # be called from statement nodes, and only when no
+ # coercion nodes need to be added around the expression
+ # being analysed. If coercion is needed, the above two phases
+ # should be invoked separately.
+ #
+ # Framework code in ExprNode provides much of the common
+ # processing for the various phases. It makes use of the
+ # 'subexprs' class attribute of ExprNodes, which should
+ # contain a list of the names of attributes which can
+ # hold sub-nodes or sequences of sub-nodes.
+ #
+ # The framework makes use of a number of abstract methods.
+ # Their responsibilities are as follows.
+ #
+ # Declaration Analysis phase
+ #
+ # analyse_target_declaration
+ # Called during the Analyse Declarations phase to analyse
+ # the LHS of an assignment or argument of a del statement.
+ # Nodes which cannot be the LHS of an assignment need not
+ # implement it.
+ #
+ # Expression Analysis phase
+ #
+ # analyse_types
+ # - Call analyse_types on all sub-expressions.
+ # - Check operand types, and wrap coercion nodes around
+ # sub-expressions where needed.
+ # - Set the type of this node.
+ # - If a temporary variable will be required for the
+ # result, set the is_temp flag of this node.
+ #
+ # analyse_target_types
+ # Called during the Analyse Types phase to analyse
+ # the LHS of an assignment or argument of a del
+ # statement. Similar responsibilities to analyse_types.
+ #
+ # allocate_temps
+ # - Call allocate_temps for all sub-nodes.
+ # - Call allocate_temp for this node.
+ # - If a temporary was allocated, call release_temp on
+ # all sub-expressions.
+ #
+ # allocate_target_temps
+ # - Call allocate_temps on sub-nodes and allocate any other
+ # temps used during assignment.
+ # - Fill in result_code with a C lvalue if needed.
+ # - If a rhs node is supplied, call release_temp on it.
+ # - Call release_temp on sub-nodes and release any other
+ # temps used during assignment.
+ #
+ # #calculate_result_code
+ # # - Called during the Allocate Temps phase. Should return a
+ # # C code fragment evaluating to the result. This is only
+ # # called when the result is not a temporary.
+ #
+ # target_code
+ # Called by the default implementation of allocate_target_temps.
+ # Should return a C lvalue for assigning to the node. The default
+ # implementation calls calculate_result_code.
+ #
+ # check_const
+ # - Check that this node and its subnodes form a
+ # legal constant expression. If so, do nothing,
+ # otherwise call not_const.
+ #
+ # The default implementation of check_const
+ # assumes that the expression is not constant.
+ #
+ # check_const_addr
+ # - Same as check_const, except check that the
+ # expression is a C lvalue whose address is
+ # constant. Otherwise, call addr_not_const.
+ #
+ # The default implementation of calc_const_addr
+ # assumes that the expression is not a constant
+ # lvalue.
+ #
+ # Code Generation phase
+ #
+ # generate_evaluation_code
+ # 1. Call generate_evaluation_code for sub-expressions.
+ # 2. Generate any C statements necessary to calculate
+ # the result of this node from the results of its
+ # sub-expressions. If result is not in a temporary, record
+ # any information that will be needed by this node's
+ # implementation of calculate_result_code().
+ # 4. If result is in a temporary, call generate_disposal_code
+ # on all sub-expressions.
+ #
+ # A default implementation of generate_evaluation_code
+ # is provided which uses the folling abstract methods:
+ # generate_result_code (for no. 2)
+ #
+ # generate_assignment_code
+ # Called on the LHS of an assignment.
+ # - Call generate_evaluation_code for sub-expressions.
+ # - Generate code to perform the assignment.
+ # - If the assignment absorbed a reference, call
+ # generate_post_assignment_code on the RHS,
+ # otherwise call generate_disposal_code on it.
+ #
+ # generate_deletion_code
+ # Called on an argument of a del statement.
+ # - Call generate_evaluation_code for sub-expressions.
+ # - Generate code to perform the deletion.
+ # - Call generate_disposal_code on all sub-expressions.
+ #
+ # calculate_result_code
+ # Return a C code fragment representing the result of this node.
+ # This is only called if the result is not in a temporary.
+ #
+
+ is_sequence_constructor = 0
+ is_attribute = 0
+
+ saved_subexpr_nodes = None
+ is_temp = 0
+
+ def not_implemented(self, method_name):
+ print_call_chain(method_name, "not implemented") ###
+ raise InternalError(
+ "%s.%s not implemented" %
+ (self.__class__.__name__, method_name))
+
+ def is_lvalue(self):
+ return 0
+
+ def is_inplace_lvalue(self):
+ return 0
+
+ def is_ephemeral(self):
+ # An ephemeral node is one whose result is in
+ # a Python temporary and we suspect there are no
+ # other references to it. Certain operations are
+ # disallowed on such values, since they are
+ # likely to result in a dangling pointer.
+ return self.type.is_pyobject and self.is_temp
+
+ def subexpr_nodes(self):
+ # Extract a list of subexpression nodes based
+ # on the contents of the subexprs class attribute.
+ if self.saved_subexpr_nodes is None:
+ nodes = []
+ for name in self.subexprs:
+ item = getattr(self, name)
+ if item:
+ if isinstance(item, ExprNode):
+ nodes.append(item)
+ else:
+ nodes.extend(item)
+ self.saved_subexpr_nodes = nodes
+ return self.saved_subexpr_nodes
+
+ def result(self):
+ # Return a C code fragment for the result of this node.
+ if self.is_temp:
+ result_code = self.result_code
+ else:
+ result_code = self.calculate_result_code()
+ return result_code
+
+ def result_as(self, type = None):
+ # Return the result code cast to the specified C type.
+ return typecast(type, self.ctype(), self.result())
+
+ def py_result(self):
+ # Return the result code cast to PyObject *.
+ return self.result_as(py_object_type)
+
+ def ctype(self):
+ # Return the native C type of the result.
+ return self.result_ctype or self.type
+
+ def compile_time_value(self, denv):
+ # Return value of compile-time expression, or report error.
+ error(self.pos, "Invalid compile-time expression")
+
+ def compile_time_value_error(self, e):
+ error(self.pos, "Error in compile-time expression: %s: %s" % (
+ e.__class__.__name__, e))
+
+ # ------------- Declaration Analysis ----------------
+
+ def analyse_target_declaration(self, env):
+ error(self.pos, "Cannot assign to or delete this")
+
+ # ------------- Expression Analysis ----------------
+
+ def analyse_const_expression(self, env):
+ # Called during the analyse_declarations phase of a
+ # constant expression. Analyses the expression's type,
+ # checks whether it is a legal const expression,
+ # and determines its value.
+ self.analyse_types(env)
+ self.allocate_temps(env)
+ self.check_const()
+
+ def analyse_expressions(self, env):
+ # Convenience routine performing both the Type
+ # Analysis and Temp Allocation phases for a whole
+ # expression.
+ self.analyse_types(env)
+ self.allocate_temps(env)
+
+ def analyse_target_expression(self, env, rhs):
+ # Convenience routine performing both the Type
+ # Analysis and Temp Allocation phases for the LHS of
+ # an assignment.
+ self.analyse_target_types(env)
+ self.allocate_target_temps(env, rhs)
+
+ def analyse_boolean_expression(self, env):
+ # Analyse expression and coerce to a boolean.
+ self.analyse_types(env)
+ bool = self.coerce_to_boolean(env)
+ bool.allocate_temps(env)
+ return bool
+
+ def analyse_temp_boolean_expression(self, env):
+ # Analyse boolean expression and coerce result into
+ # a temporary. This is used when a branch is to be
+ # performed on the result and we won't have an
+ # opportunity to ensure disposal code is executed
+ # afterwards. By forcing the result into a temporary,
+ # we ensure that all disposal has been done by the
+ # time we get the result.
+ self.analyse_types(env)
+ bool = self.coerce_to_boolean(env)
+ temp_bool = bool.coerce_to_temp(env)
+ temp_bool.allocate_temps(env)
+ return temp_bool
+
+ # --------------- Type Analysis ------------------
+
+ def analyse_as_function(self, env):
+ # Analyse types for an expression that is to be called.
+ self.analyse_types(env)
+
+ def analyse_as_module(self, env):
+ # If this node can be interpreted as a reference to a
+ # cimported module, return its scope, else None.
+ return None
+
+ def analyse_as_extension_type(self, env):
+ # If this node can be interpreted as a reference to an
+ # extension type, return its type, else None.
+ return None
+
+ def analyse_as_cimported_attribute(self, env, *args, **kwds):
+ # If this node can be interpreted as a cimported name,
+ # finish type analysis and return true, else return false.
+ return 0
+
+ def analyse_types(self, env):
+ self.not_implemented("analyse_types")
+
+ def analyse_target_types(self, env):
+ self.analyse_types(env)
+
+ def analyse_inplace_types(self, env):
+ if self.is_inplace_lvalue():
+ self.analyse_types(env)
+ else:
+ error(self.pos, "Invalid target for in-place operation")
+ self.type = error_type
+
+ def gil_assignment_check(self, env):
+ if env.nogil and self.type.is_pyobject:
+ error(self.pos, "Assignment of Python object not allowed without gil")
+
+ def check_const(self):
+ self.not_const()
+
+ def not_const(self):
+ error(self.pos, "Not allowed in a constant expression")
+
+ def check_const_addr(self):
+ self.addr_not_const()
+
+ def addr_not_const(self):
+ error(self.pos, "Address is not constant")
+
+ def gil_check(self, env):
+ if env.nogil and self.type.is_pyobject:
+ self.gil_error()
+
+ # ----------------- Result Allocation -----------------
+
+ def result_in_temp(self):
+ # Return true if result is in a temporary owned by
+ # this node or one of its subexpressions. Overridden
+ # by certain nodes which can share the result of
+ # a subnode.
+ return self.is_temp
+
+ def allocate_target_temps(self, env, rhs, inplace = 0):
+ # Perform temp allocation for the LHS of an assignment.
+ if debug_temp_alloc:
+ print self, "Allocating target temps"
+ self.allocate_subexpr_temps(env)
+ #self.result_code = self.target_code()
+ if rhs:
+ rhs.release_temp(env)
+ self.release_subexpr_temps(env)
+
+ def allocate_inplace_target_temps(self, env, rhs):
+ if debug_temp_alloc:
+ print self, "Allocating inplace target temps"
+ self.allocate_subexpr_temps(env)
+ #self.result_code = self.target_code()
+ py_inplace = self.type.is_pyobject
+ if py_inplace:
+ self.allocate_temp(env)
+ self.inplace_result = env.allocate_temp(py_object_type)
+ self.release_temp(env)
+ rhs.release_temp(env)
+ if py_inplace:
+ env.release_temp(self.inplace_result)
+ self.release_subexpr_temps(env)
+
+ def allocate_temps(self, env, result = None):
+ # Allocate temporary variables for this node and
+ # all its sub-expressions. If a result is specified,
+ # this must be a temp node and the specified variable
+ # is used as the result instead of allocating a new
+ # one.
+ if debug_temp_alloc:
+ print self, "Allocating temps"
+ self.allocate_subexpr_temps(env)
+ self.allocate_temp(env, result)
+ if self.is_temp:
+ self.release_subexpr_temps(env)
+
+ def allocate_subexpr_temps(self, env):
+ # Allocate temporary variables for all sub-expressions
+ # of this node.
+ if debug_temp_alloc:
+ print self, "Allocating temps for:", self.subexprs
+ for node in self.subexpr_nodes():
+ if node:
+ if debug_temp_alloc:
+ print self, "Allocating temps for", node
+ node.allocate_temps(env)
+
+ def allocate_temp(self, env, result = None):
+ # If this node requires a temporary variable for its
+ # result, allocate one. If a result is specified,
+ # this must be a temp node and the specified variable
+ # is used as the result instead of allocating a new
+ # one.
+ if debug_temp_alloc:
+ print self, "Allocating temp"
+ if result:
+ if not self.is_temp:
+ raise InternalError("Result forced on non-temp node")
+ self.result_code = result
+ elif self.is_temp:
+ type = self.type
+ if not type.is_void:
+ if type.is_pyobject:
+ type = PyrexTypes.py_object_type
+ self.result_code = env.allocate_temp(type)
+ else:
+ self.result_code = None
+ if debug_temp_alloc:
+ print self, "Allocated result", self.result_code
+ #else:
+ # self.result_code = self.calculate_result_code()
+
+ def target_code(self):
+ # Return code fragment for use as LHS of a C assignment.
+ return self.calculate_result_code()
+
+ def calculate_result_code(self):
+ self.not_implemented("calculate_result_code")
+
+ def release_temp(self, env):
+ # If this node owns a temporary result, release it,
+ # otherwise release results of its sub-expressions.
+ if self.is_temp:
+ if debug_temp_alloc:
+ print self, "Releasing result", self.result_code
+ env.release_temp(self.result_code)
+ else:
+ self.release_subexpr_temps(env)
+
+ def release_subexpr_temps(self, env):
+ # Release the results of all sub-expressions of
+ # this node.
+ for node in self.subexpr_nodes():
+ if node:
+ node.release_temp(env)
+
+ # ---------------- Code Generation -----------------
+
+ def mark_vars_used(self):
+ for node in self.subexpr_nodes():
+ node.mark_vars_used()
+
+ def make_owned_reference(self, code):
+ # If result is a pyobject, make sure we own
+ # a reference to it.
+ if self.type.is_pyobject and not self.result_in_temp():
+ code.put_incref(self.py_result())
+
+ def generate_evaluation_code(self, code):
+ # Generate code to evaluate this node and
+ # its sub-expressions, and dispose of any
+ # temporary results of its sub-expressions.
+ self.generate_subexpr_evaluation_code(code)
+ self.generate_result_code(code)
+ if self.is_temp:
+ self.generate_subexpr_disposal_code(code)
+
+ def generate_subexpr_evaluation_code(self, code):
+ for node in self.subexpr_nodes():
+ node.generate_evaluation_code(code)
+
+ def generate_result_code(self, code):
+ self.not_implemented("generate_result_code")
+
+ inplace_functions = {
+ "+=": "PyNumber_InPlaceAdd",
+ "-=": "PyNumber_InPlaceSubtract",
+ "*=": "PyNumber_InPlaceMultiply",
+ "/=": "PyNumber_InPlaceDivide",
+ "%=": "PyNumber_InPlaceRemainder",
+ "**=": "PyNumber_InPlacePower",
+ "<<=": "PyNumber_InPlaceLshift",
+ ">>=": "PyNumber_InPlaceRshift",
+ "&=": "PyNumber_InPlaceAnd",
+ "^=": "PyNumber_InPlaceXor",
+ "|=": "PyNumber_InPlaceOr",
+ }
+
+ def generate_inplace_operation_code(self, operator, rhs, code):
+ args = (self.py_result(), rhs.py_result())
+ if operator == "**=":
+ arg_code = "%s, %s, Py_None" % args
+ else:
+ arg_code = "%s, %s" % args
+ code.putln("%s = %s(%s); if (!%s) %s" % (
+ self.inplace_result,
+ self.inplace_functions[operator],
+ arg_code,
+ self.inplace_result,
+ code.error_goto(self.pos)))
+ if self.is_temp:
+ code.put_decref_clear(self.py_result())
+ rhs.generate_disposal_code(code)
+ if self.type.is_extension_type:
+ code.putln(
+ "if (!__Pyx_TypeTest(%s, %s)) %s" % (
+ self.inplace_result,
+ self.type.typeptr_cname,
+ code.error_goto(self.pos)))
+
+ def generate_disposal_code(self, code):
+ # If necessary, generate code to dispose of
+ # temporary Python reference.
+ if self.is_temp:
+ if self.type.is_pyobject:
+ code.put_decref_clear(self.py_result(), self.ctype())
+ else:
+ self.generate_subexpr_disposal_code(code)
+
+ def generate_subexpr_disposal_code(self, code):
+ # Generate code to dispose of temporary results
+ # of all sub-expressions.
+ for node in self.subexpr_nodes():
+ node.generate_disposal_code(code)
+
+ def generate_post_assignment_code(self, code):
+ # Same as generate_disposal_code except that
+ # assignment will have absorbed a reference to
+ # the result if it is a Python object.
+ if self.is_temp:
+ if self.type.is_pyobject:
+ code.putln("%s = 0;" % self.result())
+ else:
+ self.generate_subexpr_disposal_code(code)
+
+ def generate_inplace_result_disposal_code(self, code):
+ code.put_decref_clear(self.inplace_result, py_object_type)
+
+ def generate_assignment_code(self, rhs, code):
+ # Stub method for nodes which are not legal as
+ # the LHS of an assignment. An error will have
+ # been reported earlier.
+ pass
+
+ def generate_deletion_code(self, code):
+ # Stub method for nodes that are not legal as
+ # the argument of a del statement. An error
+ # will have been reported earlier.
+ pass
+
+ # ----------------- Coercion ----------------------
+
+ def coerce_to(self, dst_type, env):
+ # Coerce the result so that it can be assigned to
+ # something of type dst_type. If processing is necessary,
+ # wraps this node in a coercion node and returns that.
+ # Otherwise, returns this node unchanged.
+ #
+ # This method is called during the analyse_expressions
+ # phase of the src_node's processing.
+ src = self
+ src_type = self.type
+ src_is_py_type = src_type.is_pyobject
+ dst_is_py_type = dst_type.is_pyobject
+
+ if dst_type.is_pyobject:
+ if not src.type.is_pyobject:
+ src = CoerceToPyTypeNode(src, env)
+ if not src.type.subtype_of(dst_type):
+ if not isinstance(src, NoneNode):
+ src = PyTypeTestNode(src, dst_type, env)
+ elif src.type.is_pyobject:
+ src = CoerceFromPyTypeNode(dst_type, src, env)
+ else: # neither src nor dst are py types
+ if not dst_type.assignable_from(src_type):
+ error(self.pos, "Cannot assign type '%s' to '%s'" %
+ (src.type, dst_type))
+ return src
+
+ def coerce_to_pyobject(self, env):
+ return self.coerce_to(PyrexTypes.py_object_type, env)
+
+ def coerce_to_boolean(self, env):
+ # Coerce result to something acceptable as
+ # a boolean value.
+ type = self.type
+ if type.is_pyobject or type.is_ptr or type.is_float:
+ return CoerceToBooleanNode(self, env)
+ else:
+ if not type.is_int and not type.is_error:
+ error(self.pos,
+ "Type '%s' not acceptable as a boolean" % type)
+ return self
+
+ def coerce_to_integer(self, env):
+ # If not already some C integer type, coerce to longint.
+ if self.type.is_int:
+ return self
+ else:
+ return self.coerce_to(PyrexTypes.c_long_type, env)
+
+ def coerce_to_temp(self, env):
+ # Ensure that the result is in a temporary.
+ if self.result_in_temp():
+ return self
+ else:
+ return CoerceToTempNode(self, env)
+
+ def coerce_to_simple(self, env):
+ # Ensure that the result is simple (see is_simple).
+ if self.is_simple():
+ return self
+ else:
+ return self.coerce_to_temp(env)
+
+ def is_simple(self):
+ # A node is simple if its result is something that can
+ # be referred to without performing any operations, e.g.
+ # a constant, local var, C global var, struct member
+ # reference, or temporary.
+ return self.result_in_temp()
+
+
+class AtomicExprNode(ExprNode):
+ # Abstract base class for expression nodes which have
+ # no sub-expressions.
+
+ subexprs = []
+
+
+class PyConstNode(AtomicExprNode):
+ # Abstract base class for constant Python values.
+
+ def is_simple(self):
+ return 1
+
+ def analyse_types(self, env):
+ self.type = py_object_type
+
+ def calculate_result_code(self):
+ return self.value
+
+ def generate_result_code(self, code):
+ pass
+
+
+class NoneNode(PyConstNode):
+ # The constant value None
+
+ value = "Py_None"
+
+ def compile_time_value(self, denv):
+ return None
+
+
+class EllipsisNode(PyConstNode):
+ # '...' in a subscript list.
+
+ value = "Py_Ellipsis"
+
+ def compile_time_value(self, denv):
+ return Ellipsis
+
+
+class ConstNode(AtomicExprNode):
+ # Abstract base type for literal constant nodes.
+ #
+ # value string C code fragment
+
+ is_literal = 1
+
+ def is_simple(self):
+ return 1
+
+ def analyse_types(self, env):
+ pass # Types are held in class variables
+
+ def check_const(self):
+ pass
+
+ def calculate_result_code(self):
+ return str(self.value)
+
+ def generate_result_code(self, code):
+ pass
+
+
+class NullNode(ConstNode):
+ type = PyrexTypes.c_null_ptr_type
+ value = "NULL"
+
+
+class CharNode(ConstNode):
+ type = PyrexTypes.c_char_type
+
+ def compile_time_value(self, denv):
+ return ord(self.value)
+
+ def calculate_result_code(self):
+ return "'%s'" % self.value
+
+
+class IntNode(ConstNode):
+ type = PyrexTypes.c_long_type
+
+ def compile_time_value(self, denv):
+ return int(self.value, 0)
+
+
+class FloatNode(ConstNode):
+ type = PyrexTypes.c_double_type
+
+ def compile_time_value(self, denv):
+ return float(self.value)
+
+ def calculate_result_code(self):
+ strval = str(self.value)
+ if strval == 'nan':
+ return "NAN"
+ elif strval == 'inf':
+ return "INFINITY"
+ elif strval == '-inf':
+ return "(-INFINITY)"
+ else:
+ return strval
+
+
+class StringNode(ConstNode):
+ # #entry Symtab.Entry
+
+ type = PyrexTypes.c_char_ptr_type
+
+ def compile_time_value(self, denv):
+ return eval('"%s"' % self.value)
+
+# def analyse_types(self, env):
+# self.entry = env.add_string_const(self.value)
+
+ def coerce_to(self, dst_type, env):
+ # Arrange for a Python version of the string to be pre-allocated
+ # when coercing to a Python type.
+ if dst_type.is_pyobject and not self.type.is_pyobject:
+ node = self.as_py_string_node(env)
+ else:
+ node = self
+ # We still need to perform normal coerce_to processing on the
+ # result, because we might be coercing to an extension type,
+ # in which case a type test node will be needed.
+ return ConstNode.coerce_to(node, dst_type, env)
+
+ def as_py_string_node(self, env):
+ # Return a new StringNode with the same value as this node
+ # but whose type is a Python type instead of a C type.
+ #entry = self.entry
+ #env.add_py_string(entry)
+ return StringNode(self.pos, type = py_object_type, value = self.value)
+
+ def generate_evaluation_code(self, code):
+ if self.type.is_pyobject:
+ self.result_code = code.get_py_string_const(self.value)
+ else:
+ self.result_code = code.get_string_const(self.value)
+
+ def calculate_result_code(self):
+ return self.result_code
+
+
+class LongNode(AtomicExprNode):
+ # Python long integer literal
+ #
+ # value string
+
+ def compile_time_value(self, denv):
+ return long(self.value)
+
+ gil_message = "Constructing Python long int"
+
+ def analyse_types(self, env):
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ def generate_evaluation_code(self, code):
+ result = self.result()
+ code.putln(
+ '%s = PyLong_FromString("%s", 0, 0); if (!%s) %s' % (
+ self.result(),
+ self.value,
+ self.result(),
+ code.error_goto(self.pos)))
+
+
+class ImagNode(AtomicExprNode):
+ # Imaginary number literal
+ #
+ # value float imaginary part
+
+ def compile_time_value(self, denv):
+ return complex(0.0, self.value)
+
+ gil_message = "Constructing complex number"
+
+ def analyse_types(self, env):
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ def generate_evaluation_code(self, code):
+ result = self.result()
+ code.putln(
+ "%s = PyComplex_FromDoubles(0.0, %s); if (!%s) %s" % (
+ self.result(),
+ self.value,
+ self.result(),
+ code.error_goto(self.pos)))
+
+
+class NameNode(AtomicExprNode):
+ # Reference to a local or global variable name.
+ #
+ # name string Python name of the variable
+ #
+ # entry Entry Symbol table entry
+ # type_entry Entry For extension type names, the original type entry
+ # interned_cname string
+
+ is_name = 1
+ entry = None
+ type_entry = None
+
+ def compile_time_value(self, denv):
+ try:
+ return denv.lookup(self.name)
+ except KeyError:
+ error(self.pos, "Compile-time name '%s' not defined" % self.name)
+
+ def coerce_to(self, dst_type, env):
+ # If coercing to a generic pyobject and this is a builtin
+ # C function with a Python equivalent, manufacture a NameNode
+ # referring to the Python builtin.
+ #print "NameNode.coerce_to:", self.name, dst_type ###
+ if dst_type is py_object_type:
+ entry = self.entry
+ if entry.is_cfunction:
+ var_entry = entry.as_variable
+ if var_entry:
+ node = NameNode(self.pos, name = self.name)
+ node.entry = var_entry
+ node.analyse_rvalue_entry(env)
+ return node
+ return AtomicExprNode.coerce_to(self, dst_type, env)
+
+ def analyse_as_module(self, env):
+ # Try to interpret this as a reference to a cimported module.
+ # Returns the module scope, or None.
+ entry = env.lookup(self.name)
+ if entry and entry.as_module:
+ return entry.as_module
+ return None
+
+ def analyse_as_extension_type(self, env):
+ # Try to interpret this as a reference to an extension type.
+ # Returns the extension type, or None.
+ entry = env.lookup(self.name)
+ if entry and entry.is_type and entry.type.is_extension_type:
+ return entry.type
+ else:
+ return None
+
+ def analyse_target_declaration(self, env):
+ self.entry = env.lookup_here(self.name)
+ if not self.entry:
+ self.entry = env.declare_var(self.name, py_object_type, self.pos)
+
+ def analyse_types(self, env):
+ self.lookup_entry(env)
+ self.analyse_rvalue_entry(env)
+
+ def lookup_entry(self, env):
+ self.entry = env.lookup(self.name)
+ if not self.entry:
+ self.entry = env.declare_builtin(self.name, self.pos)
+
+ def analyse_target_types(self, env):
+ self.analyse_entry(env)
+ self.finish_analysing_lvalue()
+
+ def analyse_inplace_types(self, env):
+ self.analyse_rvalue_entry(env)
+ self.finish_analysing_lvalue()
+
+ def finish_analysing_lvalue(self):
+ if self.entry.is_readonly:
+ error(self.pos, "Assignment to read-only name '%s'"
+ % self.name)
+ elif not self.is_lvalue():
+ error(self.pos, "Assignment to non-lvalue '%s'"
+ % self.name)
+ self.type = PyrexTypes.error_type
+ self.entry.used = 1
+
+ def analyse_as_function(self, env):
+ self.lookup_entry(env)
+ if self.entry.is_type:
+ self.analyse_constructor_entry(env)
+ else:
+ self.analyse_rvalue_entry(env)
+
+ def analyse_constructor_entry(self, env):
+ entry = self.entry
+ type = entry.type
+ if type.is_struct_or_union:
+ self.type = entry.type.cplus_constructor_type
+ elif type.is_pyobject:
+ self.analyse_rvalue_entry(env)
+ else:
+ error(self.pos, "Type '%s' not callable as a C++ constructor" % type)
+ self.type = error_type
+
+ def analyse_rvalue_entry(self, env):
+ #print "NameNode.analyse_rvalue_entry:", self.name ###
+ #print "Entry:", self.entry.__dict__ ###
+ self.analyse_entry(env)
+ entry = self.entry
+ if entry.is_declared_generic:
+ self.result_ctype = py_object_type
+ if entry.is_pyglobal or entry.is_builtin:
+ self.is_temp = 1
+ self.gil_check(env)
+
+ gil_message = "Accessing Python global or builtin"
+
+ def analyse_entry(self, env):
+ #print "NameNode.analyse_entry:", self.name ###
+ self.check_identifier_kind()
+ entry = self.entry
+ type = entry.type
+ ctype = entry.ctype
+ self.type = type
+ if ctype:
+ self.result_ctype = ctype
+ if entry.is_pyglobal or entry.is_builtin:
+ assert type.is_pyobject, "Python global or builtin not a Python object"
+ #self.interned_cname = env.intern(self.entry.name)
+
+ def check_identifier_kind(self):
+ # Check that this is an appropriate kind of name for use in an expression.
+ # Also finds the variable entry associated with an extension type.
+ entry = self.entry
+ if entry.is_type and entry.type.is_extension_type:
+ self.type_entry = entry
+ if not (entry.is_const or entry.is_variable
+ or entry.is_builtin or entry.is_cfunction):
+ if self.entry.as_variable:
+ self.entry = self.entry.as_variable
+ else:
+ error(self.pos,
+ "'%s' is not a constant, variable or function identifier" % self.name)
+
+ def is_simple(self):
+ # If it's not a C variable, it'll be in a temp.
+ return 1
+
+ def calculate_target_results(self, env):
+ pass
+
+ def check_const(self):
+ entry = self.entry
+ if not (entry.is_const or entry.is_cfunction):
+ self.not_const()
+
+ def check_const_addr(self):
+ entry = self.entry
+ if not (entry.is_cglobal or entry.is_cfunction):
+ self.addr_not_const()
+
+ def is_lvalue(self):
+ entry = self.entry
+ return entry.is_variable and \
+ not entry.type.is_array and \
+ not entry.is_readonly
+
+ def is_inplace_lvalue(self):
+ return self.is_lvalue()
+
+ def is_ephemeral(self):
+ # Name nodes are never ephemeral, even if the
+ # result is in a temporary.
+ return 0
+
+ def allocate_temp(self, env, result = None):
+ AtomicExprNode.allocate_temp(self, env, result)
+ entry = self.entry
+ if entry:
+ entry.used = 1
+
+ def calculate_result_code(self):
+ entry = self.entry
+ if not entry:
+ return "<error>" # There was an error earlier
+ return entry.cname
+
+ def generate_result_code(self, code):
+ assert hasattr(self, 'entry')
+ entry = self.entry
+ if entry is None:
+ return # There was an error earlier
+ if entry.utility_code:
+ code.use_utility_code(entry.utility_code)
+ if entry.is_pyglobal or entry.is_builtin:
+ if entry.is_builtin:
+ namespace = Naming.builtins_cname
+ else: # entry.is_pyglobal
+ namespace = entry.namespace_cname
+ result = self.result()
+ cname = code.intern(self.entry.name)
+ code.use_utility_code(get_name_interned_utility_code)
+ code.putln(
+ '%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
+ result,
+ namespace,
+ cname,
+ result,
+ code.error_goto(self.pos)))
+
+ def generate_setattr_code(self, value_code, code):
+ entry = self.entry
+ namespace = self.entry.namespace_cname
+ cname = code.intern(self.entry.name)
+ code.putln(
+ 'if (PyObject_SetAttr(%s, %s, %s) < 0) %s' % (
+ namespace,
+ cname,
+ value_code,
+ code.error_goto(self.pos)))
+
+ def generate_assignment_code(self, rhs, code):
+ #print "NameNode.generate_assignment_code:", self.name ###
+ entry = self.entry
+ if entry is None:
+ return # There was an error earlier
+ if entry.is_pyglobal:
+ self.generate_setattr_code(rhs.py_result(), code)
+ if debug_disposal_code:
+ print "NameNode.generate_assignment_code:"
+ print "...generating disposal code for", rhs
+ rhs.generate_disposal_code(code)
+ else:
+ if self.type.is_pyobject:
+ rhs.make_owned_reference(code)
+ code.put_decref(self.py_result())
+ code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
+ if debug_disposal_code:
+ print "NameNode.generate_assignment_code:"
+ print "...generating post-assignment code for", rhs
+ rhs.generate_post_assignment_code(code)
+
+ def generate_inplace_assignment_code(self, operator, rhs, code):
+ entry = self.entry
+ if entry is None:
+ return # There was an error earlier
+ if self.type.is_pyobject:
+ self.generate_result_code(code)
+ self.generate_inplace_operation_code(operator, rhs, code)
+ if entry.is_pyglobal:
+ self.generate_setattr_code(self.inplace_result, code)
+ self.generate_inplace_result_disposal_code(code)
+ else:
+ code.put_decref(self.py_result())
+ cast_inplace_result = typecast(self.ctype(), py_object_type, self.inplace_result)
+ code.putln('%s = %s;' % (self.result(), cast_inplace_result))
+ else:
+ code.putln("%s %s %s;" % (self.result(), operator, rhs.result()))
+ rhs.generate_disposal_code(code)
+
+ def generate_deletion_code(self, code):
+ if self.entry is None:
+ return # There was an error earlier
+ if not self.entry.is_pyglobal:
+ error(self.pos, "Deletion of local or C global name not supported")
+ return
+ cname = code.intern(self.entry.name)
+ code.putln(
+ 'if (PyObject_DelAttr(%s, %s) < 0) %s' % (
+ Naming.module_cname,
+ cname,
+ code.error_goto(self.pos)))
+
+ def mark_vars_used(self):
+ if self.entry:
+ self.entry.used = 1
+
+
+class BackquoteNode(ExprNode):
+ # `expr`
+ #
+ # arg ExprNode
+
+ subexprs = ['arg']
+
+ def analyse_types(self, env):
+ self.arg.analyse_types(env)
+ self.arg = self.arg.coerce_to_pyobject(env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ gil_message = "Backquote expression"
+
+ def generate_result_code(self, code):
+ result = self.result()
+ code.putln(
+ "%s = PyObject_Repr(%s); if (!%s) %s" % (
+ self.result(),
+ self.arg.py_result(),
+ self.result(),
+ code.error_goto(self.pos)))
+
+
+class ImportNode(ExprNode):
+ # Used as part of import statement implementation.
+ # Implements result =
+ # __import__(module_name, globals(), None, name_list)
+ #
+ # module_name StringNode dotted name of module
+ # name_list ListNode or None list of names to be imported
+
+ subexprs = ['module_name', 'name_list']
+
+ def analyse_types(self, env):
+ self.module_name.analyse_types(env)
+ self.module_name = self.module_name.coerce_to_pyobject(env)
+ if self.name_list:
+ self.name_list.analyse_types(env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+# env.use_utility_code(import_utility_code)
+
+ gil_message = "Python import"
+
+ def generate_result_code(self, code):
+ if self.name_list:
+ name_list_code = self.name_list.py_result()
+ else:
+ name_list_code = "0"
+ code.use_utility_code(import_utility_code)
+ result = self.result()
+ code.putln(
+ "%s = __Pyx_Import(%s, %s); if (!%s) %s" % (
+ result,
+ self.module_name.py_result(),
+ name_list_code,
+ result,
+ code.error_goto(self.pos)))
+
+
+class IteratorNode(ExprNode):
+ # Used as part of for statement implementation.
+ # Implements result = iter(sequence)
+ #
+ # sequence ExprNode
+
+ subexprs = ['sequence']
+
+ def analyse_types(self, env):
+ self.sequence.analyse_types(env)
+ self.sequence = self.sequence.coerce_to_pyobject(env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ gil_message = "Iterating over Python object"
+
+ def generate_result_code(self, code):
+ result = self.result()
+ code.putln(
+ "%s = PyObject_GetIter(%s); if (!%s) %s" % (
+ result,
+ self.sequence.py_result(),
+ result,
+ code.error_goto(self.pos)))
+
+
+class NextNode(AtomicExprNode):
+ # Used as part of for statement implementation.
+ # Implements result = iterator.next()
+ # Created during analyse_types phase.
+ # The iterator is not owned by this node.
+ #
+ # iterator ExprNode
+
+ def __init__(self, iterator, env):
+ self.pos = iterator.pos
+ self.iterator = iterator
+ self.type = py_object_type
+ self.is_temp = 1
+
+ def generate_result_code(self, code):
+ result = self.result()
+ code.putln(
+ "%s = PyIter_Next(%s);" % (
+ result,
+ self.iterator.py_result()))
+ code.putln(
+ "if (!%s) {" %
+ result)
+ code.putln(
+ "if (PyErr_Occurred()) %s" %
+ code.error_goto(self.pos))
+ code.putln(
+ "break;")
+ code.putln(
+ "}")
+
+
+class ExcValueNode(AtomicExprNode):
+ # Node created during analyse_types phase
+ # of an ExceptClauseNode to fetch the current
+ # exception or traceback value.
+
+ def __init__(self, pos, env, var):
+ ExprNode.__init__(self, pos)
+ self.type = py_object_type
+ self.var = var
+
+ def calculate_result_code(self):
+ return self.var
+
+ def generate_result_code(self, code):
+ pass
+
+
+class TempNode(AtomicExprNode):
+ # Node created during analyse_types phase
+ # of some nodes to hold a temporary value.
+
+ def __init__(self, pos, type, env):
+ ExprNode.__init__(self, pos)
+ self.type = type
+ if type.is_pyobject:
+ self.result_ctype = py_object_type
+ self.is_temp = 1
+
+ def generate_result_code(self, code):
+ pass
+
+
+class PyTempNode(TempNode):
+ # TempNode holding a Python value.
+
+ def __init__(self, pos, env):
+ TempNode.__init__(self, pos, PyrexTypes.py_object_type, env)
+
+
+#-------------------------------------------------------------------
+#
+# Trailer nodes
+#
+#-------------------------------------------------------------------
+
+class IndexNode(ExprNode):
+ # Sequence indexing.
+ #
+ # base ExprNode
+ # index ExprNode
+
+ subexprs = ['base', 'index']
+
+ 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, e:
+ self.compile_time_value_error(e)
+
+ def is_ephemeral(self):
+ return self.base.is_ephemeral()
+
+ def analyse_target_declaration(self, env):
+ pass
+
+ def analyse_types(self, env):
+ self.analyse_base_and_index_types(env, getting = 1)
+
+ def analyse_target_types(self, env):
+ self.analyse_base_and_index_types(env, setting = 1)
+
+ def analyse_inplace_types(self, env):
+ self.analyse_base_and_index_types(env, getting = 1, setting = 1)
+
+ def analyse_base_and_index_types(self, env, getting = 0, setting = 0):
+ self.base.analyse_types(env)
+ self.index.analyse_types(env)
+ btype = self.base.type
+ if btype.is_pyobject:
+ itype = self.index.type
+ if not (btype.is_sequence and itype.is_int and itype.signed):
+ self.index = self.index.coerce_to_pyobject(env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+ else:
+ if self.base.type.is_ptr or self.base.type.is_array:
+ self.type = self.base.type.base_type
+ else:
+ error(self.pos,
+ "Attempting to index non-array type '%s'" %
+ self.base.type)
+ self.type = PyrexTypes.error_type
+ if self.index.type.is_pyobject:
+ self.index = self.index.coerce_to(
+ PyrexTypes.c_py_ssize_t_type, env)
+ if not self.index.type.is_int:
+ error(self.pos,
+ "Invalid index type '%s'" %
+ self.index.type)
+
+ gil_message = "Indexing Python object"
+
+ def check_const_addr(self):
+ self.base.check_const_addr()
+ self.index.check_const()
+
+ def is_lvalue(self):
+ return 1
+
+ def is_inplace_lvalue(self):
+ return 1
+
+ def calculate_result_code(self):
+ return "(%s[%s])" % (
+ self.base.result(), self.index.result())
+
+ def generate_result_code(self, code):
+ if self.type.is_pyobject:
+ itype = self.index.type
+ if itype.is_int and itype.signed:
+ code.use_utility_code(getitem_int_utility_code)
+ function = "__Pyx_GetItemInt"
+ index_code = self.index.result()
+ else:
+ function = "PyObject_GetItem"
+ index_code = self.index.py_result()
+ result = self.result()
+ code.putln(
+ "%s = %s(%s, %s); if (!%s) %s" % (
+ result,
+ function,
+ self.base.py_result(),
+ index_code,
+ result,
+ code.error_goto(self.pos)))
+
+ def generate_setitem_code(self, value_code, code):
+ itype = self.index.type
+ if itype.is_int and itype.signed:
+ code.use_utility_code(setitem_int_utility_code)
+ function = "__Pyx_SetItemInt"
+ index_code = self.index.result()
+ else:
+ function = "PyObject_SetItem"
+ index_code = self.index.py_result()
+ code.putln(
+ "if (%s(%s, %s, %s) < 0) %s" % (
+ function,
+ self.base.py_result(),
+ index_code,
+ value_code,
+ code.error_goto(self.pos)))
+
+ def generate_assignment_code(self, rhs, code):
+ self.generate_subexpr_evaluation_code(code)
+ if self.type.is_pyobject:
+ self.generate_setitem_code(rhs.py_result(), code)
+ else:
+ code.putln(
+ "%s = %s;" % (
+ self.result(), rhs.result()))
+ self.generate_subexpr_disposal_code(code)
+ rhs.generate_disposal_code(code)
+
+ def generate_inplace_assignment_code(self, operator, rhs, code):
+ self.generate_subexpr_evaluation_code(code)
+ if self.type.is_pyobject:
+ self.generate_result_code(code)
+ self.generate_inplace_operation_code(operator, rhs, code)
+ self.generate_setitem_code(self.inplace_result, code)
+ self.generate_inplace_result_disposal_code(code)
+ else:
+ code.putln("%s %s %s;" % (self.result(), operator, rhs.result()))
+ rhs.generate_disposal_code(code)
+ self.generate_subexpr_disposal_code(code)
+
+ def generate_deletion_code(self, code):
+ self.generate_subexpr_evaluation_code(code)
+ if self.base.type.is_sequence and self.index.type.is_int:
+ function = "PySequence_DelItem"
+ index_code = self.index.result()
+ else:
+ function = "PyObject_DelItem"
+ index_code = self.index.py_result()
+ code.putln(
+ "if (%s(%s, %s) < 0) %s" % (
+ function,
+ self.base.py_result(),
+ index_code,
+ code.error_goto(self.pos)))
+ #else:
+ # error(self.pos, "Cannot delete non-Python variable")
+ self.generate_subexpr_disposal_code(code)
+
+
+class SliceIndexNode(ExprNode):
+ # 2-element slice indexing
+ #
+ # base ExprNode
+ # start ExprNode or None
+ # stop ExprNode or None
+
+ subexprs = ['base', 'start', 'stop']
+
+ def is_inplace_lvalue(self):
+ return 1
+
+ def compile_time_value(self, denv):
+ base = self.base.compile_time_value(denv)
+ start = self.start.compile_time_value(denv)
+ stop = self.stop.compile_time_value(denv)
+ try:
+ return base[start:stop]
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ def analyse_target_declaration(self, env):
+ pass
+
+ def analyse_types(self, env):
+ self.base.analyse_types(env)
+ if self.start:
+ self.start.analyse_types(env)
+ if self.stop:
+ self.stop.analyse_types(env)
+ self.base = self.base.coerce_to_pyobject(env)
+ c_int = PyrexTypes.c_py_ssize_t_type
+ if self.start:
+ self.start = self.start.coerce_to(c_int, env)
+ if self.stop:
+ self.stop = self.stop.coerce_to(c_int, env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ gil_message = "Slicing Python object"
+
+ def generate_result_code(self, code):
+ result = self.result()
+ code.putln(
+ "%s = PySequence_GetSlice(%s, %s, %s); if (!%s) %s" % (
+ result,
+ self.base.py_result(),
+ self.start_code(),
+ self.stop_code(),
+ result,
+ code.error_goto(self.pos)))
+
+ def generate_setslice_code(self, value_code, code):
+ code.putln(
+ "if (PySequence_SetSlice(%s, %s, %s, %s) < 0) %s" % (
+ self.base.py_result(),
+ self.start_code(),
+ self.stop_code(),
+ value_code,
+ code.error_goto(self.pos)))
+
+ def generate_assignment_code(self, rhs, code):
+ self.generate_subexpr_evaluation_code(code)
+ self.generate_setslice_code(rhs.result(), code)
+ self.generate_subexpr_disposal_code(code)
+ rhs.generate_disposal_code(code)
+
+ def generate_inplace_assignment_code(self, operator, rhs, code):
+ self.generate_subexpr_evaluation_code(code)
+ self.generate_result_code(code)
+ self.generate_inplace_operation_code(operator, rhs, code)
+ self.generate_setslice_code(self.inplace_result, code)
+ self.generate_inplace_result_disposal_code(code)
+ self.generate_subexpr_disposal_code(code)
+
+ def generate_deletion_code(self, code):
+ self.generate_subexpr_evaluation_code(code)
+ code.putln(
+ "if (PySequence_DelSlice(%s, %s, %s) < 0) %s" % (
+ self.base.py_result(),
+ self.start_code(),
+ self.stop_code(),
+ code.error_goto(self.pos)))
+ self.generate_subexpr_disposal_code(code)
+
+ def start_code(self):
+ if self.start:
+ return self.start.result()
+ else:
+ return "0"
+
+ def stop_code(self):
+ if self.stop:
+ return self.stop.result()
+ else:
+ return "PY_SSIZE_T_MAX"
+
+# def calculate_result_code(self):
+# # self.result_code is not used, but this method must exist
+# return "<unused>"
+
+
+class SliceNode(ExprNode):
+ # start:stop:step in subscript list
+ #
+ # start ExprNode
+ # stop ExprNode
+ # step ExprNode
+
+ def compile_time_value(self, denv):
+ start = self.start.compile_time_value(denv)
+ stop = self.stop.compile_time_value(denv)
+ step = step.step.compile_time_value(denv)
+ try:
+ return slice(start, stop, step)
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ subexprs = ['start', 'stop', 'step']
+
+ def analyse_types(self, env):
+ self.start.analyse_types(env)
+ self.stop.analyse_types(env)
+ self.step.analyse_types(env)
+ self.start = self.start.coerce_to_pyobject(env)
+ self.stop = self.stop.coerce_to_pyobject(env)
+ self.step = self.step.coerce_to_pyobject(env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ gil_message = "Constructing Python slice object"
+
+ def generate_result_code(self, code):
+ result = self.result()
+ code.putln(
+ "%s = PySlice_New(%s, %s, %s); if (!%s) %s" % (
+ result,
+ self.start.py_result(),
+ self.stop.py_result(),
+ self.step.py_result(),
+ result,
+ code.error_goto(self.pos)))
+
+
+class CallNode(ExprNode):
+
+ def gil_check(self, env):
+ # Make sure we're not in a nogil environment
+ if env.nogil:
+ error(self.pos, "Calling gil-requiring function without gil")
+
+
+class SimpleCallNode(CallNode):
+ # Function call without keyword, * or ** args.
+ #
+ # function ExprNode
+ # args [ExprNode]
+ # arg_tuple ExprNode or None used internally
+ # self ExprNode or None used internally
+ # coerced_self ExprNode or None used internally
+ # function_type PyrexType used internally
+
+ subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple']
+
+ self = None
+ coerced_self = None
+ arg_tuple = None
+ is_new = False
+
+ cplus_argless_constr_type = CFuncType(None, [])
+
+ def compile_time_value(self, denv):
+ function = self.function.compile_time_value(denv)
+ args = [arg.compile_time_value(denv) for arg in self.args]
+ try:
+ return function(*args)
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ def analyse_types(self, env):
+ #print "SimpleCallNode.analyse_types:", self.pos ###
+ function = self.function
+ function.is_called = 1
+ function.analyse_as_function(env)
+ if function.is_name or function.is_attribute:
+ #print "SimpleCallNode.analyse_types:", self.pos, "is name or attribute" ###
+ func_entry = function.entry
+ if func_entry:
+ if func_entry.is_cmethod or func_entry.is_builtin_method:
+ # Take ownership of the object from which the attribute
+ # was obtained, because we need to pass it as 'self'.
+ #print "SimpleCallNode: Snarfing self argument" ###
+ self.self = function.obj
+ function.obj = CloneNode(self.self)
+ elif self.is_new:
+ if not (func_entry.is_type and func_entry.type.is_struct_or_union
+ and func_entry.type.scope.is_cplus):
+ error(self.pos, "'new' operator can only be used on a C++ struct type")
+ self.type = error_type
+ return
+ else:
+ #print "SimpleCallNode.analyse_types:", self.pos, "not name or attribute" ###
+ if self.is_new:
+ error(self.pos, "Invalid use of 'new' operator")
+ self.type = error_type
+ return
+ func_type = self.function.type
+ if func_type.is_ptr:
+ func_type = func_type.base_type
+ self.function_type = func_type
+ if func_type.is_pyobject:
+ #print "SimpleCallNode: Python call" ###
+ if self.args:
+ self.arg_tuple = TupleNode(self.pos, args = self.args)
+ self.arg_tuple.analyse_types(env)
+ else:
+ self.arg_tuple = None
+ self.args = None
+ if function.is_name and function.type_entry:
+ # We are calling an extension type constructor
+ self.type = function.type_entry.type
+ self.result_ctype = py_object_type
+ else:
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+ else:
+ #print "SimpleCallNode: C call" ###
+ for arg in self.args:
+ arg.analyse_types(env)
+ if func_type.is_cfunction:
+ self.type = func_type.return_type
+ if self.is_new:
+ self.type = CPtrType(self.type)
+ if func_type.is_overloaded:
+ func_type = self.resolve_overloading()
+ if not func_type:
+ self.type = error_type
+ return
+ if self.self and func_type.args:
+ #print "SimpleCallNode: Inserting self into argument list" ###
+ # Coerce 'self' to the type expected by the method.
+ expected_type = func_type.args[0].type
+ self.coerced_self = CloneNode(self.self).coerce_to(
+ expected_type, env)
+ # Insert coerced 'self' argument into argument list.
+ self.args.insert(0, self.coerced_self)
+ self.analyse_c_function_call(env)
+
+ def resolve_overloading(self):
+ func_type = self.function_type
+ arg_types = [arg.type for arg in self.args]
+ signatures = func_type.signatures or [self.cplus_argless_constr_type]
+ for signature in signatures:
+ if signature.callable_with(arg_types):
+ signature.return_type = func_type.return_type
+ self.function_type = signature
+ return signature
+ def display_types(types):
+ return ", ".join([str(type) for type in types])
+ error(self.pos, "No matching signature found for argument types (%s)"
+ % display_types(arg_types))
+ if signatures:
+ error(self.pos, "Candidates are:")
+ for signature in signatures:
+ error(signature.pos, "(%s)" % display_types(signature.args))
+
+ def analyse_c_function_call(self, env):
+ func_type = self.function_type
+ # Check function type
+ if not func_type.is_cfunction:
+ if not func_type.is_error:
+ error(self.pos, "Calling non-function type '%s'" %
+ func_type)
+ self.type = PyrexTypes.error_type
+ return
+ # Check no. of args
+ expected_nargs = len(func_type.args)
+ actual_nargs = len(self.args)
+ if actual_nargs < expected_nargs \
+ or (not func_type.has_varargs and actual_nargs > expected_nargs):
+ expected_str = str(expected_nargs)
+ if func_type.has_varargs:
+ expected_str = "at least " + expected_str
+ error(self.pos,
+ "Call with wrong number of arguments (expected %s, got %s)"
+ % (expected_str, actual_nargs))
+ self.args = None
+ self.type = PyrexTypes.error_type
+ return
+ # Coerce arguments
+ for i in range(expected_nargs):
+ formal_type = func_type.args[i].type
+ self.args[i] = self.args[i].coerce_to(formal_type, env)
+ for i in range(expected_nargs, actual_nargs):
+ if self.args[i].type.is_pyobject:
+ error(self.args[i].pos,
+ "Python object cannot be passed as a varargs parameter")
+ # Calc result code fragment
+ #print "SimpleCallNode.analyse_c_function_call: self.type =", self.type ###
+ if self.type.is_pyobject \
+ or func_type.exception_value is not None \
+ or func_type.exception_check:
+ self.is_temp = 1
+ if self.type.is_pyobject:
+ self.result_ctype = py_object_type
+ # Check gil
+ if not func_type.nogil:
+ self.gil_check(env)
+ if func_type.exception_check and env.nogil:
+ self.gil_error("Calling 'except ?' or 'except *' function")
+
+ def calculate_result_code(self):
+ return self.c_call_code()
+
+ def c_call_code(self):
+ if self.type.is_error or self.args is None or not self.function_type.is_cfunction:
+ return "<error>"
+ func_type = self.function_type
+ formal_args = func_type.args
+ arg_list_code = []
+ for (formal_arg, actual_arg) in zip(formal_args, self.args):
+ arg_code = actual_arg.result_as(formal_arg.type)
+ arg_list_code.append(arg_code)
+ for actual_arg in self.args[len(formal_args):]:
+ arg_list_code.append(actual_arg.result())
+ result = "%s(%s)" % (self.function.result(),
+ join(arg_list_code, ","))
+ if self.is_new:
+ result = "new " + result
+ return result
+
+ def generate_result_code(self, code):
+ if self.type.is_error:
+ return
+ func_type = self.function_type
+ result = self.result()
+ if func_type.is_pyobject:
+ if self.arg_tuple:
+ arg_code = self.arg_tuple.py_result()
+ else:
+ arg_code = "0"
+ code.putln(
+ "%s = PyObject_CallObject(%s, %s); if (!%s) %s" % (
+ result,
+ self.function.py_result(),
+ arg_code,
+ result,
+ code.error_goto(self.pos)))
+ elif func_type.is_cfunction:
+ exc_checks = []
+ if self.type.is_pyobject:
+ exc_checks.append("!%s" % result)
+ else:
+ exc_val = func_type.exception_value
+ exc_check = func_type.exception_check
+ if exc_val is not None:
+ exc_checks.append("%s == %s" % (self.result(), exc_val))
+ if exc_check:
+ exc_checks.append("PyErr_Occurred()")
+ if self.is_temp or exc_checks:
+ rhs = self.c_call_code()
+ result = self.result()
+ if result:
+ lhs = "%s = " % result
+ if self.is_temp and self.type.is_pyobject:
+ #return_type = self.type # func_type.return_type
+ #print "SimpleCallNode.generate_result_code: casting", rhs, \
+ # "from", return_type, "to pyobject" ###
+ rhs = typecast(py_object_type, self.type, rhs)
+ else:
+ lhs = ""
+ code.putln(
+ "%s%s; if (%s) %s" % (
+ lhs,
+ rhs,
+ " && ".join(exc_checks),
+ code.error_goto(self.pos)))
+
+
+class GeneralCallNode(CallNode):
+ # General Python function call, including keyword,
+ # * and ** arguments.
+ #
+ # function ExprNode
+ # positional_args ExprNode Tuple of positional arguments
+ # keyword_args ExprNode or None Dict of keyword arguments
+ # starstar_arg ExprNode or None Dict of extra keyword args
+
+ subexprs = ['function', 'positional_args', 'keyword_args', 'starstar_arg']
+
+ def compile_time_value(self, denv):
+ function = self.function.compile_time_value(denv)
+ positional_args = self.positional_args.compile_time_value(denv)
+ keyword_args = self.keyword_args.compile_time_value(denv)
+ starstar_arg = self.starstar_arg.compile_time_value(denv)
+ try:
+ keyword_args.update(starstar_arg)
+ return function(*positional_args, **keyword_args)
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ def analyse_types(self, env):
+ function = self.function
+ function.analyse_types(env)
+ self.positional_args.analyse_types(env)
+ if self.keyword_args:
+ self.keyword_args.analyse_types(env)
+ if self.starstar_arg:
+ self.starstar_arg.analyse_types(env)
+ self.function = self.function.coerce_to_pyobject(env)
+ self.positional_args = \
+ self.positional_args.coerce_to_pyobject(env)
+ if self.starstar_arg:
+ self.starstar_arg = \
+ self.starstar_arg.coerce_to_pyobject(env)
+ if function.is_name and function.type_entry:
+ # We are calling an extension type constructor
+ self.type = function.type_entry.type
+ self.result_ctype = py_object_type
+ else:
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ def generate_result_code(self, code):
+ if self.keyword_args and self.starstar_arg:
+ code.putln(
+ "if (PyDict_Update(%s, %s) < 0) %s" % (
+ self.keyword_args.py_result(),
+ self.starstar_arg.py_result(),
+ code.error_goto(self.pos)))
+ keyword_code = self.keyword_args.py_result()
+ elif self.keyword_args:
+ keyword_code = self.keyword_args.py_result()
+ elif self.starstar_arg:
+ keyword_code = self.starstar_arg.py_result()
+ else:
+ keyword_code = None
+ if not keyword_code:
+ call_code = "PyObject_CallObject(%s, %s)" % (
+ self.function.py_result(),
+ self.positional_args.py_result())
+ else:
+ call_code = "PyEval_CallObjectWithKeywords(%s, %s, %s)" % (
+ self.function.py_result(),
+ self.positional_args.py_result(),
+ keyword_code)
+ result = self.result()
+ code.putln(
+ "%s = %s; if (!%s) %s" % (
+ result,
+ call_code,
+ result,
+ code.error_goto(self.pos)))
+
+
+class AsTupleNode(ExprNode):
+ # Convert argument to tuple. Used for normalising
+ # the * argument of a function call.
+ #
+ # arg ExprNode
+
+ subexprs = ['arg']
+
+ def compile_time_value(self, denv):
+ arg = self.arg.compile_time_value(denv)
+ try:
+ return tuple(arg)
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ def analyse_types(self, env):
+ self.arg.analyse_types(env)
+ self.arg = self.arg.coerce_to_pyobject(env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ gil_message = "Constructing Python tuple"
+
+ def generate_result_code(self, code):
+ result = self.result()
+ code.putln(
+ "%s = PySequence_Tuple(%s); if (!%s) %s" % (
+ result,
+ self.arg.py_result(),
+ result,
+ code.error_goto(self.pos)))
+
+
+class AttributeNode(ExprNode):
+ # obj.attribute
+ #
+ # obj ExprNode
+ # attribute string
+ #
+ # Used internally:
+ #
+ # is_py_attr boolean Is a Python getattr operation
+ # member string C name of struct member
+ # is_called boolean Function call is being done on result
+ # entry Entry Symbol table entry of attribute
+ # interned_attr_cname string C name of interned attribute name
+
+ is_attribute = 1
+ subexprs = ['obj']
+
+ type = PyrexTypes.error_type
+ result_code = "<error>"
+ entry = None
+ is_called = 0
+
+ def compile_time_value(self, denv):
+ attr = self.attribute
+ if attr.startswith("__") and attr.endswith("__"):
+ self.error("Invalid attribute name '%s' in compile-time expression"
+ % attr)
+ return None
+ obj = self.obj.compile_time_value(denv)
+ try:
+ return getattr(obj, attr)
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ def analyse_target_declaration(self, env):
+ pass
+
+ def analyse_target_types(self, env):
+ self.analyse_types(env, target = 1)
+
+ def analyse_as_function(self, env):
+ module_scope = self.obj.analyse_as_module(env)
+ if module_scope:
+ entry = module_scope.lookup_here(self.attribute)
+ if entry and entry.is_type:
+ self.mutate_into_name_node(entry)
+ self.analyse_constructor_entry(env)
+ return
+ self.analyse_types(env)
+
+ def analyse_types(self, env, target = 0):
+ if self.analyse_as_cimported_attribute(env, target):
+ return
+ if not target and self.analyse_as_unbound_cmethod(env):
+ return
+ self.analyse_as_ordinary_attribute(env, target)
+
+ def analyse_as_cimported_attribute(self, env, target = 0, allow_type = 0):
+ # Try to interpret this as a reference to an imported
+ # C const, type, var or function. If successful, mutates
+ # this node into a NameNode and returns 1, otherwise
+ # returns 0.
+ module_scope = self.obj.analyse_as_module(env)
+ if module_scope:
+ entry = module_scope.lookup_here(self.attribute)
+ if entry and (
+ entry.is_cglobal or entry.is_cfunction
+ or entry.is_type or entry.is_const):
+ self.mutate_into_name_node(entry)
+ if entry.is_type and allow_type:
+ pass
+ elif target:
+ self.analyse_target_types(env)
+ else:
+ self.analyse_rvalue_entry(env)
+ return 1
+ return 0
+
+ def analyse_as_unbound_cmethod(self, env):
+ # Try to interpret this as a reference to an unbound
+ # C method of an extension type. If successful, mutates
+ # this node into a NameNode and returns 1, otherwise
+ # returns 0.
+ type = self.obj.analyse_as_extension_type(env)
+ if type:
+ entry = type.scope.lookup_here(self.attribute)
+ if entry and entry.is_cmethod:
+ # Create a temporary entry describing the C method
+ # as an ordinary function.
+ ubcm_entry = Symtab.Entry(entry.name,
+ "%s->%s" % (type.vtabptr_cname, entry.cname),
+ entry.type)
+ ubcm_entry.is_cfunction = 1
+ ubcm_entry.func_cname = entry.func_cname
+ self.mutate_into_name_node(ubcm_entry)
+ self.analyse_rvalue_entry(env)
+ return 1
+ return 0
+
+ def analyse_as_extension_type(self, env):
+ # Try to interpret this as a reference to an extension type
+ # in a cimported module. Returns the extension type, or None.
+ module_scope = self.obj.analyse_as_module(env)
+ if module_scope:
+ entry = module_scope.lookup_here(self.attribute)
+ if entry and entry.is_type and entry.type.is_extension_type:
+ return entry.type
+ return None
+
+ def analyse_as_module(self, env):
+ # Try to interpret this as a reference to a cimported module
+ # in another cimported module. Returns the module scope, or None.
+ module_scope = self.obj.analyse_as_module(env)
+ if module_scope:
+ entry = module_scope.lookup_here(self.attribute)
+ if entry and entry.as_module:
+ return entry.as_module
+ return None
+
+ def mutate_into_name_node(self, entry):
+ # Turn this node into a NameNode with the given entry.
+ self.__class__ = NameNode
+ self.name = self.attribute
+ self.entry = entry
+ del self.obj
+ del self.attribute
+
+ def analyse_as_ordinary_attribute(self, env, target):
+ self.obj.analyse_types(env)
+ self.analyse_attribute(env)
+ if self.entry and self.entry.is_cmethod and not self.is_called:
+ error(self.pos, "C method can only be called")
+ if self.is_py_attr:
+ if not target:
+ self.is_temp = 1
+ self.result_ctype = py_object_type
+
+ def analyse_attribute(self, env):
+ # Look up attribute and set self.type and self.member.
+ self.is_py_attr = 0
+ self.member = self.attribute
+ if self.obj.type.is_string:
+ self.obj = self.obj.coerce_to_pyobject(env)
+ obj_type = self.obj.type
+ if obj_type.is_ptr:
+ obj_type = obj_type.base_type
+ self.op = "->"
+ elif obj_type.is_extension_type:
+ self.op = "->"
+ else:
+ self.op = "."
+ if obj_type.has_attributes:
+ entry = None
+ if obj_type.attributes_known():
+ entry = obj_type.scope.lookup_here(self.attribute)
+ else:
+ error(self.pos,
+ "Cannot select attribute of incomplete type '%s'"
+ % obj_type)
+ obj_type = PyrexTypes.error_type
+ self.entry = entry
+ if entry:
+ if obj_type.is_extension_type and entry.name == "__weakref__":
+ error(self.pos, "Illegal use of special attribute __weakref__")
+ if entry.is_variable or entry.is_cmethod:
+ self.type = entry.type
+ self.member = entry.cname
+ return
+ if entry.is_builtin_method and self.is_called:
+ # Mutate into NameNode referring to C function
+ #print "AttributeNode: Mutating builtin method into NameNode" ###
+ self.type = entry.type
+ self.__class__ = NameNode
+ return
+ else:
+ # If it's not a variable or C method, it must be a Python
+ # method of an extension type, so we treat it like a Python
+ # attribute.
+ pass
+ # If we get here, the base object is not a struct/union/extension
+ # type, or it is an extension type and the attribute is either not
+ # declared or is declared as a Python method. Treat it as a Python
+ # attribute reference.
+ if obj_type.is_pyobject:
+ self.type = py_object_type
+ self.is_py_attr = 1
+ #self.interned_attr_cname = env.intern(self.attribute)
+ self.gil_check(env)
+ else:
+ if not obj_type.is_error:
+ error(self.pos,
+ "Object of type '%s' has no attribute '%s'" %
+ (obj_type, self.attribute))
+
+ gil_message = "Accessing Python attribute"
+
+ def is_simple(self):
+ if self.obj:
+ return self.result_in_temp() or self.obj.is_simple()
+ else:
+ return NameNode.is_simple(self)
+
+ def is_lvalue(self):
+ if self.obj:
+ return 1
+ else:
+ return NameNode.is_lvalue(self)
+
+ def is_inplace_lvalue(self):
+ return self.is_lvalue()
+
+ def is_ephemeral(self):
+ if self.obj:
+ return self.obj.is_ephemeral()
+ else:
+ return NameNode.is_ephemeral(self)
+
+ def calculate_result_code(self):
+ obj = self.obj
+ obj_code = obj.result_as(obj.type)
+ if self.entry and self.entry.is_cmethod:
+ return "((struct %s *)%s%s%s)->%s" % (
+ obj.type.vtabstruct_cname, obj_code, self.op,
+ obj.type.vtabslot_cname, self.member)
+ else:
+ return "%s%s%s" % (obj_code, self.op, self.member)
+
+ def generate_result_code(self, code):
+ if self.is_py_attr:
+ result = self.result()
+ cname = code.intern(self.attribute)
+ code.putln(
+ '%s = PyObject_GetAttr(%s, %s); if (!%s) %s' % (
+ result,
+ self.obj.py_result(),
+ cname,
+ result,
+ code.error_goto(self.pos)))
+
+ def generate_setattr_code(self, value_code, code):
+ cname = code.intern(self.attribute)
+ code.putln(
+ 'if (PyObject_SetAttr(%s, %s, %s) < 0) %s' % (
+ self.obj.py_result(),
+ cname,
+ value_code,
+ code.error_goto(self.pos)))
+
+ def generate_assignment_code(self, rhs, code):
+ self.obj.generate_evaluation_code(code)
+ if self.is_py_attr:
+ self.generate_setattr_code(rhs.py_result(), code)
+ rhs.generate_disposal_code(code)
+ else:
+ select_code = self.result()
+ if self.type.is_pyobject:
+ rhs.make_owned_reference(code)
+ code.put_decref(select_code, self.ctype())
+ code.putln(
+ "%s = %s;" % (
+ select_code,
+ rhs.result_as(self.ctype())))
+ rhs.generate_post_assignment_code(code)
+ self.obj.generate_disposal_code(code)
+
+ def generate_inplace_assignment_code(self, operator, rhs, code):
+ self.obj.generate_evaluation_code(code)
+ select_code = self.result()
+ if self.type.is_pyobject:
+ self.generate_result_code(code)
+ self.generate_inplace_operation_code(operator, rhs, code)
+ if self.is_py_attr:
+ self.generate_setattr_code(self.inplace_result, code)
+ self.generate_inplace_result_disposal_code(code)
+ else:
+ code.put_decref(select_code, self.ctype())
+ cast_inplace_result = typecast(self.ctype(), py_object_type, self.inplace_result)
+ code.putln("%s = %s;" % (select_code, cast_inplace_result))
+ else:
+ code.putln("%s %s %s;" % (select_code, operator, rhs.result()))
+ rhs.generate_disposal_code(code)
+ self.obj.generate_disposal_code(code)
+
+ def generate_deletion_code(self, code):
+ self.obj.generate_evaluation_code(code)
+ if self.is_py_attr:
+ cname = code.intern(self.attribute)
+ code.putln(
+ 'if (PyObject_DelAttr(%s, %s) < 0) %s' % (
+ self.obj.py_result(),
+ cname,
+ code.error_goto(self.pos)))
+ else:
+ error(self.pos, "Cannot delete C attribute of extension type")
+ self.obj.generate_disposal_code(code)
+
+#-------------------------------------------------------------------
+#
+# Constructor nodes
+#
+#-------------------------------------------------------------------
+
+class SequenceNode(ExprNode):
+ # Base class for list and tuple constructor nodes.
+ # Contains common code for performing sequence unpacking.
+ #
+ # args [ExprNode]
+ # iterator ExprNode
+ # unpacked_items [ExprNode] or None
+ # coerced_unpacked_items [ExprNode] or None
+
+ subexprs = ['args']
+
+ is_sequence_constructor = 1
+ unpacked_items = None
+
+ def compile_time_value_list(self, denv):
+ return [arg.compile_time_value(denv) for arg in self.args]
+
+ def analyse_target_declaration(self, env):
+ for arg in self.args:
+ arg.analyse_target_declaration(env)
+
+ def analyse_types(self, env):
+ for i in range(len(self.args)):
+ arg = self.args[i]
+ arg.analyse_types(env)
+ self.args[i] = arg.coerce_to_pyobject(env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ def analyse_target_types(self, env):
+ self.iterator = PyTempNode(self.pos, env)
+ self.unpacked_items = []
+ self.coerced_unpacked_items = []
+ for arg in self.args:
+ arg.analyse_target_types(env)
+ unpacked_item = PyTempNode(self.pos, env)
+ coerced_unpacked_item = unpacked_item.coerce_to(arg.type, env)
+ self.unpacked_items.append(unpacked_item)
+ self.coerced_unpacked_items.append(coerced_unpacked_item)
+ self.type = py_object_type
+# env.use_utility_code(unpacking_utility_code)
+
+ def allocate_target_temps(self, env, rhs):
+ self.iterator.allocate_temps(env)
+ if rhs:
+ rhs.release_temp(env)
+ for arg, node in zip(self.args, self.coerced_unpacked_items):
+ node.allocate_temps(env)
+ arg.allocate_target_temps(env, node)
+ #arg.release_target_temp(env)
+ #node.release_temp(env)
+ self.iterator.release_temp(env)
+
+# def release_target_temp(self, env):
+# #for arg in self.args:
+# # arg.release_target_temp(env)
+# #for node in self.coerced_unpacked_items:
+# # node.release_temp(env)
+# self.iterator.release_temp(env)
+
+ def generate_result_code(self, code):
+ self.generate_operation_code(code)
+
+ def generate_assignment_code(self, rhs, code):
+ iter_result = self.iterator.result()
+ code.putln(
+ "%s = PyObject_GetIter(%s); if (!%s) %s" % (
+ iter_result,
+ rhs.py_result(),
+ iter_result,
+ code.error_goto(self.pos)))
+ rhs.generate_disposal_code(code)
+ for i in range(len(self.args)):
+ item = self.unpacked_items[i]
+ code.use_utility_code(unpacking_utility_code)
+ unpack_code = "__Pyx_UnpackItem(%s)" % (
+ self.iterator.py_result())
+ item_result = item.result()
+ code.putln(
+ "%s = %s; if (!%s) %s" % (
+ item_result,
+ typecast(item.ctype(), py_object_type, unpack_code),
+ item_result,
+ code.error_goto(self.pos)))
+ value_node = self.coerced_unpacked_items[i]
+ value_node.generate_evaluation_code(code)
+ self.args[i].generate_assignment_code(value_node, code)
+ code.putln(
+ "if (__Pyx_EndUnpack(%s) < 0) %s" % (
+ self.iterator.py_result(),
+ code.error_goto(self.pos)))
+ if debug_disposal_code:
+ print "UnpackNode.generate_assignment_code:"
+ print "...generating disposal code for", rhs
+ self.iterator.generate_disposal_code(code)
+
+
+class TupleNode(SequenceNode):
+ # Tuple constructor.
+
+ gil_message = "Constructing Python tuple"
+
+ def compile_time_value(self, denv):
+ values = self.compile_time_value_list(denv)
+ try:
+ return tuple(values)
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ def generate_operation_code(self, code):
+ result = self.result()
+ code.putln(
+ "%s = PyTuple_New(%s); if (!%s) %s" % (
+ result,
+ len(self.args),
+ result,
+ code.error_goto(self.pos)))
+ for i in range(len(self.args)):
+ arg = self.args[i]
+ arg_result = arg.py_result()
+ # ??? Change this to use make_owned_reference?
+ if not arg.result_in_temp():
+ code.put_incref(arg_result)
+ code.putln(
+ "PyTuple_SET_ITEM(%s, %s, %s);" % (
+ result,
+ i,
+ arg_result))
+
+ def generate_subexpr_disposal_code(self, code):
+ # We call generate_post_assignment_code here instead
+ # of generate_disposal_code, because values were stored
+ # in the tuple using a reference-stealing operation.
+ for arg in self.args:
+ arg.generate_post_assignment_code(code)
+
+
+class ListNode(SequenceNode):
+ # List constructor.
+
+ gil_message = "Constructing Python list"
+
+ def compile_time_value(self, denv):
+ return self.compile_time_value_list(denv)
+
+ def generate_operation_code(self, code):
+ result = self.result()
+ code.putln("%s = PyList_New(%s); if (!%s) %s" %
+ (result,
+ len(self.args),
+ result,
+ code.error_goto(self.pos)))
+ for i in range(len(self.args)):
+ arg = self.args[i]
+ arg_result = arg.py_result()
+ #if not arg.is_temp:
+ if not arg.result_in_temp():
+ code.put_incref(arg_result)
+ code.putln("PyList_SET_ITEM(%s, %s, %s);" %
+ (result,
+ i,
+ arg_result))
+
+ def generate_subexpr_disposal_code(self, code):
+ # We call generate_post_assignment_code here instead
+ # of generate_disposal_code, because values were stored
+ # in the list using a reference-stealing operation.
+ for arg in self.args:
+ arg.generate_post_assignment_code(code)
+
+
+class DictNode(ExprNode):
+ # Dictionary constructor.
+ #
+ # key_value_pairs [(ExprNode, ExprNode)]
+
+ def compile_time_value(self, denv):
+ pairs = [(key.compile_time_value(denv), value.compile_time_value(denv))
+ for (key, value) in self.key_value_pairs]
+ try:
+ return dict(pairs)
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ def analyse_types(self, env):
+ new_pairs = []
+ for key, value in self.key_value_pairs:
+ key.analyse_types(env)
+ value.analyse_types(env)
+ key = key.coerce_to_pyobject(env)
+ value = value.coerce_to_pyobject(env)
+ new_pairs.append((key, value))
+ self.key_value_pairs = new_pairs
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ gil_message = "Constructing Python dict"
+
+ def allocate_temps(self, env, result = None):
+ # Custom method used here because key-value
+ # pairs are evaluated and used one at a time.
+ self.allocate_temp(env, result)
+ for key, value in self.key_value_pairs:
+ key.allocate_temps(env)
+ value.allocate_temps(env)
+ key.release_temp(env)
+ value.release_temp(env)
+
+ def generate_evaluation_code(self, code):
+ # Custom method used here because key-value
+ # pairs are evaluated and used one at a time.
+ result = self.result()
+ code.putln(
+ "%s = PyDict_New(); if (!%s) %s" % (
+ result,
+ result,
+ code.error_goto(self.pos)))
+ for key, value in self.key_value_pairs:
+ key.generate_evaluation_code(code)
+ value.generate_evaluation_code(code)
+ code.putln(
+ "if (PyDict_SetItem(%s, %s, %s) < 0) %s" % (
+ result,
+ key.py_result(),
+ value.py_result(),
+ code.error_goto(self.pos)))
+ key.generate_disposal_code(code)
+ value.generate_disposal_code(code)
+
+
+class ClassNode(ExprNode):
+ # Helper class used in the implementation of Python
+ # class definitions. Constructs a class object given
+ # a name, tuple of bases and class dictionary.
+ #
+ # name ExprNode Name of the class
+ # bases ExprNode Base class tuple
+ # dict ExprNode Class dict (not owned by this node)
+ # doc ExprNode or None Doc string
+ # module_name string Name of defining module
+
+ subexprs = ['name', 'bases', 'doc']
+
+ def analyse_types(self, env):
+ self.name.analyse_types(env)
+ self.name = self.name.coerce_to_pyobject(env)
+ self.bases.analyse_types(env)
+ if self.doc:
+ self.doc.analyse_types(env)
+ self.doc = self.doc.coerce_to_pyobject(env)
+ self.module_name = env.global_scope().qualified_name
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+# env.use_utility_code(create_class_utility_code)
+
+ gil_message = "Constructing Python class"
+
+ def generate_result_code(self, code):
+ result = self.result()
+ if self.doc:
+ code.putln(
+ 'if (PyDict_SetItemString(%s, "__doc__", %s) < 0) %s' % (
+ self.dict.py_result(),
+ self.doc.py_result(),
+ code.error_goto(self.pos)))
+ code.use_utility_code(create_class_utility_code)
+ code.putln(
+ '%s = __Pyx_CreateClass(%s, %s, %s, "%s"); if (!%s) %s' % (
+ result,
+ self.bases.py_result(),
+ self.dict.py_result(),
+ self.name.py_result(),
+ self.module_name,
+ result,
+ code.error_goto(self.pos)))
+
+
+class UnboundMethodNode(ExprNode):
+ # Helper class used in the implementation of Python
+ # class definitions. Constructs an unbound method
+ # object from a class and a function.
+ #
+ # class_cname string C var holding the class object
+ # function ExprNode Function object
+
+ subexprs = ['function']
+
+ def analyse_types(self, env):
+ self.function.analyse_types(env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+
+ gil_message = "Constructing an unbound method"
+
+ def generate_result_code(self, code):
+ result = self.result()
+ code.putln(
+ "%s = PyMethod_New(%s, 0, %s); if (!%s) %s" % (
+ result,
+ self.function.py_result(),
+ self.class_cname,
+ result,
+ code.error_goto(self.pos)))
+
+
+class PyCFunctionNode(AtomicExprNode):
+ # Helper class used in the implementation of Python
+ # class definitions. Constructs a PyCFunction object
+ # from a PyMethodDef struct.
+ #
+ # pymethdef_cname string PyMethodDef structure
+ # module_name string Name of defining module
+
+ def analyse_types(self, env):
+ self.type = py_object_type
+ self.module_name = env.global_scope().module_name
+ self.gil_check(env)
+ self.is_temp = 1
+
+ gil_message = "Constructing Python function"
+
+ def generate_result_code(self, code):
+ result = self.result()
+ code.putln(
+ "%s = PyCFunction_NewEx(&%s, 0, %s); if (!%s) %s" % (
+ result,
+ self.pymethdef_cname,
+ code.get_py_string_const(self.module_name),
+ result,
+ code.error_goto(self.pos)))
+
+#-------------------------------------------------------------------
+#
+# Unary operator nodes
+#
+#-------------------------------------------------------------------
+
+compile_time_unary_operators = {
+ 'not': operator.not_,
+ '~': operator.inv,
+ '-': operator.neg,
+ '+': operator.pos,
+}
+
+class UnopNode(ExprNode):
+ # operator string
+ # operand ExprNode
+ #
+ # Processing during analyse_expressions phase:
+ #
+ # analyse_c_operation
+ # Called when the operand is not a pyobject.
+ # - Check operand type and coerce if needed.
+ # - Determine result type and result code fragment.
+ # - Allocate temporary for result if needed.
+
+ subexprs = ['operand']
+
+ def compile_time_value(self, denv):
+ func = compile_time_unary_operators.get(self.operator)
+ if not func:
+ error(self.pos,
+ "Unary '%s' not supported in compile-time expression"
+ % self.operator)
+ operand = self.operand.compile_time_value(denv)
+ try:
+ return func(operand)
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ def analyse_types(self, env):
+ self.operand.analyse_types(env)
+ if self.is_py_operation():
+ self.coerce_operand_to_pyobject(env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+ else:
+ self.analyse_c_operation(env)
+
+ def check_const(self):
+ self.operand.check_const()
+
+ def is_py_operation(self):
+ return self.operand.type.is_pyobject
+
+ def coerce_operand_to_pyobject(self, env):
+ self.operand = self.operand.coerce_to_pyobject(env)
+
+ def generate_result_code(self, code):
+ if self.operand.type.is_pyobject:
+ self.generate_py_operation_code(code)
+ else:
+ if self.is_temp:
+ self.generate_c_operation_code(code)
+
+ def generate_py_operation_code(self, code):
+ function = self.py_operation_function()
+ result = self.result()
+ code.putln(
+ "%s = %s(%s); if (!%s) %s" % (
+ result,
+ function,
+ self.operand.py_result(),
+ result,
+ code.error_goto(self.pos)))
+
+ def type_error(self):
+ if not self.operand.type.is_error:
+ error(self.pos, "Invalid operand type for '%s' (%s)" %
+ (self.operator, self.operand.type))
+ self.type = PyrexTypes.error_type
+
+
+class NotNode(ExprNode):
+ # 'not' operator
+ #
+ # operand ExprNode
+
+ def compile_time_value(self, denv):
+ operand = self.operand.compile_time_value(denv)
+ try:
+ return not operand
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ subexprs = ['operand']
+
+ def analyse_types(self, env):
+ self.operand.analyse_types(env)
+ self.operand = self.operand.coerce_to_boolean(env)
+ self.type = PyrexTypes.c_int_type
+
+ def calculate_result_code(self):
+ return "(!%s)" % self.operand.result()
+
+ def generate_result_code(self, code):
+ pass
+
+
+class UnaryPlusNode(UnopNode):
+ # unary '+' operator
+
+ operator = '+'
+
+ def analyse_c_operation(self, env):
+ self.type = self.operand.type
+
+ def py_operation_function(self):
+ return "PyNumber_Positive"
+
+ def calculate_result_code(self):
+ return self.operand.result()
+
+
+class UnaryMinusNode(UnopNode):
+ # unary '-' operator
+
+ operator = '-'
+
+ def analyse_c_operation(self, env):
+ if self.operand.type.is_numeric:
+ self.type = self.operand.type
+ else:
+ self.type_error()
+
+ def py_operation_function(self):
+ return "PyNumber_Negative"
+
+ def calculate_result_code(self):
+ return "(-%s)" % self.operand.result()
+
+
+class TildeNode(UnopNode):
+ # unary '~' operator
+
+ def analyse_c_operation(self, env):
+ if self.operand.type.is_int:
+ self.type = self.operand.type
+ else:
+ self.type_error()
+
+ def py_operation_function(self):
+ return "PyNumber_Invert"
+
+ def calculate_result_code(self):
+ return "(~%s)" % self.operand.result()
+
+
+class AmpersandNode(ExprNode):
+ # The C address-of operator.
+ #
+ # operand ExprNode
+
+ subexprs = ['operand']
+
+ def analyse_types(self, env):
+ self.operand.analyse_types(env)
+ argtype = self.operand.type
+ if not (argtype.is_cfunction or self.operand.is_lvalue()):
+ self.error("Taking address of non-lvalue")
+ return
+ if argtype.is_pyobject:
+ self.error("Cannot take address of Python variable")
+ return
+ self.type = PyrexTypes.c_ptr_type(argtype)
+
+ def check_const(self):
+ self.operand.check_const_addr()
+
+ def error(self, mess):
+ error(self.pos, mess)
+ self.type = PyrexTypes.error_type
+ self.result_code = "<error>"
+
+ def calculate_result_code(self):
+ return "(&%s)" % self.operand.result()
+
+ def generate_result_code(self, code):
+ pass
+
+
+unop_node_classes = {
+ "+": UnaryPlusNode,
+ "-": UnaryMinusNode,
+ "~": TildeNode,
+}
+
+def unop_node(pos, operator, operand):
+ # Construct unnop node of appropriate class for
+ # given operator.
+ return unop_node_classes[operator](pos,
+ operator = operator,
+ operand = operand)
+
+
+class TypecastNode(ExprNode):
+ # C type cast
+ #
+ # base_type CBaseTypeNode
+ # declarator CDeclaratorNode
+ # operand ExprNode
+
+ subexprs = ['operand']
+
+ def analyse_types(self, env):
+ base_type = self.base_type.analyse(env)
+ _, self.type = self.declarator.analyse(base_type, env)
+ if self.type.is_cfunction:
+ error(self.pos,
+ "Cannot cast to a function type")
+ self.type = PyrexTypes.error_type
+ self.operand.analyse_types(env)
+ to_py = self.type.is_pyobject
+ from_py = self.operand.type.is_pyobject
+ if from_py and not to_py and self.operand.is_ephemeral():
+ error(self.pos, "Casting temporary Python object to non-Python type")
+ # Must do the following, so that the result can be increfed without
+ # the operand getting evaluated twice.
+ if to_py and not from_py:
+ #self.result_ctype = py_object_type
+ #self.is_temp = 1
+ self.operand = self.operand.coerce_to_simple(env)
+
+ def check_const(self):
+ self.operand.check_const()
+
+ def calculate_result_code(self):
+ opnd = self.operand
+ result_code = self.type.cast_code(opnd.result())
+ return result_code
+
+ def result_as(self, type):
+ if not self.is_temp and type.is_pyobject and self.type.is_pyobject:
+ # Optimise away some unnecessary casting
+ return self.operand.result_as(type)
+ else:
+ return ExprNode.result_as(self, type)
+
+ def generate_result_code(self, code):
+ if self.is_temp:
+ code.putln(
+ "%s = %s;" % (
+ self.result(),
+ self.operand.py_result()))
+ code.put_incref(self.py_result())
+
+
+class SizeofNode(ExprNode):
+ # Base class for sizeof(x) expression nodes.
+ #
+ # sizeof_code string
+
+ subexprs = []
+
+ def check_const(self):
+ pass
+
+ def analyse_types(self, env):
+ self.analyse_argument(env)
+ self.type = PyrexTypes.c_size_t_type
+
+ def analyse_type_argument(self, arg_type):
+ if arg_type.is_pyobject:
+ error(self.pos, "Cannot take sizeof Python object")
+ elif arg_type.is_void:
+ error(self.pos, "Cannot take sizeof void")
+ elif not arg_type.is_complete():
+ error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type)
+ arg_code = arg_type.declaration_code("")
+ self.sizeof_code = "(sizeof(%s))" % arg_code
+
+ def calculate_result_code(self):
+ return self.sizeof_code
+
+ def generate_result_code(self, code):
+ pass
+
+
+class SizeofTypeNode(SizeofNode):
+ # C sizeof function applied to a type
+ #
+ # base_type CBaseTypeNode
+ # declarator CDeclaratorNode
+
+ def analyse_argument(self, env):
+ base_type = self.base_type.analyse(env)
+ _, arg_type = self.declarator.analyse(base_type, env)
+ self.analyse_type_argument(arg_type)
+
+
+class SizeofVarNode(SizeofNode):
+ # C sizeof function applied to a variable or qualified name
+ # (which may actually refer to a type)
+ #
+ # operand ExprNode
+
+ #subexprs = ['operand']
+
+ def analyse_argument(self, env):
+ is_type = 0
+ operand = self.operand
+ if operand.analyse_as_cimported_attribute(env, allow_type = 1):
+ if operand.entry.is_type:
+ is_type = 1
+ self.analyse_type_argument(operand.entry.type)
+ else:
+ self.operand.analyse_types(env)
+ self.operand.mark_vars_used()
+ if not is_type:
+ self.sizeof_code = "(sizeof(%s))" % operand.result()
+
+
+#-------------------------------------------------------------------
+#
+# Binary operator nodes
+#
+#-------------------------------------------------------------------
+
+compile_time_binary_operators = {
+ '<': operator.lt,
+ '<=': operator.le,
+ '==': operator.eq,
+ '!=': operator.ne,
+ '>=': operator.ge,
+ '>': operator.gt,
+ 'is': operator.is_,
+ 'is_not': operator.is_not,
+ '+': operator.add,
+ '&': operator.and_,
+ '/': operator.div,
+ '//': operator.floordiv,
+ '<<': operator.lshift,
+ '%': operator.mod,
+ '*': operator.mul,
+ '|': operator.or_,
+ '**': operator.pow,
+ '>>': operator.rshift,
+ '-': operator.sub,
+ #'/': operator.truediv,
+ '^': operator.xor,
+ 'in': lambda x, y: x in y,
+ 'not_in': lambda x, y: x not in y,
+}
+
+def get_compile_time_binop(node):
+ func = compile_time_binary_operators.get(node.operator)
+ if not func:
+ error(node.pos,
+ "Binary '%s' not supported in compile-time expression"
+ % node.operator)
+ return func
+
+class BinopNode(ExprNode):
+ # operator string
+ # operand1 ExprNode
+ # operand2 ExprNode
+ #
+ # Processing during analyse_expressions phase:
+ #
+ # analyse_c_operation
+ # Called when neither operand is a pyobject.
+ # - Check operand types and coerce if needed.
+ # - Determine result type and result code fragment.
+ # - Allocate temporary for result if needed.
+
+ subexprs = ['operand1', 'operand2']
+
+ def compile_time_value(self, denv):
+ func = get_compile_time_binop(self)
+ operand1 = self.operand1.compile_time_value(denv)
+ operand2 = self.operand2.compile_time_value(denv)
+ try:
+ return func(operand1, operand2)
+ except Exception, e:
+ self.compile_time_value_error(e)
+
+ def analyse_types(self, env):
+ self.operand1.analyse_types(env)
+ self.operand2.analyse_types(env)
+ if self.is_py_operation():
+ self.coerce_operands_to_pyobjects(env)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+ else:
+ self.analyse_c_operation(env)
+
+ def is_py_operation(self):
+ return (self.operand1.type.is_pyobject
+ or self.operand2.type.is_pyobject)
+
+ def coerce_operands_to_pyobjects(self, env):
+ self.operand1 = self.operand1.coerce_to_pyobject(env)
+ self.operand2 = self.operand2.coerce_to_pyobject(env)
+
+ def check_const(self):
+ self.operand1.check_const()
+ self.operand2.check_const()
+
+ def generate_result_code(self, code):
+ #print "BinopNode.generate_result_code:", self.operand1, self.operand2 ###
+ if self.operand1.type.is_pyobject:
+ function = self.py_operation_function()
+ if function == "PyNumber_Power":
+ extra_args = ", Py_None"
+ else:
+ extra_args = ""
+ result = self.result()
+ code.putln(
+ "%s = %s(%s, %s%s); if (!%s) %s" % (
+ result,
+ function,
+ self.operand1.py_result(),
+ self.operand2.py_result(),
+ extra_args,
+ result,
+ code.error_goto(self.pos)))
+ else:
+ if self.is_temp:
+ self.generate_c_operation_code(code)
+
+ def type_error(self):
+ if not (self.operand1.type.is_error
+ or self.operand2.type.is_error):
+ error(self.pos, "Invalid operand types for '%s' (%s; %s)" %
+ (self.operator, self.operand1.type,
+ self.operand2.type))
+ self.type = PyrexTypes.error_type
+
+
+class NumBinopNode(BinopNode):
+ # Binary operation taking numeric arguments.
+
+ def analyse_c_operation(self, env):
+ type1 = self.operand1.type
+ type2 = self.operand2.type
+ if self.operator == "**" and type1.is_int and type2.is_int:
+ error(self.pos, "** with two C int types is ambiguous")
+ self.type = error_type
+ return
+ self.type = self.compute_c_result_type(type1, type2)
+ if not self.type:
+ self.type_error()
+
+ def compute_c_result_type(self, type1, type2):
+ if self.c_types_okay(type1, type2):
+ return PyrexTypes.widest_numeric_type(type1, type2)
+ else:
+ return None
+
+ def c_types_okay(self, type1, type2):
+ #print "NumBinopNode.c_types_okay:", type1, type2 ###
+ return (type1.is_numeric or type1.is_enum) \
+ and (type2.is_numeric or type2.is_enum)
+
+ def calculate_result_code(self):
+ return "(%s %s %s)" % (
+ self.operand1.result(),
+ self.operator,
+ self.operand2.result())
+
+ def py_operation_function(self):
+ return self.py_functions[self.operator]
+
+ py_functions = {
+ "|": "PyNumber_Or",
+ "^": "PyNumber_Xor",
+ "&": "PyNumber_And",
+ "<<": "PyNumber_Lshift",
+ ">>": "PyNumber_Rshift",
+ "+": "PyNumber_Add",
+ "-": "PyNumber_Subtract",
+ "*": "PyNumber_Multiply",
+ "/": "PyNumber_Divide",
+ "%": "PyNumber_Remainder",
+ "**": "PyNumber_Power"
+ }
+
+
+class IntBinopNode(NumBinopNode):
+ # Binary operation taking integer arguments.
+
+ def c_types_okay(self, type1, type2):
+ #print "IntBinopNode.c_types_okay:", type1, type2 ###
+ return (type1.is_int or type1.is_enum) \
+ and (type2.is_int or type2.is_enum)
+
+
+class AddNode(NumBinopNode):
+ # '+' operator.
+
+ def is_py_operation(self):
+ if self.operand1.type.is_string \
+ and self.operand2.type.is_string:
+ return 1
+ else:
+ return NumBinopNode.is_py_operation(self)
+
+ def compute_c_result_type(self, type1, type2):
+ #print "AddNode.compute_c_result_type:", type1, self.operator, type2 ###
+ if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
+ return type1
+ elif (type2.is_ptr or type2.is_array) and (type1.is_int or type1.is_enum):
+ return type2
+ else:
+ return NumBinopNode.compute_c_result_type(
+ self, type1, type2)
+
+
+class SubNode(NumBinopNode):
+ # '-' operator.
+
+ def compute_c_result_type(self, type1, type2):
+ if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
+ return type1
+ elif (type1.is_ptr or type1.is_array) and (type2.is_ptr or type2.is_array):
+ return PyrexTypes.c_int_type
+ else:
+ return NumBinopNode.compute_c_result_type(
+ self, type1, type2)
+
+
+class MulNode(NumBinopNode):
+ # '*' operator.
+
+ def is_py_operation(self):
+ type1 = self.operand1.type
+ type2 = self.operand2.type
+ if (type1.is_string and type2.is_int) \
+ or (type2.is_string and type1.is_int):
+ return 1
+ else:
+ return NumBinopNode.is_py_operation(self)
+
+
+class ModNode(IntBinopNode):
+ # '%' operator.
+
+ def is_py_operation(self):
+ return (self.operand1.type.is_string
+ or self.operand2.type.is_string
+ or IntBinopNode.is_py_operation(self))
+
+
+class PowNode(NumBinopNode):
+ # '**' operator.
+
+ def analyse_types(self, env):
+ env.pow_function_used = 1
+ NumBinopNode.analyse_types(self, env)
+
+ def compute_c_result_type(self, type1, type2):
+ if self.c_types_okay(type1, type2):
+ return PyrexTypes.c_double_type
+ else:
+ return None
+
+ def calculate_result_code(self):
+ return "pow(%s, %s)" % (
+ self.operand1.result(), self.operand2.result())
+
+
+class BoolBinopNode(ExprNode):
+ # Short-circuiting boolean operation.
+ #
+ # operator string
+ # operand1 ExprNode
+ # operand2 ExprNode
+ # temp_bool ExprNode used internally
+
+ temp_bool = None
+
+ subexprs = ['operand1', 'operand2', 'temp_bool']
+
+ def compile_time_value(self, denv):
+ if self.operator == 'and':
+ return self.operand1.compile_time_value(denv) \
+ and self.operand2.compile_time_value(denv)
+ else:
+ return self.operand1.compile_time_value(denv) \
+ or self.operand2.compile_time_value(denv)
+
+ def analyse_types(self, env):
+ self.operand1.analyse_types(env)
+ self.operand2.analyse_types(env)
+ if self.operand1.type.is_pyobject or \
+ self.operand2.type.is_pyobject:
+ self.operand1 = self.operand1.coerce_to_pyobject(env)
+ self.operand2 = self.operand2.coerce_to_pyobject(env)
+ self.temp_bool = TempNode(self.pos,
+ PyrexTypes.c_int_type, env)
+ self.type = py_object_type
+ self.gil_check(env)
+ else:
+ self.operand1 = self.operand1.coerce_to_boolean(env)
+ self.operand2 = self.operand2.coerce_to_boolean(env)
+ self.type = PyrexTypes.c_int_type
+ # For what we're about to do, it's vital that
+ # both operands be temp nodes.
+ self.operand1 = self.operand1.coerce_to_temp(env) #CTT
+ self.operand2 = self.operand2.coerce_to_temp(env)
+ self.is_temp = 1
+
+ gil_message = "Truth-testing Python object"
+
+ def allocate_temps(self, env, result_code = None):
+ # We don't need both operands at the same time, and
+ # one of the operands will also be our result. So we
+ # use an allocation strategy here which results in
+ # this node and both its operands sharing the same
+ # result variable. This allows us to avoid some
+ # assignments and increfs/decrefs that would otherwise
+ # be necessary.
+ self.allocate_temp(env, result_code)
+ self.operand1.allocate_temps(env, self.result_code)
+ if self.temp_bool:
+ self.temp_bool.allocate_temp(env)
+ self.temp_bool.release_temp(env)
+ self.operand2.allocate_temps(env, self.result_code)
+ # We haven't called release_temp on either operand,
+ # because although they are temp nodes, they don't own
+ # their result variable. And because they are temp
+ # nodes, any temps in their subnodes will have been
+ # released before their allocate_temps returned.
+ # Therefore, they contain no temp vars that need to
+ # be released.
+
+ def check_const(self):
+ self.operand1.check_const()
+ self.operand2.check_const()
+
+ def calculate_result_code(self):
+ return "(%s %s %s)" % (
+ self.operand1.result(),
+ self.py_to_c_op[self.operator],
+ self.operand2.result())
+
+ py_to_c_op = {'and': "&&", 'or': "||"}
+
+ def generate_evaluation_code(self, code):
+ self.operand1.generate_evaluation_code(code)
+ test_result = self.generate_operand1_test(code)
+ if self.operator == 'and':
+ sense = ""
+ else:
+ sense = "!"
+ code.putln(
+ "if (%s%s) {" % (
+ sense,
+ test_result))
+ self.operand1.generate_disposal_code(code)
+ self.operand2.generate_evaluation_code(code)
+ code.putln(
+ "}")
+
+ def generate_operand1_test(self, code):
+ # Generate code to test the truth of the first operand.
+ if self.type.is_pyobject:
+ test_result = self.temp_bool.result()
+ code.putln(
+ "%s = PyObject_IsTrue(%s); if (%s < 0) %s" % (
+ test_result,
+ self.operand1.py_result(),
+ test_result,
+ code.error_goto(self.pos)))
+ else:
+ test_result = self.operand1.result()
+ return test_result
+
+
+class CmpNode:
+ # Mixin class containing code common to PrimaryCmpNodes
+ # and CascadedCmpNodes.
+
+ def cascaded_compile_time_value(self, operand1, denv):
+ func = get_compile_time_binop(self)
+ operand2 = self.operand2.compile_time_value(denv)
+ try:
+ result = func(operand1, operand2)
+ except Exception, e:
+ self.compile_time_value_error(e)
+ result = None
+ if result:
+ cascade = self.cascade
+ if cascade:
+ result = result and cascade.compile_time_value(operand2, denv)
+ return result
+
+ def is_python_comparison(self):
+ return (self.has_python_operands()
+ or (self.cascade and self.cascade.is_python_comparison())
+ or self.operator in ('in', 'not_in'))
+
+ def check_types(self, env, operand1, op, operand2):
+ if not self.types_okay(operand1, op, operand2):
+ error(self.pos, "Invalid types for '%s' (%s, %s)" %
+ (self.operator, operand1.type, operand2.type))
+
+ def types_okay(self, operand1, op, operand2):
+ type1 = operand1.type
+ type2 = operand2.type
+ if type1.is_error or type2.is_error:
+ return 1
+ if type1.is_pyobject: # type2 will be, too
+ return 1
+ elif type1.is_ptr or type1.is_array:
+ return type1.is_null_ptr or type2.is_null_ptr \
+ or ((type2.is_ptr or type2.is_array)
+ and type1.base_type.same_as(type2.base_type))
+ elif ((type1.is_numeric and type2.is_numeric
+ or type1.is_enum and (type2.is_int or type1.same_as(type2))
+ or type1.is_int and type2.is_enum)
+ and op not in ('is', 'is_not')):
+ return 1
+ else:
+ return 0
+
+ def generate_operation_code(self, code, result,
+ operand1, op , operand2):
+ if op == 'in' or op == 'not_in':
+ code.putln(
+ "%s = PySequence_Contains(%s, %s); if (%s < 0) %s" % (
+ result,
+ operand2.py_result(),
+ operand1.py_result(),
+ result,
+ code.error_goto(self.pos)))
+ if op == 'not_in':
+ code.putln(
+ "%s = !%s;" % (
+ result, result))
+ elif (operand1.type.is_pyobject
+ and op not in ('is', 'is_not')):
+ code.putln(
+ "if (PyObject_Cmp(%s, %s, &%s) < 0) %s" % (
+ operand1.py_result(),
+ operand2.py_result(),
+ result,
+ code.error_goto(self.pos)))
+ code.putln(
+ "%s = %s %s 0;" % (
+ result, result, op))
+ else:
+ type1 = operand1.type
+ type2 = operand2.type
+ if (type1.is_extension_type or type2.is_extension_type) \
+ and not operand1.ctype().same_as(operand2.ctype()):
+ code1 = operand1.result_as(py_object_type)
+ code2 = operand2.result_as(py_object_type)
+ else:
+ code1 = operand1.result()
+ code2 = operand2.result()
+ code.putln("%s = %s %s %s;" % (
+ result,
+ code1,
+ self.c_operator(op),
+ code2))
+
+ def c_operator(self, op):
+ if op == 'is':
+ return "=="
+ elif op == 'is_not':
+ return "!="
+ else:
+ return op
+
+
+class PrimaryCmpNode(ExprNode, CmpNode):
+ # Non-cascaded comparison or first comparison of
+ # a cascaded sequence.
+ #
+ # operator string
+ # operand1 ExprNode
+ # operand2 ExprNode
+ # cascade CascadedCmpNode
+
+ # We don't use the subexprs mechanism, because
+ # things here are too complicated for it to handle.
+ # Instead, we override all the framework methods
+ # which use it.
+
+ cascade = None
+
+ def compile_time_value(self, denv):
+ operand1 = self.operand1.compile_time_value(denv)
+ return self.cascaded_compile_time_value(operand1, denv)
+
+ def analyse_types(self, env):
+ self.operand1.analyse_types(env)
+ self.operand2.analyse_types(env)
+ if self.cascade:
+ self.cascade.analyse_types(env, self.operand2)
+ self.is_pycmp = self.is_python_comparison()
+ if self.is_pycmp:
+ self.coerce_operands_to_pyobjects(env)
+ if self.cascade:
+ self.operand2 = self.operand2.coerce_to_simple(env)
+ self.cascade.coerce_cascaded_operands_to_temp(env)
+ self.check_operand_types(env)
+ self.type = PyrexTypes.c_int_type
+ if self.is_pycmp or self.cascade:
+ self.is_temp = 1
+
+ def check_operand_types(self, env):
+ self.check_types(env,
+ self.operand1, self.operator, self.operand2)
+ if self.cascade:
+ self.cascade.check_operand_types(env, self.operand2)
+
+ def has_python_operands(self):
+ return (self.operand1.type.is_pyobject
+ or self.operand2.type.is_pyobject)
+
+ def coerce_operands_to_pyobjects(self, env):
+ self.operand1 = self.operand1.coerce_to_pyobject(env)
+ self.operand2 = self.operand2.coerce_to_pyobject(env)
+ if self.cascade:
+ self.cascade.coerce_operands_to_pyobjects(env)
+
+ def allocate_subexpr_temps(self, env):
+ self.operand1.allocate_temps(env)
+ self.operand2.allocate_temps(env)
+ if self.cascade:
+ self.cascade.allocate_subexpr_temps(env)
+
+ def release_subexpr_temps(self, env):
+ self.operand1.release_temp(env)
+ self.operand2.release_temp(env)
+ if self.cascade:
+ self.cascade.release_subexpr_temps(env)
+
+ def check_const(self):
+ self.operand1.check_const()
+ self.operand2.check_const()
+ if self.cascade:
+ self.not_const()
+
+ def calculate_result_code(self):
+ return "(%s %s %s)" % (
+ self.operand1.result(),
+ self.c_operator(self.operator),
+ self.operand2.result())
+
+ def generate_evaluation_code(self, code):
+ self.operand1.generate_evaluation_code(code)
+ self.operand2.generate_evaluation_code(code)
+ if self.is_temp:
+ result = self.result()
+ self.generate_operation_code(code, result,
+ self.operand1, self.operator, self.operand2)
+ if self.cascade:
+ self.cascade.generate_evaluation_code(code,
+ result, self.operand2)
+ self.operand1.generate_disposal_code(code)
+ self.operand2.generate_disposal_code(code)
+
+ def generate_subexpr_disposal_code(self, code):
+ # If this is called, it is a non-cascaded cmp,
+ # so only need to dispose of the two main operands.
+ self.operand1.generate_disposal_code(code)
+ self.operand2.generate_disposal_code(code)
+
+
+class CascadedCmpNode(Node, CmpNode):
+ # A CascadedCmpNode is not a complete expression node. It
+ # hangs off the side of another comparison node, shares
+ # its left operand with that node, and shares its result
+ # with the PrimaryCmpNode at the head of the chain.
+ #
+ # operator string
+ # operand2 ExprNode
+ # cascade CascadedCmpNode
+
+ cascade = None
+
+ def analyse_types(self, env, operand1):
+ self.operand2.analyse_types(env)
+ if self.cascade:
+ self.cascade.analyse_types(env, self.operand2)
+
+ def check_operand_types(self, env, operand1):
+ self.check_types(env,
+ operand1, self.operator, self.operand2)
+ if self.cascade:
+ self.cascade.check_operand_types(env, self.operand2)
+
+ def has_python_operands(self):
+ return self.operand2.type.is_pyobject
+
+ def coerce_operands_to_pyobjects(self, env):
+ self.operand2 = self.operand2.coerce_to_pyobject(env)
+ if self.cascade:
+ self.cascade.coerce_operands_to_pyobjects(env)
+
+ def coerce_cascaded_operands_to_temp(self, env):
+ if self.cascade:
+ #self.operand2 = self.operand2.coerce_to_temp(env) #CTT
+ self.operand2 = self.operand2.coerce_to_simple(env)
+ self.cascade.coerce_cascaded_operands_to_temp(env)
+
+ def allocate_subexpr_temps(self, env):
+ self.operand2.allocate_temps(env)
+ if self.cascade:
+ self.cascade.allocate_subexpr_temps(env)
+
+ def release_subexpr_temps(self, env):
+ self.operand2.release_temp(env)
+ if self.cascade:
+ self.cascade.release_subexpr_temps(env)
+
+ def generate_evaluation_code(self, code, result, operand1):
+ code.putln("if (%s) {" % result)
+ self.operand2.generate_evaluation_code(code)
+ self.generate_operation_code(code, result,
+ operand1, self.operator, self.operand2)
+ if self.cascade:
+ self.cascade.generate_evaluation_code(
+ code, result, self.operand2)
+ # Cascaded cmp result is always temp
+ self.operand2.generate_disposal_code(code)
+ code.putln("}")
+
+
+binop_node_classes = {
+ "or": BoolBinopNode,
+ "and": BoolBinopNode,
+ "|": IntBinopNode,
+ "^": IntBinopNode,
+ "&": IntBinopNode,
+ "<<": IntBinopNode,
+ ">>": IntBinopNode,
+ "+": AddNode,
+ "-": SubNode,
+ "*": MulNode,
+ "/": NumBinopNode,
+ "%": ModNode,
+ "**": PowNode
+}
+
+def binop_node(pos, operator, operand1, operand2):
+ # Construct binop node of appropriate class for
+ # given operator.
+ return binop_node_classes[operator](pos,
+ operator = operator,
+ operand1 = operand1,
+ operand2 = operand2)
+
+#-------------------------------------------------------------------
+#
+# Coercion nodes
+#
+# Coercion nodes are special in that they are created during
+# the analyse_types phase of parse tree processing.
+# Their __init__ methods consequently incorporate some aspects
+# of that phase.
+#
+#-------------------------------------------------------------------
+
+class CoercionNode(ExprNode):
+ # Abstract base class for coercion nodes.
+ #
+ # arg ExprNode node being coerced
+
+ subexprs = ['arg']
+
+ def __init__(self, arg):
+ self.pos = arg.pos
+ self.arg = arg
+ if debug_coercion:
+ print self, "Coercing", self.arg
+
+
+class CastNode(CoercionNode):
+ # Wrap a node in a C type cast.
+
+ def __init__(self, arg, new_type):
+ CoercionNode.__init__(self, arg)
+ self.type = new_type
+
+ def calculate_result_code(self):
+ return self.arg.result_as(self.type)
+
+ def generate_result_code(self, code):
+ self.arg.generate_result_code(code)
+
+
+class PyTypeTestNode(CoercionNode):
+ # This node is used to check that a generic Python
+ # object is an instance of a particular extension type.
+ # This node borrows the result of its argument node.
+
+ def __init__(self, arg, dst_type, env):
+ # The arg is know to be a Python object, and
+ # the dst_type is known to be an extension type.
+ assert dst_type.is_extension_type, "PyTypeTest on non extension type"
+ CoercionNode.__init__(self, arg)
+ self.type = dst_type
+ self.result_ctype = arg.ctype()
+# env.use_utility_code(type_test_utility_code)
+ self.gil_check(env)
+
+ gil_message = "Python type test"
+
+ def result_in_temp(self):
+ return self.arg.result_in_temp()
+
+ def is_ephemeral(self):
+ return self.arg.is_ephemeral()
+
+ def calculate_result_code(self):
+ return self.arg.result()
+
+ def generate_result_code(self, code):
+ if self.type.typeobj_is_available():
+ code.use_utility_code(type_test_utility_code)
+ code.putln(
+ "if (!__Pyx_TypeTest(%s, %s)) %s" % (
+ self.arg.py_result(),
+ self.type.typeptr_cname,
+ code.error_goto(self.pos)))
+ else:
+ error(self.pos, "Cannot test type of extern C class "
+ "without type object name specification")
+
+ def generate_post_assignment_code(self, code):
+ self.arg.generate_post_assignment_code(code)
+
+
+class CoerceToPyTypeNode(CoercionNode):
+ # This node is used to convert a C data type
+ # to a Python object.
+
+ def __init__(self, arg, env):
+ CoercionNode.__init__(self, arg)
+ self.type = py_object_type
+ self.gil_check(env)
+ self.is_temp = 1
+ if not arg.type.to_py_function:
+ error(arg.pos,
+ "Cannot convert '%s' to Python object" % arg.type)
+
+ gil_message = "Converting to Python object"
+
+ def generate_result_code(self, code):
+ function = self.arg.type.to_py_function
+ result = self.result()
+ code.putln('%s = %s(%s); if (!%s) %s' % (
+ result,
+ function,
+ self.arg.result(),
+ result,
+ code.error_goto(self.pos)))
+
+
+class CoerceFromPyTypeNode(CoercionNode):
+ # This node is used to convert a Python object
+ # to a C data type.
+
+ def __init__(self, result_type, arg, env):
+ CoercionNode.__init__(self, arg)
+ self.type = result_type
+ self.is_temp = 1
+ if not result_type.from_py_function:
+ error(arg.pos,
+ "Cannot convert Python object to '%s'" % result_type)
+ if self.type.is_string and self.arg.is_ephemeral():
+ error(arg.pos,
+ "Obtaining char * from temporary Python value")
+
+ def generate_result_code(self, code):
+ function = self.type.from_py_function
+ operand = self.arg.py_result()
+ rhs = "%s(%s)" % (function, operand)
+ if self.type.is_enum:
+ rhs = typecast(self.type, c_long_type, rhs)
+ result = self.result()
+ if self.type.is_string:
+ err_code = "!%s" % result
+ else:
+ err_code = "PyErr_Occurred()"
+ code.putln('%s = %s; if (%s) %s' % (
+ result,
+ rhs,
+ err_code,
+ code.error_goto(self.pos)))
+
+
+class CoerceToBooleanNode(CoercionNode):
+ # This node is used when a result needs to be used
+ # in a boolean context.
+
+ def __init__(self, arg, env):
+ CoercionNode.__init__(self, arg)
+ self.type = PyrexTypes.c_int_type
+ if arg.type.is_pyobject:
+ if env.nogil:
+ self.gil_error()
+ self.is_temp = 1
+
+ gil_message = "Truth-testing Python object"
+
+ def check_const(self):
+ if self.is_temp:
+ self.not_const()
+ self.arg.check_const()
+
+ def calculate_result_code(self):
+ return "(%s != 0)" % self.arg.result()
+
+ def generate_result_code(self, code):
+ if self.arg.type.is_pyobject:
+ result = self.result()
+ code.putln(
+ "%s = PyObject_IsTrue(%s); if (%s < 0) %s" % (
+ result,
+ self.arg.py_result(),
+ result,
+ code.error_goto(self.pos)))
+
+
+class CoerceToTempNode(CoercionNode):
+ # This node is used to force the result of another node
+ # to be stored in a temporary. It is only used if the
+ # argument node's result is not already in a temporary.
+
+ def __init__(self, arg, env):
+ CoercionNode.__init__(self, arg)
+ self.type = self.arg.type
+ self.is_temp = 1
+ if self.type.is_pyobject:
+ self.gil_check(env)
+ self.result_ctype = py_object_type
+
+ gil_message = "Creating temporary Python reference"
+
+
+ def generate_result_code(self, code):
+ #self.arg.generate_evaluation_code(code) # Already done
+ # by generic generate_subexpr_evaluation_code!
+ code.putln("%s = %s;" % (
+ self.result(), self.arg.result_as(self.ctype())))
+ if self.type.is_pyobject:
+ code.put_incref(self.py_result())
+
+
+class CloneNode(CoercionNode):
+ # This node is employed when the result of another node needs
+ # to be used multiple times. The argument node's result must
+ # be in a temporary. This node "borrows" the result from the
+ # argument node, and does not generate any evaluation or
+ # disposal code for it. The original owner of the argument
+ # node is responsible for doing those things.
+
+ subexprs = [] # Arg is not considered a subexpr
+
+ def __init__(self, arg):
+ CoercionNode.__init__(self, arg)
+ self.type = arg.type
+ self.result_ctype = arg.result_ctype
+
+ def calculate_result_code(self):
+ return self.arg.result()
+
+ def generate_evaluation_code(self, code):
+ pass
+
+ def generate_result_code(self, code):
+ pass
+
+#------------------------------------------------------------------------------------
+#
+# Runtime support code
+#
+#------------------------------------------------------------------------------------
+
+get_name_utility_code = [
+"""
+static PyObject *__Pyx_GetName(PyObject *dict, char *name); /*proto*/
+""","""
+static PyObject *__Pyx_GetName(PyObject *dict, char *name) {
+ PyObject *result;
+ result = PyObject_GetAttrString(dict, name);
+ if (!result)
+ PyErr_SetString(PyExc_NameError, name);
+ return result;
+}
+"""]
+
+get_name_interned_utility_code = [
+"""
+static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/
+""","""
+static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
+ PyObject *result;
+ result = PyObject_GetAttr(dict, name);
+ if (!result)
+ PyErr_SetObject(PyExc_NameError, name);
+ return result;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+import_utility_code = [
+"""
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
+""","""
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
+ PyObject *__import__ = 0;
+ PyObject *empty_list = 0;
+ PyObject *module = 0;
+ PyObject *global_dict = 0;
+ PyObject *empty_dict = 0;
+ PyObject *list;
+ __import__ = PyObject_GetAttrString(%(BUILTINS)s, "__import__");
+ if (!__import__)
+ goto bad;
+ if (from_list)
+ list = from_list;
+ else {
+ empty_list = PyList_New(0);
+ if (!empty_list)
+ goto bad;
+ list = empty_list;
+ }
+ global_dict = PyModule_GetDict(%(GLOBALS)s);
+ if (!global_dict)
+ goto bad;
+ empty_dict = PyDict_New();
+ if (!empty_dict)
+ goto bad;
+ module = PyObject_CallFunction(__import__, "OOOO",
+ name, global_dict, empty_dict, list);
+bad:
+ Py_XDECREF(empty_list);
+ Py_XDECREF(__import__);
+ Py_XDECREF(empty_dict);
+ return module;
+}
+""" % {
+ "BUILTINS": Naming.builtins_cname,
+ "GLOBALS": Naming.module_cname,
+}]
+
+#------------------------------------------------------------------------------------
+#
+#get_exception_utility_code = [
+#"""
+#static PyObject *__Pyx_GetExcValue(void); /*proto*/
+#""","""
+#static PyObject *__Pyx_GetExcValue(void) {
+# PyObject *type = 0, *value = 0, *tb = 0;
+# PyObject *result = 0;
+# PyThreadState *tstate = PyThreadState_Get();
+# PyErr_Fetch(&type, &value, &tb);
+# PyErr_NormalizeException(&type, &value, &tb);
+# if (PyErr_Occurred())
+# goto bad;
+# if (!value) {
+# value = Py_None;
+# Py_INCREF(value);
+# }
+# Py_XDECREF(tstate->exc_type);
+# Py_XDECREF(tstate->exc_value);
+# Py_XDECREF(tstate->exc_traceback);
+# tstate->exc_type = type;
+# tstate->exc_value = value;
+# tstate->exc_traceback = tb;
+# result = value;
+# Py_XINCREF(result);
+# type = 0;
+# value = 0;
+# tb = 0;
+#bad:
+# Py_XDECREF(type);
+# Py_XDECREF(value);
+# Py_XDECREF(tb);
+# return result;
+#}
+#"""]
+#
+#------------------------------------------------------------------------------------
+
+unpacking_utility_code = [
+"""
+static PyObject *__Pyx_UnpackItem(PyObject *); /*proto*/
+static int __Pyx_EndUnpack(PyObject *); /*proto*/
+""","""
+static void __Pyx_UnpackError(void) {
+ PyErr_SetString(PyExc_ValueError, "unpack sequence of wrong size");
+}
+
+static PyObject *__Pyx_UnpackItem(PyObject *iter) {
+ PyObject *item;
+ if (!(item = PyIter_Next(iter))) {
+ if (!PyErr_Occurred())
+ __Pyx_UnpackError();
+ }
+ return item;
+}
+
+static int __Pyx_EndUnpack(PyObject *iter) {
+ PyObject *item;
+ if ((item = PyIter_Next(iter))) {
+ Py_DECREF(item);
+ __Pyx_UnpackError();
+ return -1;
+ }
+ else if (!PyErr_Occurred())
+ return 0;
+ else
+ return -1;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+type_test_utility_code = [
+"""
+static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/
+""","""
+static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
+ if (!type) {
+ PyErr_Format(PyExc_SystemError, "Missing type object");
+ return 0;
+ }
+ if (obj == Py_None || PyObject_TypeCheck(obj, type))
+ return 1;
+ PyErr_Format(PyExc_TypeError, "Cannot convert %s to %s",
+ obj->ob_type->tp_name, type->tp_name);
+ return 0;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+create_class_utility_code = [
+"""
+static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/
+""","""
+static PyObject *__Pyx_CreateClass(
+ PyObject *bases, PyObject *dict, PyObject *name, char *modname)
+{
+ PyObject *py_modname;
+ PyObject *result = 0;
+
+ py_modname = PyString_FromString(modname);
+ if (!py_modname)
+ goto bad;
+ if (PyDict_SetItemString(dict, "__module__", py_modname) < 0)
+ goto bad;
+ result = PyClass_New(bases, dict, name);
+bad:
+ Py_XDECREF(py_modname);
+ return result;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+getitem_int_utility_code = [
+"""
+static PyObject *__Pyx_GetItemInt(PyObject *o, Py_ssize_t i); /*proto*/
+""","""
+static PyObject *__Pyx_GetItemInt(PyObject *o, Py_ssize_t i) {
+ PyTypeObject *t = o->ob_type;
+ PyObject *r;
+ if (t->tp_as_sequence && t->tp_as_sequence->sq_item)
+ r = PySequence_GetItem(o, i);
+ else {
+ PyObject *j = PyInt_FromLong(i);
+ if (!j)
+ return 0;
+ r = PyObject_GetItem(o, j);
+ Py_DECREF(j);
+ }
+ return r;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+setitem_int_utility_code = [
+"""
+static int __Pyx_SetItemInt(PyObject *o, Py_ssize_t i, PyObject *v); /*proto*/
+""","""
+static int __Pyx_SetItemInt(PyObject *o, Py_ssize_t i, PyObject *v) {
+ PyTypeObject *t = o->ob_type;
+ int r;
+ if (t->tp_as_sequence && t->tp_as_sequence->sq_item)
+ r = PySequence_SetItem(o, i, v);
+ else {
+ PyObject *j = PyInt_FromLong(i);
+ if (!j)
+ return -1;
+ r = PyObject_SetItem(o, j, v);
+ Py_DECREF(j);
+ }
+ return r;
+}
+"""]