text: #
  #   Parse tree nodes for expressions
  #
  
  import cython
  cython.declare(error=object, warning=object, warn_once=object, InternalError=object,
                 CompileError=object, UtilityCode=object, TempitaUtilityCode=object,
                 StringEncoding=object, operator=object,
                 Naming=object, Nodes=object, PyrexTypes=object, py_object_type=object,
                 list_type=object, tuple_type=object, set_type=object, dict_type=object,
                 unicode_type=object, str_type=object, bytes_type=object, type_type=object,
                 Builtin=object, Symtab=object, Utils=object, find_coercion_error=object,
                 debug_disposal_code=object, debug_temp_alloc=object, debug_coercion=object,
                 bytearray_type=object, slice_type=object)
  
  import sys
  import copy
  import operator
  
  from Errors import error, warning, warn_once, InternalError, CompileError
  from Errors import hold_errors, release_errors, held_errors, report_error
  from Code import UtilityCode, TempitaUtilityCode
  import StringEncoding
  import Naming
  import Nodes
  from Nodes import Node
  import PyrexTypes
  from PyrexTypes import py_object_type, c_long_type, typecast, error_type, \
      unspecified_type
  import TypeSlots
  from Builtin import list_type, tuple_type, set_type, dict_type, type_type, \
       unicode_type, str_type, bytes_type, bytearray_type, basestring_type, slice_type
  import Builtin
  import Symtab
  from Cython import Utils
  from Annotate import AnnotationItem
  from Cython.Compiler import Future
  from Cython.Debugging import print_call_chain
  from DebugFlags import debug_disposal_code, debug_temp_alloc, \
      debug_coercion
  
  try:
      from __builtin__ import basestring
  except ImportError:
      basestring = str # Python 3
  
  try:
      from builtins import bytes
  except ImportError:
      bytes = str # Python 2
  
  
  class NotConstant(object):
      _obj = None
  
      def __new__(cls):
          if NotConstant._obj is None:
              NotConstant._obj = super(NotConstant, cls).__new__(cls)
  
          return NotConstant._obj
  
      def __repr__(self):
          return "<NOT CONSTANT>"
  
  not_a_constant = NotConstant()
  constant_value_not_set = object()
  
  # error messages when coercing from key[0] to key[1]
  coercion_error_dict = {
      # string related errors
      (Builtin.unicode_type, Builtin.bytes_type) : "Cannot convert Unicode string to 'bytes' implicitly, encoding required.",
      (Builtin.unicode_type, Builtin.str_type)   : "Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.",
      (Builtin.unicode_type, PyrexTypes.c_char_ptr_type) : "Unicode objects only support coercion to Py_UNICODE*.",
      (Builtin.unicode_type, PyrexTypes.c_uchar_ptr_type) : "Unicode objects only support coercion to Py_UNICODE*.",
      (Builtin.bytes_type, Builtin.unicode_type) : "Cannot convert 'bytes' object to unicode implicitly, decoding required",
      (Builtin.bytes_type, Builtin.str_type) : "Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.",
      (Builtin.bytes_type, Builtin.basestring_type) : "Cannot convert 'bytes' object to basestring implicitly. This is not portable to Py3.",
      (Builtin.bytes_type, PyrexTypes.c_py_unicode_ptr_type) : "Cannot convert 'bytes' object to Py_UNICODE*, use 'unicode'.",
      (Builtin.basestring_type, Builtin.bytes_type) : "Cannot convert 'basestring' object to bytes implicitly. This is not portable.",
      (Builtin.str_type, Builtin.unicode_type) : "str objects do not support coercion to unicode, use a unicode string literal instead (u'')",
      (Builtin.str_type, Builtin.bytes_type) : "Cannot convert 'str' to 'bytes' implicitly. This is not portable.",
      (Builtin.str_type, PyrexTypes.c_char_ptr_type) : "'str' objects do not support coercion to C types (use 'bytes'?).",
      (Builtin.str_type, PyrexTypes.c_uchar_ptr_type) : "'str' objects do not support coercion to C types (use 'bytes'?).",
      (Builtin.str_type, PyrexTypes.c_py_unicode_ptr_type) : "'str' objects do not support coercion to C types (use 'unicode'?).",
      (PyrexTypes.c_char_ptr_type, Builtin.unicode_type) : "Cannot convert 'char*' to unicode implicitly, decoding required",
      (PyrexTypes.c_uchar_ptr_type, Builtin.unicode_type) : "Cannot convert 'char*' to unicode implicitly, decoding required",
  }
  
  def find_coercion_error(type_tuple, default, env):
      err = coercion_error_dict.get(type_tuple)
      if err is None:
          return default
      elif ((PyrexTypes.c_char_ptr_type in type_tuple or PyrexTypes.c_uchar_ptr_type in type_tuple)
              and env.directives['c_string_encoding']):
          if type_tuple[1].is_pyobject:
              return default
          elif env.directives['c_string_encoding'] in ('ascii', 'default'):
              return default
          else:
              return "'%s' objects do not support coercion to C types with non-ascii or non-default c_string_encoding" % type_tuple[0].name
      else:
          return err
  
  
  def default_str_type(env):
      return {
          'bytes': bytes_type,
          'bytearray': bytearray_type,
          'str': str_type,
          'unicode': unicode_type
      }.get(env.directives['c_string_type'])
  
  
  def check_negative_indices(*nodes):
      """
      Raise a warning on nodes that are known to have negative numeric values.
      Used to find (potential) bugs inside of "wraparound=False" sections.
      """
      for node in nodes:
          if (node is None
                  or not isinstance(node.constant_result, (int, float, long))):
              continue
          if node.constant_result < 0:
              warning(node.pos,
                      "the result of using negative indices inside of "
                      "code sections marked as 'wraparound=False' is "
                      "undefined", level=1)
  
  
  def infer_sequence_item_type(env, seq_node, index_node=None, seq_type=None):
      if not seq_node.is_sequence_constructor:
          if seq_type is None:
              seq_type = seq_node.infer_type(env)
          if seq_type is tuple_type:
              # tuples are immutable => we can safely follow assignments
              if seq_node.cf_state and len(seq_node.cf_state) == 1:
                  try:
                      seq_node = seq_node.cf_state[0].rhs
                  except AttributeError:
                      pass
      if seq_node is not None and seq_node.is_sequence_constructor:
          if index_node is not None and index_node.has_constant_result():
              try:
                  item = seq_node.args[index_node.constant_result]
              except (ValueError, TypeError, IndexError):
                  pass
              else:
                  return item.infer_type(env)
          # if we're lucky, all items have the same type
          item_types = set([item.infer_type(env) for item in seq_node.args])
          if len(item_types) == 1:
              return item_types.pop()
      return None
  
  
  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
      #  is_temp      boolean      Result is in a temporary variable
      #  is_sequence_constructor
      #               boolean      Is a list or tuple constructor expression
      #  is_starred   boolean      Is a starred expression (e.g. '*a')
      #  saved_subexpr_nodes
      #               [ExprNode or [ExprNode or None] or None]
      #                            Cached result of subexpr_nodes()
      #  use_managed_ref boolean   use ref-counted temps/assignments/etc.
      #  result_is_used  boolean   indicates that the result will be dropped and the
      #                            result_code/temp_result can safely be set to None
  
      result_ctype = None
      type = None
      temp_code = None
      old_temp = None # error checker for multiple frees etc.
      use_managed_ref = True # can be set by optimisation transforms
      result_is_used = True
  
      #  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. In that case, 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.
      #
      #      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
      #        - Call generate_evaluation_code for sub-expressions.
      #        - Perform the functions of generate_result_code
      #          (see below).
      #        - If result is temporary, call generate_disposal_code
      #          on all sub-expressions.
      #
      #        A default implementation of generate_evaluation_code
      #        is provided which uses the following abstract methods:
      #
      #          generate_result_code
      #            - Generate any C statements necessary to calculate
      #              the result of this node from the results of its
      #              sub-expressions.
      #
      #          calculate_result_code
      #            - Should return a C code fragment evaluating to the
      #              result. This is only called when the result is not
      #              a temporary.
      #
      #      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.
      #
      #
  
      is_sequence_constructor = 0
      is_string_literal = 0
      is_attribute = 0
      is_subscript = 0
  
      saved_subexpr_nodes = None
      is_temp = 0
      is_target = 0
      is_starred = 0
  
      constant_result = constant_value_not_set
  
      # whether this node with a memoryview type should be broadcast
      memslice_broadcast = False
  
      child_attrs = property(fget=operator.attrgetter('subexprs'))
  
      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_addressable(self):
          return self.is_lvalue() and not self.type.is_memoryviewslice
  
      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.
          nodes = []
          for name in self.subexprs:
              item = getattr(self, name)
              if item is not None:
                  if type(item) is list:
                      nodes.extend(item)
                  else:
                      nodes.append(item)
          return nodes
  
      def result(self):
          if self.is_temp:
              return self.temp_code
          else:
              return self.calculate_result_code()
  
      def result_as(self, type = None):
          #  Return the result code cast to the specified C type.
          if (self.is_temp and self.type.is_pyobject and
                  type != py_object_type):
              # Allocated temporaries are always PyObject *, which may not
              # reflect the actual type (e.g. an extension type)
              return typecast(type, py_object_type, self.result())
          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 (i.e. the
          #  C type of the result_code expression).
          return self.result_ctype or self.type
  
      def get_constant_c_result_code(self):
          # Return the constant value of this node as a result code
          # string, or None if the node is not constant.  This method
          # can be called when the constant result code is required
          # before the code generation phase.
          #
          # The return value is a string that can represent a simple C
          # value, a constant C name or a constant C expression.  If the
          # node type depends on Python code, this must return None.
          return None
  
      def calculate_constant_result(self):
          # Calculate the constant compile time result value of this
          # expression and store it in ``self.constant_result``.  Does
          # nothing by default, thus leaving ``self.constant_result``
          # unknown.  If valid, the result can be an arbitrary Python
          # value.
          #
          # This must only be called when it is assured that all
          # sub-expressions have a valid constant_result value.  The
          # ConstantFolding transform will do this.
          pass
  
      def has_constant_result(self):
          return self.constant_result is not constant_value_not_set and \
                 self.constant_result is not not_a_constant
  
      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.
          node = self.analyse_types(env)
          node.check_const()
          return node
  
      def analyse_expressions(self, env):
          #  Convenience routine performing both the Type
          #  Analysis and Temp Allocation phases for a whole
          #  expression.
          return self.analyse_types(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.
          return self.analyse_target_types(env)
  
      def analyse_boolean_expression(self, env):
          #  Analyse expression and coerce to a boolean.
          node = self.analyse_types(env)
          bool = node.coerce_to_boolean(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.
          node = self.analyse_types(env)
          return node.coerce_to_boolean(env).coerce_to_simple(env)
  
      # --------------- Type Inference -----------------
  
      def type_dependencies(self, env):
          # Returns the list of entries whose types must be determined
          # before the type of self can be inferred.
          if hasattr(self, 'type') and self.type is not None:
              return ()
          return sum([node.type_dependencies(env) for node in self.subexpr_nodes()], ())
  
      def infer_type(self, env):
          # Attempt to deduce the type of self.
          # Differs from analyse_types as it avoids unnecessary
          # analysis of subexpressions, but can assume everything
          # in self.type_dependencies() has been resolved.
          if hasattr(self, 'type') and self.type is not None:
              return self.type
          elif hasattr(self, 'entry') and self.entry is not None:
              return self.entry.type
          else:
              self.not_implemented("infer_type")
  
      def nonlocally_immutable(self):
          # Returns whether this variable is a safe reference, i.e.
          # can't be modified as part of globals or closures.
          return self.is_literal or self.is_temp or self.type.is_array or self.type.is_cfunction
  
      # --------------- Type Analysis ------------------
  
      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_type(self, env):
          # If this node can be interpreted as a reference to a
          # type, return that type, else None.
          return None
  
      def analyse_as_extension_type(self, env):
          # If this node can be interpreted as a reference to an
          # extension type or builtin type, return its type, else None.
          return None
  
      def analyse_types(self, env):
          self.not_implemented("analyse_types")
  
      def analyse_target_types(self, env):
          return self.analyse_types(env)
  
      def nogil_check(self, env):
          # By default, any expression based on Python objects is
          # prevented in nogil environments.  Subtypes must override
          # this if they can work without the GIL.
          if self.type and self.type.is_pyobject:
              self.gil_error()
  
      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()
          return False
  
      def not_const(self):
          error(self.pos, "Not allowed in a constant expression")
  
      def check_const_addr(self):
          self.addr_not_const()
          return False
  
      def addr_not_const(self):
          error(self.pos, "Address is not constant")
  
      # ----------------- 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 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_target_temp(self, env):
  #        #  Release temporaries used by LHS of an assignment.
  #        self.release_subexpr_temps(env)
  
      def allocate_temp_result(self, code):
          if self.temp_code:
              raise RuntimeError("Temp allocated multiple times in %r: %r" % (self.__class__.__name__, self.pos))
          type = self.type
          if not type.is_void:
              if type.is_pyobject:
                  type = PyrexTypes.py_object_type
              self.temp_code = code.funcstate.allocate_temp(
                  type, manage_ref=self.use_managed_ref)
          else:
              self.temp_code = None
  
      def release_temp_result(self, code):
          if not self.temp_code:
              if not self.result_is_used:
                  # not used anyway, so ignore if not set up
                  return
              if self.old_temp:
                  raise RuntimeError("temp %s released multiple times in %s" % (
                          self.old_temp, self.__class__.__name__))
              else:
                  raise RuntimeError("no temp, but release requested in %s" % (
                          self.__class__.__name__))
          code.funcstate.release_temp(self.temp_code)
          self.old_temp = self.temp_code
          self.temp_code = None
  
      # ---------------- Code Generation -----------------
  
      def make_owned_reference(self, code):
          """
          If result is a pyobject, make sure we own a reference to it.
          If the result is in a temp, it is already a new reference.
          """
          if self.type.is_pyobject and not self.result_in_temp():
              code.put_incref(self.result(), self.ctype())
  
      def make_owned_memoryviewslice(self, code):
          """
          Make sure we own the reference to this memoryview slice.
          """
          if not self.result_in_temp():
              code.put_incref_memoryviewslice(self.result(),
                                              have_gil=self.in_nogil_context)
  
      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)
  
          code.mark_pos(self.pos)
          if self.is_temp:
              self.allocate_temp_result(code)
  
          self.generate_result_code(code)
          if self.is_temp:
              # If we are temp we do not need to wait until this node is disposed
              # before disposing children.
              self.generate_subexpr_disposal_code(code)
              self.free_subexpr_temps(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")
  
      def generate_disposal_code(self, code):
          if self.is_temp:
              if self.result():
                  if self.type.is_pyobject:
                      code.put_decref_clear(self.result(), self.ctype())
                  elif self.type.is_memoryviewslice:
                      code.put_xdecref_memoryviewslice(
                              self.result(), have_gil=not self.in_nogil_context)
          else:
              # Already done if self.is_temp
              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):
          if self.is_temp:
              if self.type.is_pyobject:
                  code.putln("%s = 0;" % self.result())
              elif self.type.is_memoryviewslice:
                  code.putln("%s.memview = NULL;" % self.result())
                  code.putln("%s.data = NULL;" % self.result())
          else:
              self.generate_subexpr_disposal_code(code)
  
      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, ignore_nonexisting=False):
          #  Stub method for nodes that are not legal as
          #  the argument of a del statement. An error
          #  will have been reported earlier.
          pass
  
      def free_temps(self, code):
          if self.is_temp:
              if not self.type.is_void:
                  self.release_temp_result(code)
          else:
              self.free_subexpr_temps(code)
  
      def free_subexpr_temps(self, code):
          for sub in self.subexpr_nodes():
              sub.free_temps(code)
  
      def generate_function_definitions(self, env, code):
          pass
  
      # ---------------- Annotation ---------------------
  
      def annotate(self, code):
          for node in self.subexpr_nodes():
              node.annotate(code)
  
      # ----------------- 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.
          #
          #   Note that subclasses that override this (especially
          #   ConstNodes) must not (re-)set their own .type attribute
          #   here.  Since expression nodes may turn up in different
          #   places in the tree (e.g. inside of CloneNodes in cascaded
          #   assignments), this method must return a new node instance
          #   if it changes the type.
          #
          src = self
          src_type = self.type
  
          if self.check_for_coercion_error(dst_type, env):
              return self
  
          if dst_type.is_reference and not src_type.is_reference:
              dst_type = dst_type.ref_base_type
  
          if src_type.is_const:
              src_type = src_type.const_base_type
  
          if src_type.is_fused or dst_type.is_fused:
              # See if we are coercing a fused function to a pointer to a
              # specialized function
              if (src_type.is_cfunction and not dst_type.is_fused and
                      dst_type.is_ptr and dst_type.base_type.is_cfunction):
  
                  dst_type = dst_type.base_type
  
                  for signature in src_type.get_all_specialized_function_types():
                      if signature.same_as(dst_type):
                          src.type = signature
                          src.entry = src.type.entry
                          src.entry.used = True
                          return self
  
              if src_type.is_fused:
                  error(self.pos, "Type is not specialized")
              else:
                  error(self.pos, "Cannot coerce to a type that is not specialized")
  
              self.type = error_type
              return self
  
          if self.coercion_type is not None:
              # This is purely for error checking purposes!
              node = NameNode(self.pos, name='', type=self.coercion_type)
              node.coerce_to(dst_type, env)
  
          if dst_type.is_memoryviewslice:
              import MemoryView
              if not src.type.is_memoryviewslice:
                  if src.type.is_pyobject:
                      src = CoerceToMemViewSliceNode(src, dst_type, env)
                  elif src.type.is_array:
                      src = CythonArrayNode.from_carray(src, env).coerce_to(
                                                              dst_type, env)
                  elif not src_type.is_error:
                      error(self.pos,
                            "Cannot convert '%s' to memoryviewslice" %
                                                                  (src_type,))
              elif not MemoryView.src_conforms_to_dst(
                          src.type, dst_type, broadcast=self.memslice_broadcast):
                  if src.type.dtype.same_as(dst_type.dtype):
                      msg = "Memoryview '%s' not conformable to memoryview '%s'."
                      tup = src.type, dst_type
                  else:
                      msg = "Different base types for memoryviews (%s, %s)"
                      tup = src.type.dtype, dst_type.dtype
  
                  error(self.pos, msg % tup)
  
          elif dst_type.is_pyobject:
              if not src.type.is_pyobject:
                  if dst_type is bytes_type and src.type.is_int:
                      src = CoerceIntToBytesNode(src, env)
                  else:
                      src = CoerceToPyTypeNode(src, env, type=dst_type)
              if not src.type.subtype_of(dst_type):
                  if src.constant_result is not None:
                      src = PyTypeTestNode(src, dst_type, env)
          elif src.type.is_pyobject:
              src = CoerceFromPyTypeNode(dst_type, src, env)
          elif (dst_type.is_complex
                and src_type != dst_type
                and dst_type.assignable_from(src_type)):
              src = CoerceToComplexNode(src, dst_type, env)
          else: # neither src nor dst are py types
              # Added the string comparison, since for c types that
              # is enough, but Cython gets confused when the types are
              # in different pxi files.
              if not (str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)):
                  self.fail_assignment(dst_type)
          return src
  
      def fail_assignment(self, dst_type):
          error(self.pos, "Cannot assign type '%s' to '%s'" % (self.type, dst_type))
  
      def check_for_coercion_error(self, dst_type, env, fail=False, default=None):
          if fail and not default:
              default = "Cannot assign type '%(FROM)s' to '%(TO)s'"
          message = find_coercion_error((self.type, dst_type), default, env)
          if message is not None:
              error(self.pos, message % {'FROM': self.type, 'TO': dst_type})
              return True
          if fail:
              self.fail_assignment(dst_type)
              return True
          return False
  
      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.
  
          # if it's constant, calculate the result now
          if self.has_constant_result():
              bool_value = bool(self.constant_result)
              return BoolNode(self.pos, value=bool_value,
                              constant_result=bool_value)
  
          type = self.type
          if type.is_enum or type.is_error:
              return self
          elif type.is_pyobject or type.is_int or type.is_ptr or type.is_float:
              return CoerceToBooleanNode(self, env)
          else:
              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()
  
      def may_be_none(self):
          if self.type and not (self.type.is_pyobject or
                                self.type.is_memoryviewslice):
              return False
          if self.has_constant_result():
              return self.constant_result is not None
          return True
  
      def as_cython_attribute(self):
          return None
  
      def as_none_safe_node(self, message, error="PyExc_TypeError", format_args=()):
          # Wraps the node in a NoneCheckNode if it is not known to be
          # not-None (e.g. because it is a Python literal).
          if self.may_be_none():
              return NoneCheckNode(self, error, message, format_args)
          else:
              return self
  
      @classmethod
      def from_node(cls, node, **kwargs):
          """Instantiate this node class from another node, properly
          copying over all attributes that one would forget otherwise.
          """
          attributes = "cf_state cf_maybe_null cf_is_null constant_result".split()
          for attr_name in attributes:
              if attr_name in kwargs:
                  continue
              try:
                  value = getattr(node, attr_name)
              except AttributeError:
                  pass
              else:
                  kwargs[attr_name] = value
          return cls(node.pos, **kwargs)
  
  
  class AtomicExprNode(ExprNode):
      #  Abstract base class for expression nodes which have
      #  no sub-expressions.
  
      subexprs = []
  
      # Override to optimize -- we know we have no children
      def generate_subexpr_evaluation_code(self, code):
          pass
      def generate_subexpr_disposal_code(self, code):
          pass
  
  class PyConstNode(AtomicExprNode):
      #  Abstract base class for constant Python values.
  
      is_literal = 1
      type = py_object_type
  
      def is_simple(self):
          return 1
  
      def may_be_none(self):
          return False
  
      def analyse_types(self, env):
          return self
  
      def calculate_result_code(self):
          return self.value
  
      def generate_result_code(self, code):
          pass
  
  
  class NoneNode(PyConstNode):
      #  The constant value None
  
      is_none = 1
      value = "Py_None"
  
      constant_result = None
  
      nogil_check = None
  
      def compile_time_value(self, denv):
          return None
  
      def may_be_none(self):
          return True
  
  
  class EllipsisNode(PyConstNode):
      #  '...' in a subscript list.
  
      value = "Py_Ellipsis"
  
      constant_result = 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
      nogil_check = None
  
      def is_simple(self):
          return 1
  
      def nonlocally_immutable(self):
          return 1
  
      def may_be_none(self):
          return False
  
      def analyse_types(self, env):
          return self  # Types are held in class variables
  
      def check_const(self):
          return True
  
      def get_constant_c_result_code(self):
          return self.calculate_result_code()
  
      def calculate_result_code(self):
          return str(self.value)
  
      def generate_result_code(self, code):
          pass
  
  
  class BoolNode(ConstNode):
      type = PyrexTypes.c_bint_type
      #  The constant value True or False
  
      def calculate_constant_result(self):
          self.constant_result = self.value
  
      def compile_time_value(self, denv):
          return self.value
  
      def calculate_result_code(self):
          if self.type.is_pyobject:
              return self.value and 'Py_True' or 'Py_False'
          else:
              return str(int(self.value))
  
      def coerce_to(self, dst_type, env):
          if dst_type.is_pyobject and self.type.is_int:
              return BoolNode(
                  self.pos, value=self.value,
                  constant_result=self.constant_result,
                  type=Builtin.bool_type)
          if dst_type.is_int and self.type.is_pyobject:
              return BoolNode(
                  self.pos, value=self.value,
                  constant_result=self.constant_result,
                  type=PyrexTypes.c_bint_type)
          return ConstNode.coerce_to(self, dst_type, env)
  
  
  class NullNode(ConstNode):
      type = PyrexTypes.c_null_ptr_type
      value = "NULL"
      constant_result = 0
  
      def get_constant_c_result_code(self):
          return self.value
  
  
  class CharNode(ConstNode):
      type = PyrexTypes.c_char_type
  
      def calculate_constant_result(self):
          self.constant_result = ord(self.value)
  
      def compile_time_value(self, denv):
          return ord(self.value)
  
      def calculate_result_code(self):
          return "'%s'" % StringEncoding.escape_char(self.value)
  
  
  class IntNode(ConstNode):
  
      # unsigned     "" or "U"
      # longness     "" or "L" or "LL"
      # is_c_literal   True/False/None   creator considers this a C integer literal
  
      unsigned = ""
      longness = ""
      is_c_literal = None # unknown
  
      def __init__(self, pos, **kwds):
          ExprNode.__init__(self, pos, **kwds)
          if 'type' not in kwds:
              self.type = self.find_suitable_type_for_value()
  
      def find_suitable_type_for_value(self):
          if self.constant_result is constant_value_not_set:
              try:
                  self.calculate_constant_result()
              except ValueError:
                  pass
          # we ignore 'is_c_literal = True' and instead map signed 32bit
          # integers as C long values
          if self.is_c_literal or \
                 self.constant_result in (constant_value_not_set, not_a_constant) or \
                 self.unsigned or self.longness == 'LL':
              # clearly a C literal
              rank = (self.longness == 'LL') and 2 or 1
              suitable_type = PyrexTypes.modifiers_and_name_to_type[not self.unsigned, rank, "int"]
              if self.type:
                  suitable_type = PyrexTypes.widest_numeric_type(suitable_type, self.type)
          else:
              # C literal or Python literal - split at 32bit boundary
              if -2**31 <= self.constant_result < 2**31:
                  if self.type and self.type.is_int:
                      suitable_type = self.type
                  else:
                      suitable_type = PyrexTypes.c_long_type
              else:
                  suitable_type = PyrexTypes.py_object_type
          return suitable_type
  
      def coerce_to(self, dst_type, env):
          if self.type is dst_type:
              return self
          elif dst_type.is_float:
              if self.has_constant_result():
                  return FloatNode(self.pos, value='%d.0' % int(self.constant_result), type=dst_type,
                                   constant_result=float(self.constant_result))
              else:
                  return FloatNode(self.pos, value=self.value, type=dst_type,
                                   constant_result=not_a_constant)
          if dst_type.is_numeric and not dst_type.is_complex:
              node = IntNode(self.pos, value=self.value, constant_result=self.constant_result,
                             type = dst_type, is_c_literal = True,
                             unsigned=self.unsigned, longness=self.longness)
              return node
          elif dst_type.is_pyobject:
              node = IntNode(self.pos, value=self.value, constant_result=self.constant_result,
                             type = PyrexTypes.py_object_type, is_c_literal = False,
                             unsigned=self.unsigned, longness=self.longness)
          else:
              # FIXME: not setting the type here to keep it working with
              # complex numbers. Should they be special cased?
              node = IntNode(self.pos, value=self.value, constant_result=self.constant_result,
                             unsigned=self.unsigned, longness=self.longness)
          # We still need to perform normal coerce_to processing on the
          # 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 coerce_to_boolean(self, env):
          return IntNode(
              self.pos, value=self.value,
              constant_result=self.constant_result,
              type=PyrexTypes.c_bint_type,
              unsigned=self.unsigned, longness=self.longness)
  
      def generate_evaluation_code(self, code):
          if self.type.is_pyobject:
              # pre-allocate a Python version of the number
              plain_integer_string = str(Utils.str_to_number(self.value))
              self.result_code = code.get_py_int(plain_integer_string, self.longness)
          else:
              self.result_code = self.get_constant_c_result_code()
  
      def get_constant_c_result_code(self):
          return self.value_as_c_integer_string() + self.unsigned + self.longness
  
      def value_as_c_integer_string(self):
          value = self.value
          if len(value) > 2:
              # convert C-incompatible Py3 oct/bin notations
              if value[1] in 'oO':
                  value = value[0] + value[2:] # '0o123' => '0123'
              elif value[1] in 'bB':
                  value = int(value[2:], 2)
          return str(value)
  
      def calculate_result_code(self):
          return self.result_code
  
      def calculate_constant_result(self):
          self.constant_result = Utils.str_to_number(self.value)
  
      def compile_time_value(self, denv):
          return Utils.str_to_number(self.value)
  
  
  class FloatNode(ConstNode):
      type = PyrexTypes.c_double_type
  
      def calculate_constant_result(self):
          self.constant_result = float(self.value)
  
      def compile_time_value(self, denv):
          return float(self.value)
  
      def coerce_to(self, dst_type, env):
          if dst_type.is_pyobject and self.type.is_float:
              return FloatNode(
                  self.pos, value=self.value,
                  constant_result=self.constant_result,
                  type=Builtin.float_type)
          if dst_type.is_float and self.type.is_pyobject:
              return FloatNode(
                  self.pos, value=self.value,
                  constant_result=self.constant_result,
                  type=dst_type)
          return ConstNode.coerce_to(self, dst_type, env)
  
      def calculate_result_code(self):
          return self.result_code
  
      def get_constant_c_result_code(self):
          strval = self.value
          assert isinstance(strval, (str, unicode))
          cmpval = repr(float(strval))
          if cmpval == 'nan':
              return "(Py_HUGE_VAL * 0)"
          elif cmpval == 'inf':
              return "Py_HUGE_VAL"
          elif cmpval == '-inf':
              return "(-Py_HUGE_VAL)"
          else:
              return strval
  
      def generate_evaluation_code(self, code):
          c_value = self.get_constant_c_result_code()
          if self.type.is_pyobject:
              self.result_code = code.get_py_float(self.value, c_value)
          else:
              self.result_code = c_value
  
  
  class BytesNode(ConstNode):
      # A char* or bytes literal
      #
      # value      BytesLiteral
  
      is_string_literal = True
      # start off as Python 'bytes' to support len() in O(1)
      type = bytes_type
  
      def calculate_constant_result(self):
          self.constant_result = self.value
  
      def as_sliced_node(self, start, stop, step=None):
          value = StringEncoding.BytesLiteral(self.value[start:stop:step])
          value.encoding = self.value.encoding
          return BytesNode(
              self.pos, value=value, constant_result=value)
  
      def compile_time_value(self, denv):
          return self.value
  
      def analyse_as_type(self, env):
          type = PyrexTypes.parse_basic_type(self.value)
          if type is not None:
              return type
          from TreeFragment import TreeFragment
          pos = (self.pos[0], self.pos[1], self.pos[2]-7)
          declaration = TreeFragment(u"sizeof(%s)" % self.value, name=pos[0].filename, initial_pos=pos)
          sizeof_node = declaration.root.stats[0].expr
          sizeof_node = sizeof_node.analyse_types(env)
          if isinstance(sizeof_node, SizeofTypeNode):
              return sizeof_node.arg_type
  
      def can_coerce_to_char_literal(self):
          return len(self.value) == 1
  
      def coerce_to_boolean(self, env):
          # This is special because testing a C char* for truth directly
          # would yield the wrong result.
          bool_value = bool(self.value)
          return BoolNode(self.pos, value=bool_value, constant_result=bool_value)
  
      def coerce_to(self, dst_type, env):
          if self.type == dst_type:
              return self
          if dst_type.is_int:
              if not self.can_coerce_to_char_literal():
                  error(self.pos, "Only single-character string literals can be coerced into ints.")
                  return self
              if dst_type.is_unicode_char:
                  error(self.pos, "Bytes literals cannot coerce to Py_UNICODE/Py_UCS4, use a unicode literal instead.")
                  return self
              return CharNode(self.pos, value=self.value,
                              constant_result=ord(self.value))
  
          node = BytesNode(self.pos, value=self.value,
                           constant_result=self.constant_result)
          if dst_type.is_pyobject:
              if dst_type in (py_object_type, Builtin.bytes_type):
                  node.type = Builtin.bytes_type
              else:
                  self.check_for_coercion_error(dst_type, env, fail=True)
                  return node
          elif dst_type == PyrexTypes.c_char_ptr_type:
              node.type = dst_type
              return node
          elif dst_type == PyrexTypes.c_uchar_ptr_type:
              node.type = PyrexTypes.c_char_ptr_type
              return CastNode(node, PyrexTypes.c_uchar_ptr_type)
          elif dst_type.assignable_from(PyrexTypes.c_char_ptr_type):
              node.type = dst_type
              return node
  
          # 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 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 get_constant_c_result_code(self):
          return None # FIXME
  
      def calculate_result_code(self):
          return self.result_code
  
  
  class UnicodeNode(ConstNode):
      # A Py_UNICODE* or unicode literal
      #
      # value        EncodedString
      # bytes_value  BytesLiteral    the literal parsed as bytes string
      #                              ('-3' unicode literals only)
  
      is_string_literal = True
      bytes_value = None
      type = unicode_type
  
      def calculate_constant_result(self):
          self.constant_result = self.value
  
      def as_sliced_node(self, start, stop, step=None):
          if StringEncoding.string_contains_surrogates(self.value[:stop]):
              # this is unsafe as it may give different results
              # in different runtimes
              return None
          value = StringEncoding.EncodedString(self.value[start:stop:step])
          value.encoding = self.value.encoding
          if self.bytes_value is not None:
              bytes_value = StringEncoding.BytesLiteral(
                  self.bytes_value[start:stop:step])
              bytes_value.encoding = self.bytes_value.encoding
          else:
              bytes_value = None
          return UnicodeNode(
              self.pos, value=value, bytes_value=bytes_value,
              constant_result=value)
  
      def coerce_to(self, dst_type, env):
          if dst_type is self.type:
              pass
          elif dst_type.is_unicode_char:
              if not self.can_coerce_to_char_literal():
                  error(self.pos,
                        "Only single-character Unicode string literals or "
                        "surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.")
                  return self
              int_value = ord(self.value)
              return IntNode(self.pos, type=dst_type, value=str(int_value),
                             constant_result=int_value)
          elif not dst_type.is_pyobject:
              if dst_type.is_string and self.bytes_value is not None:
                  # special case: '-3' enforced unicode literal used in a
                  # C char* context
                  return BytesNode(self.pos, value=self.bytes_value
                      ).coerce_to(dst_type, env)
              if dst_type.is_pyunicode_ptr:
                  node = UnicodeNode(self.pos, value=self.value)
                  node.type = dst_type
                  return node
              error(self.pos,
                    "Unicode literals do not support coercion to C types other "
                    "than Py_UNICODE/Py_UCS4 (for characters) or Py_UNICODE* "
                    "(for strings).")
          elif dst_type not in (py_object_type, Builtin.basestring_type):
              self.check_for_coercion_error(dst_type, env, fail=True)
          return self
  
      def can_coerce_to_char_literal(self):
          return len(self.value) == 1
              ## or (len(self.value) == 2
              ##     and (0xD800 <= self.value[0] <= 0xDBFF)
              ##     and (0xDC00 <= self.value[1] <= 0xDFFF))
  
      def coerce_to_boolean(self, env):
          bool_value = bool(self.value)
          return BoolNode(self.pos, value=bool_value, constant_result=bool_value)
  
      def contains_surrogates(self):
          return StringEncoding.string_contains_surrogates(self.value)
  
      def generate_evaluation_code(self, code):
          if self.type.is_pyobject:
              if self.contains_surrogates():
                  # surrogates are not really portable and cannot be
                  # decoded by the UTF-8 codec in Py3.3
                  self.result_code = code.get_py_const(py_object_type, 'ustring')
                  data_cname = code.get_pyunicode_ptr_const(self.value)
                  code = code.get_cached_constants_writer()
                  code.mark_pos(self.pos)
                  code.putln(
                      "%s = PyUnicode_FromUnicode(%s, (sizeof(%s) / sizeof(Py_UNICODE))-1); %s" % (
                          self.result_code,
                          data_cname,
                          data_cname,
                          code.error_goto_if_null(self.result_code, self.pos)))
                  code.putln("#if CYTHON_PEP393_ENABLED")
                  code.put_error_if_neg(
                      self.pos, "PyUnicode_READY(%s)" % self.result_code)
                  code.putln("#endif")
              else:
                  self.result_code = code.get_py_string_const(self.value)
          else:
              self.result_code = code.get_pyunicode_ptr_const(self.value)
  
      def calculate_result_code(self):
          return self.result_code
  
      def compile_time_value(self, env):
          return self.value
  
  
  class StringNode(PyConstNode):
      # A Python str object, i.e. a byte string in Python 2.x and a
      # unicode string in Python 3.x
      #
      # value          BytesLiteral (or EncodedString with ASCII content)
      # unicode_value  EncodedString or None
      # is_identifier  boolean
  
      type = str_type
      is_string_literal = True
      is_identifier = None
      unicode_value = None
  
      def calculate_constant_result(self):
          if self.unicode_value is not None:
              # only the Unicode value is portable across Py2/3
              self.constant_result = self.unicode_value
  
      def as_sliced_node(self, start, stop, step=None):
          value = type(self.value)(self.value[start:stop:step])
          value.encoding = self.value.encoding
          if self.unicode_value is not None:
              if StringEncoding.string_contains_surrogates(self.unicode_value[:stop]):
                  # this is unsafe as it may give different results in different runtimes
                  return None
              unicode_value = StringEncoding.EncodedString(
                  self.unicode_value[start:stop:step])
          else:
              unicode_value = None
          return StringNode(
              self.pos, value=value, unicode_value=unicode_value,
              constant_result=value, is_identifier=self.is_identifier)
  
      def coerce_to(self, dst_type, env):
          if dst_type is not py_object_type and not str_type.subtype_of(dst_type):
  #            if dst_type is Builtin.bytes_type:
  #                # special case: bytes = 'str literal'
  #                return BytesNode(self.pos, value=self.value)
              if not dst_type.is_pyobject:
                  return BytesNode(self.pos, value=self.value).coerce_to(dst_type, env)
              if dst_type is not Builtin.basestring_type:
                  self.check_for_coercion_error(dst_type, env, fail=True)
          return self
  
      def can_coerce_to_char_literal(self):
          return not self.is_identifier and len(self.value) == 1
  
      def generate_evaluation_code(self, code):
          self.result_code = code.get_py_string_const(
              self.value, identifier=self.is_identifier, is_str=True,
              unicode_value=self.unicode_value)
  
      def get_constant_c_result_code(self):
          return None
  
      def calculate_result_code(self):
          return self.result_code
  
      def compile_time_value(self, env):
          return self.value
  
  
  class IdentifierStringNode(StringNode):
      # A special str value that represents an identifier (bytes in Py2,
      # unicode in Py3).
      is_identifier = True
  
  
  class ImagNode(AtomicExprNode):
      #  Imaginary number literal
      #
      #  value   float    imaginary part
  
      type = PyrexTypes.c_double_complex_type
  
      def calculate_constant_result(self):
          self.constant_result = complex(0.0, self.value)
  
      def compile_time_value(self, denv):
          return complex(0.0, self.value)
  
      def analyse_types(self, env):
          self.type.create_declaration_utility_code(env)
          return self
  
      def may_be_none(self):
          return False
  
      def coerce_to(self, dst_type, env):
          if self.type is dst_type:
              return self
          node = ImagNode(self.pos, value=self.value)
          if dst_type.is_pyobject:
              node.is_temp = 1
              node.type = PyrexTypes.py_object_type
          # 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 AtomicExprNode.coerce_to(node, dst_type, env)
  
      gil_message = "Constructing complex number"
  
      def calculate_result_code(self):
          if self.type.is_pyobject:
              return self.result()
          else:
              return "%s(0, %r)" % (self.type.from_parts, float(self.value))
  
      def generate_result_code(self, code):
          if self.type.is_pyobject:
              code.putln(
                  "%s = PyComplex_FromDoubles(0.0, %r); %s" % (
                      self.result(),
                      float(self.value),
                      code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.py_result())
  
  
  class NewExprNode(AtomicExprNode):
  
      # C++ new statement
      #
      # cppclass              node                 c++ class to create
  
      type = None
  
      def infer_type(self, env):
          type = self.cppclass.analyse_as_type(env)
          if type is None or not type.is_cpp_class:
              error(self.pos, "new operator can only be applied to a C++ class")
              self.type = error_type
              return
          self.cpp_check(env)
          constructor = type.scope.lookup(u'<init>')
          if constructor is None:
              func_type = PyrexTypes.CFuncType(type, [], exception_check='+')
              type.scope.declare_cfunction(u'<init>', func_type, self.pos)
              constructor = type.scope.lookup(u'<init>')
          self.class_type = type
          self.entry = constructor
          self.type = constructor.type
          return self.type
  
      def analyse_types(self, env):
          if self.type is None:
              self.infer_type(env)
          return self
  
      def may_be_none(self):
          return False
  
      def generate_result_code(self, code):
          pass
  
      def calculate_result_code(self):
          return "new " + self.class_type.declaration_code("")
  
  
  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
      #  cf_is_null      boolean   Is uninitialized before this node
      #  cf_maybe_null   boolean   Maybe uninitialized before this node
      #  allow_null      boolean   Don't raise UnboundLocalError
      #  nogil           boolean   Whether it is used in a nogil context
  
      is_name = True
      is_cython_module = False
      cython_attribute = None
      lhs_of_first_assignment = False # TODO: remove me
      is_used_as_rvalue = 0
      entry = None
      type_entry = None
      cf_maybe_null = True
      cf_is_null = False
      allow_null = False
      nogil = False
      inferred_type = None
  
      def as_cython_attribute(self):
          return self.cython_attribute
  
      def type_dependencies(self, env):
          if self.entry is None:
              self.entry = env.lookup(self.name)
          if self.entry is not None and self.entry.type.is_unspecified:
              return (self,)
          else:
              return ()
  
      def infer_type(self, env):
          if self.entry is None:
              self.entry = env.lookup(self.name)
          if self.entry is None or self.entry.type is unspecified_type:
              if self.inferred_type is not None:
                  return self.inferred_type
              return py_object_type
          elif (self.entry.type.is_extension_type or self.entry.type.is_builtin_type) and \
                  self.name == self.entry.type.name:
              # Unfortunately the type attribute of type objects
              # is used for the pointer to the type they represent.
              return type_type
          elif self.entry.type.is_cfunction:
              if self.entry.scope.is_builtin_scope:
                  # special case: optimised builtin functions must be treated as Python objects
                  return py_object_type
              else:
                  # special case: referring to a C function must return its pointer
                  return PyrexTypes.CPtrType(self.entry.type)
          else:
              # If entry is inferred as pyobject it's safe to use local
              # NameNode's inferred_type.
              if self.entry.type.is_pyobject and self.inferred_type:
                  # Overflow may happen if integer
                  if not (self.inferred_type.is_int and self.entry.might_overflow):
                      return self.inferred_type
              return self.entry.type
  
      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 get_constant_c_result_code(self):
          if not self.entry or self.entry.type.is_pyobject:
              return None
          return self.entry.cname
  
      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 and entry.is_cfunction:
                  var_entry = entry.as_variable
                  if var_entry:
                      if var_entry.is_builtin and var_entry.is_const:
                          var_entry = env.declare_builtin(var_entry.name, self.pos)
                      node = NameNode(self.pos, name = self.name)
                      node.entry = var_entry
                      node.analyse_rvalue_entry(env)
                      return node
  
          return super(NameNode, self).coerce_to(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 = self.entry
          if not entry:
              entry = env.lookup(self.name)
          if entry and entry.as_module:
              return entry.as_module
          return None
  
      def analyse_as_type(self, env):
          if self.cython_attribute:
              type = PyrexTypes.parse_basic_type(self.cython_attribute)
          else:
              type = PyrexTypes.parse_basic_type(self.name)
          if type:
              return type
          entry = self.entry
          if not entry:
              entry = env.lookup(self.name)
          if entry and entry.is_type:
              return entry.type
          else:
              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 = self.entry
          if not entry:
              entry = env.lookup(self.name)
          if entry and entry.is_type:
              if entry.type.is_extension_type or entry.type.is_builtin_type:
                  return entry.type
          return None
  
      def analyse_target_declaration(self, env):
          if not self.entry:
              self.entry = env.lookup_here(self.name)
          if not self.entry:
              if env.directives['warn.undeclared']:
                  warning(self.pos, "implicit declaration of '%s'" % self.name, 1)
              if env.directives['infer_types'] != False:
                  type = unspecified_type
              else:
                  type = py_object_type
              self.entry = env.declare_var(self.name, type, self.pos)
          if self.entry.is_declared_generic:
              self.result_ctype = py_object_type
  
      def analyse_types(self, env):
          self.initialized_check = env.directives['initializedcheck']
          if self.entry is None:
              self.entry = env.lookup(self.name)
          if not self.entry:
              self.entry = env.declare_builtin(self.name, self.pos)
          if not self.entry:
              self.type = PyrexTypes.error_type
              return self
          entry = self.entry
          if entry:
              entry.used = 1
              if entry.type.is_buffer:
                  import Buffer
                  Buffer.used_buffer_aux_vars(entry)
          self.analyse_rvalue_entry(env)
          return self
  
      def analyse_target_types(self, env):
          self.analyse_entry(env, is_target=True)
  
          if (not self.is_lvalue() and self.entry.is_cfunction and
                  self.entry.fused_cfunction and self.entry.as_variable):
              # We need this for the fused 'def' TreeFragment
              self.entry = self.entry.as_variable
              self.type = self.entry.type
  
          if self.type.is_const:
              error(self.pos, "Assignment to const '%s'" % self.name)
          if self.type.is_reference:
              error(self.pos, "Assignment to reference '%s'" % self.name)
          if not self.is_lvalue():
              error(self.pos, "Assignment to non-lvalue '%s'"
                  % self.name)
              self.type = PyrexTypes.error_type
          self.entry.used = 1
          if self.entry.type.is_buffer:
              import Buffer
              Buffer.used_buffer_aux_vars(self.entry)
          return self
  
      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:
              if entry.is_builtin and entry.is_const:
                  self.is_temp = 0
              else:
                  self.is_temp = 1
  
              self.is_used_as_rvalue = 1
          elif entry.type.is_memoryviewslice:
              self.is_temp = False
              self.is_used_as_rvalue = True
              self.use_managed_ref = True
          return self
  
      def nogil_check(self, env):
          self.nogil = True
          if self.is_used_as_rvalue:
              entry = self.entry
              if entry.is_builtin:
                  if not entry.is_const: # cached builtins are ok
                      self.gil_error()
              elif entry.is_pyglobal:
                  self.gil_error()
              elif self.entry.type.is_memoryviewslice:
                  if self.cf_is_null or self.cf_maybe_null:
                      import MemoryView
                      MemoryView.err_if_nogil_initialized_check(self.pos, env)
  
      gil_message = "Accessing Python global or builtin"
  
      def analyse_entry(self, env, is_target=False):
          #print "NameNode.analyse_entry:", self.name ###
          self.check_identifier_kind()
          entry = self.entry
          type = entry.type
          if (not is_target and type.is_pyobject and self.inferred_type and
                  self.inferred_type.is_builtin_type):
              # assume that type inference is smarter than the static entry
              type = self.inferred_type
          self.type = type
  
      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
              or entry.is_cpp_class):
                  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 may_be_none(self):
          if self.cf_state and self.type and (self.type.is_pyobject or
                                              self.type.is_memoryviewslice):
              # gard against infinite recursion on self-dependencies
              if getattr(self, '_none_checking', False):
                  # self-dependency - either this node receives a None
                  # value from *another* node, or it can not reference
                  # None at this point => safe to assume "not None"
                  return False
              self._none_checking = True
              # evaluate control flow state to see if there were any
              # potential None values assigned to the node so far
              may_be_none = False
              for assignment in self.cf_state:
                  if assignment.rhs.may_be_none():
                      may_be_none = True
                      break
              del self._none_checking
              return may_be_none
          return super(NameNode, self).may_be_none()
  
      def nonlocally_immutable(self):
          if ExprNode.nonlocally_immutable(self):
              return True
          entry = self.entry
          if not entry or entry.in_closure:
              return False
          return entry.is_local or entry.is_arg or entry.is_builtin or entry.is_readonly
  
      def calculate_target_results(self, env):
          pass
  
      def check_const(self):
          entry = self.entry
          if entry is not None and not (entry.is_const or entry.is_cfunction or entry.is_builtin):
              self.not_const()
              return False
          return True
  
      def check_const_addr(self):
          entry = self.entry
          if not (entry.is_cglobal or entry.is_cfunction or entry.is_builtin):
              self.addr_not_const()
              return False
          return True
  
      def is_lvalue(self):
          return self.entry.is_variable and \
              not self.entry.type.is_array and \
              not self.entry.is_readonly
  
      def is_addressable(self):
          return self.entry.is_variable and not self.type.is_memoryviewslice
  
      def is_ephemeral(self):
          #  Name nodes are never ephemeral, even if the
          #  result is in a temporary.
          return 0
  
      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.is_builtin and entry.is_const:
              return # Lookup already cached
          elif entry.is_pyclass_attr:
              assert entry.type.is_pyobject, "Python global or builtin not a Python object"
              interned_cname = code.intern_identifier(self.entry.name)
              if entry.is_builtin:
                  namespace = Naming.builtins_cname
              else: # entry.is_pyglobal
                  namespace = entry.scope.namespace_cname
              if not self.cf_is_null:
                  code.putln(
                      '%s = PyObject_GetItem(%s, %s);' % (
                          self.result(),
                          namespace,
                          interned_cname))
                  code.putln('if (unlikely(!%s)) {' % self.result())
                  code.putln('PyErr_Clear();')
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c"))
              code.putln(
                  '%s = __Pyx_GetModuleGlobalName(%s);' % (
                      self.result(),
                      interned_cname))
              if not self.cf_is_null:
                  code.putln("}")
              code.putln(code.error_goto_if_null(self.result(), self.pos))
              code.put_gotref(self.py_result())
  
          elif entry.is_builtin:
              assert entry.type.is_pyobject, "Python global or builtin not a Python object"
              interned_cname = code.intern_identifier(self.entry.name)
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("GetBuiltinName", "ObjectHandling.c"))
              code.putln(
                  '%s = __Pyx_GetBuiltinName(%s); %s' % (
                  self.result(),
                  interned_cname,
                  code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.py_result())
  
          elif entry.is_pyglobal:
              assert entry.type.is_pyobject, "Python global or builtin not a Python object"
              interned_cname = code.intern_identifier(self.entry.name)
              if entry.scope.is_module_scope:
                  code.globalstate.use_utility_code(
                      UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c"))
                  code.putln(
                      '%s = __Pyx_GetModuleGlobalName(%s); %s' % (
                          self.result(),
                          interned_cname,
                          code.error_goto_if_null(self.result(), self.pos)))
              else:
                  # FIXME: is_pyglobal is also used for class namespace
                  code.globalstate.use_utility_code(
                      UtilityCode.load_cached("GetNameInClass", "ObjectHandling.c"))
                  code.putln(
                      '%s = __Pyx_GetNameInClass(%s, %s); %s' % (
                          self.result(),
                          entry.scope.namespace_cname,
                          interned_cname,
                          code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.py_result())
  
          elif entry.is_local or entry.in_closure or entry.from_closure or entry.type.is_memoryviewslice:
              # Raise UnboundLocalError for objects and memoryviewslices
              raise_unbound = (
                  (self.cf_maybe_null or self.cf_is_null) and not self.allow_null)
              null_code = entry.type.check_for_null_code(entry.cname)
  
              memslice_check = entry.type.is_memoryviewslice and self.initialized_check
  
              if null_code and raise_unbound and (entry.type.is_pyobject or memslice_check):
                  code.put_error_if_unbound(self.pos, entry, self.in_nogil_context)
  
      def generate_assignment_code(self, rhs, code):
          #print "NameNode.generate_assignment_code:", self.name ###
          entry = self.entry
          if entry is None:
              return # There was an error earlier
  
          if (self.entry.type.is_ptr and isinstance(rhs, ListNode)
              and not self.lhs_of_first_assignment and not rhs.in_module_scope):
              error(self.pos, "Literal list must be assigned to pointer at time of declaration")
  
          # is_pyglobal seems to be True for module level-globals only.
          # We use this to access class->tp_dict if necessary.
          if entry.is_pyglobal:
              assert entry.type.is_pyobject, "Python global or builtin not a Python object"
              interned_cname = code.intern_identifier(self.entry.name)
              namespace = self.entry.scope.namespace_cname
              if entry.is_member:
                  # if the entry is a member we have to cheat: SetAttr does not work
                  # on types, so we create a descriptor which is then added to tp_dict
                  setter = 'PyDict_SetItem'
                  namespace = '%s->tp_dict' % namespace
              elif entry.scope.is_module_scope:
                  setter = 'PyDict_SetItem'
                  namespace = Naming.moddict_cname
              elif entry.is_pyclass_attr:
                  setter = 'PyObject_SetItem'
              else:
                  assert False, repr(entry)
              code.put_error_if_neg(
                  self.pos,
                  '%s(%s, %s, %s)' % (
                      setter,
                      namespace,
                      interned_cname,
                      rhs.py_result()))
              if debug_disposal_code:
                  print("NameNode.generate_assignment_code:")
                  print("...generating disposal code for %s" % rhs)
              rhs.generate_disposal_code(code)
              rhs.free_temps(code)
              if entry.is_member:
                  # in Py2.6+, we need to invalidate the method cache
                  code.putln("PyType_Modified(%s);" %
                             entry.scope.parent_type.typeptr_cname)
          else:
              if self.type.is_memoryviewslice:
                  self.generate_acquire_memoryviewslice(rhs, code)
  
              elif self.type.is_buffer:
                  # Generate code for doing the buffer release/acquisition.
                  # This might raise an exception in which case the assignment (done
                  # below) will not happen.
                  #
                  # The reason this is not in a typetest-like node is because the
                  # variables that the acquired buffer info is stored to is allocated
                  # per entry and coupled with it.
                  self.generate_acquire_buffer(rhs, code)
              assigned = False
              if self.type.is_pyobject:
                  #print "NameNode.generate_assignment_code: to", self.name ###
                  #print "...from", rhs ###
                  #print "...LHS type", self.type, "ctype", self.ctype() ###
                  #print "...RHS type", rhs.type, "ctype", rhs.ctype() ###
                  if self.use_managed_ref:
                      rhs.make_owned_reference(code)
                      is_external_ref = entry.is_cglobal or self.entry.in_closure or self.entry.from_closure
                      if is_external_ref:
                          if not self.cf_is_null:
                              if self.cf_maybe_null:
                                  code.put_xgotref(self.py_result())
                              else:
                                  code.put_gotref(self.py_result())
                      assigned = True
                      if entry.is_cglobal:
                          code.put_decref_set(
                              self.result(), rhs.result_as(self.ctype()))
                      else:
                          if not self.cf_is_null:
                              if self.cf_maybe_null:
                                  code.put_xdecref_set(
                                      self.result(), rhs.result_as(self.ctype()))
                              else:
                                  code.put_decref_set(
                                      self.result(), rhs.result_as(self.ctype()))
                          else:
                              assigned = False
                      if is_external_ref:
                          code.put_giveref(rhs.py_result())
              if not self.type.is_memoryviewslice:
                  if not assigned:
                      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 %s" % rhs)
                  rhs.generate_post_assignment_code(code)
              elif rhs.result_in_temp():
                  rhs.generate_post_assignment_code(code)
  
              rhs.free_temps(code)
  
      def generate_acquire_memoryviewslice(self, rhs, code):
          """
          Slices, coercions from objects, return values etc are new references.
          We have a borrowed reference in case of dst = src
          """
          import MemoryView
  
          MemoryView.put_acquire_memoryviewslice(
              lhs_cname=self.result(),
              lhs_type=self.type,
              lhs_pos=self.pos,
              rhs=rhs,
              code=code,
              have_gil=not self.in_nogil_context,
              first_assignment=self.cf_is_null)
  
      def generate_acquire_buffer(self, rhs, code):
          # rhstmp is only used in case the rhs is a complicated expression leading to
          # the object, to avoid repeating the same C expression for every reference
          # to the rhs. It does NOT hold a reference.
          pretty_rhs = isinstance(rhs, NameNode) or rhs.is_temp
          if pretty_rhs:
              rhstmp = rhs.result_as(self.ctype())
          else:
              rhstmp = code.funcstate.allocate_temp(self.entry.type, manage_ref=False)
              code.putln('%s = %s;' % (rhstmp, rhs.result_as(self.ctype())))
  
          import Buffer
          Buffer.put_assign_to_buffer(self.result(), rhstmp, self.entry,
                                      is_initialized=not self.lhs_of_first_assignment,
                                      pos=self.pos, code=code)
  
          if not pretty_rhs:
              code.putln("%s = 0;" % rhstmp)
              code.funcstate.release_temp(rhstmp)
  
      def generate_deletion_code(self, code, ignore_nonexisting=False):
          if self.entry is None:
              return # There was an error earlier
          elif self.entry.is_pyclass_attr:
              namespace = self.entry.scope.namespace_cname
              interned_cname = code.intern_identifier(self.entry.name)
              if ignore_nonexisting:
                  key_error_code = 'PyErr_Clear(); else'
              else:
                  # minor hack: fake a NameError on KeyError
                  key_error_code = (
                      '{ PyErr_Clear(); PyErr_Format(PyExc_NameError, "name \'%%s\' is not defined", "%s"); }' %
                      self.entry.name)
              code.putln(
                  'if (unlikely(PyObject_DelItem(%s, %s) < 0)) {'
                  ' if (likely(PyErr_ExceptionMatches(PyExc_KeyError))) %s'
                  ' %s '
                  '}' % (namespace, interned_cname,
                         key_error_code,
                         code.error_goto(self.pos)))
          elif self.entry.is_pyglobal:
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("PyObjectSetAttrStr", "ObjectHandling.c"))
              interned_cname = code.intern_identifier(self.entry.name)
              del_code = '__Pyx_PyObject_DelAttrStr(%s, %s)' % (
                  Naming.module_cname, interned_cname)
              if ignore_nonexisting:
                  code.putln('if (unlikely(%s < 0)) { if (likely(PyErr_ExceptionMatches(PyExc_AttributeError))) PyErr_Clear(); else %s }' % (
                      del_code,
                      code.error_goto(self.pos)))
              else:
                  code.put_error_if_neg(self.pos, del_code)
          elif self.entry.type.is_pyobject or self.entry.type.is_memoryviewslice:
              if not self.cf_is_null:
                  if self.cf_maybe_null and not ignore_nonexisting:
                      code.put_error_if_unbound(self.pos, self.entry)
  
                  if self.entry.type.is_pyobject:
                      if self.entry.in_closure:
                          # generator
                          if ignore_nonexisting and self.cf_maybe_null:
                              code.put_xgotref(self.result())
                          else:
                              code.put_gotref(self.result())
                      if ignore_nonexisting and self.cf_maybe_null:
                          code.put_xdecref(self.result(), self.ctype())
                      else:
                          code.put_decref(self.result(), self.ctype())
                      code.putln('%s = NULL;' % self.result())
                  else:
                      code.put_xdecref_memoryviewslice(self.entry.cname,
                                                       have_gil=not self.nogil)
          else:
              error(self.pos, "Deletion of C names not supported")
  
      def annotate(self, code):
          if hasattr(self, 'is_called') and self.is_called:
              pos = (self.pos[0], self.pos[1], self.pos[2] - len(self.name) - 1)
              if self.type.is_pyobject:
                  style, text = 'py_call', 'python function (%s)'
              else:
                  style, text = 'c_call', 'c function (%s)'
              code.annotate(pos, AnnotationItem(style, text % self.type, size=len(self.name)))
  
  class BackquoteNode(ExprNode):
      #  `expr`
      #
      #  arg    ExprNode
  
      type = py_object_type
  
      subexprs = ['arg']
  
      def analyse_types(self, env):
          self.arg = self.arg.analyse_types(env)
          self.arg = self.arg.coerce_to_pyobject(env)
          self.is_temp = 1
          return self
  
      gil_message = "Backquote expression"
  
      def calculate_constant_result(self):
          self.constant_result = repr(self.arg.constant_result)
  
      def generate_result_code(self, code):
          code.putln(
              "%s = PyObject_Repr(%s); %s" % (
                  self.result(),
                  self.arg.py_result(),
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  
  class ImportNode(ExprNode):
      #  Used as part of import statement implementation.
      #  Implements result =
      #    __import__(module_name, globals(), None, name_list, level)
      #
      #  module_name   StringNode            dotted name of module. Empty module
      #                       name means importing the parent package according
      #                       to level
      #  name_list     ListNode or None      list of names to be imported
      #  level         int                   relative import level:
      #                       -1: attempt both relative import and absolute import;
      #                        0: absolute import;
      #                       >0: the number of parent directories to search
      #                           relative to the current module.
      #                     None: decide the level according to language level and
      #                           directives
  
      type = py_object_type
  
      subexprs = ['module_name', 'name_list']
  
      def analyse_types(self, env):
          if self.level is None:
              if (env.directives['py2_import'] or
                  Future.absolute_import not in env.global_scope().context.future_directives):
                  self.level = -1
              else:
                  self.level = 0
          module_name = self.module_name.analyse_types(env)
          self.module_name = module_name.coerce_to_pyobject(env)
          if self.name_list:
              name_list = self.name_list.analyse_types(env)
              self.name_list = name_list.coerce_to_pyobject(env)
          self.is_temp = 1
          env.use_utility_code(UtilityCode.load_cached("Import", "ImportExport.c"))
          return self
  
      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.putln(
              "%s = __Pyx_Import(%s, %s, %d); %s" % (
                  self.result(),
                  self.module_name.py_result(),
                  name_list_code,
                  self.level,
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  
  class IteratorNode(ExprNode):
      #  Used as part of for statement implementation.
      #
      #  Implements result = iter(sequence)
      #
      #  sequence   ExprNode
  
      type = py_object_type
      iter_func_ptr = None
      counter_cname = None
      cpp_iterator_cname = None
      reversed = False      # currently only used for list/tuple types (see Optimize.py)
  
      subexprs = ['sequence']
  
      def analyse_types(self, env):
          self.sequence = self.sequence.analyse_types(env)
          if (self.sequence.type.is_array or self.sequence.type.is_ptr) and \
                  not self.sequence.type.is_string:
              # C array iteration will be transformed later on
              self.type = self.sequence.type
          elif self.sequence.type.is_cpp_class:
              self.analyse_cpp_types(env)
          else:
              self.sequence = self.sequence.coerce_to_pyobject(env)
              if self.sequence.type is list_type or \
                     self.sequence.type is tuple_type:
                  self.sequence = self.sequence.as_none_safe_node("'NoneType' object is not iterable")
          self.is_temp = 1
          return self
  
      gil_message = "Iterating over Python object"
  
      _func_iternext_type = PyrexTypes.CPtrType(PyrexTypes.CFuncType(
          PyrexTypes.py_object_type, [
              PyrexTypes.CFuncTypeArg("it", PyrexTypes.py_object_type, None),
              ]))
  
      def type_dependencies(self, env):
          return self.sequence.type_dependencies(env)
  
      def infer_type(self, env):
          sequence_type = self.sequence.infer_type(env)
          if sequence_type.is_array or sequence_type.is_ptr:
              return sequence_type
          elif sequence_type.is_cpp_class:
              begin = sequence_type.scope.lookup("begin")
              if begin is not None:
                  return begin.type.return_type
          elif sequence_type.is_pyobject:
              return sequence_type
          return py_object_type
  
      def analyse_cpp_types(self, env):
          sequence_type = self.sequence.type
          if sequence_type.is_ptr:
              sequence_type = sequence_type.base_type
          begin = sequence_type.scope.lookup("begin")
          end = sequence_type.scope.lookup("end")
          if (begin is None
              or not begin.type.is_cfunction
              or begin.type.args):
              error(self.pos, "missing begin() on %s" % self.sequence.type)
              self.type = error_type
              return
          if (end is None
              or not end.type.is_cfunction
              or end.type.args):
              error(self.pos, "missing end() on %s" % self.sequence.type)
              self.type = error_type
              return
          iter_type = begin.type.return_type
          if iter_type.is_cpp_class:
              if env.lookup_operator_for_types(
                      self.pos,
                      "!=",
                      [iter_type, end.type.return_type]) is None:
                  error(self.pos, "missing operator!= on result of begin() on %s" % self.sequence.type)
                  self.type = error_type
                  return
              if env.lookup_operator_for_types(self.pos, '++', [iter_type]) is None:
                  error(self.pos, "missing operator++ on result of begin() on %s" % self.sequence.type)
                  self.type = error_type
                  return
              if env.lookup_operator_for_types(self.pos, '*', [iter_type]) is None:
                  error(self.pos, "missing operator* on result of begin() on %s" % self.sequence.type)
                  self.type = error_type
                  return
              self.type = iter_type
          elif iter_type.is_ptr:
              if not (iter_type == end.type.return_type):
                  error(self.pos, "incompatible types for begin() and end()")
              self.type = iter_type
          else:
              error(self.pos, "result type of begin() on %s must be a C++ class or pointer" % self.sequence.type)
              self.type = error_type
              return
  
      def generate_result_code(self, code):
          sequence_type = self.sequence.type
          if sequence_type.is_cpp_class:
              if self.sequence.is_name:
                  # safe: C++ won't allow you to reassign to class references
                  begin_func = "%s.begin" % self.sequence.result()
              else:
                  sequence_type = PyrexTypes.c_ptr_type(sequence_type)
                  self.cpp_iterator_cname = code.funcstate.allocate_temp(sequence_type, manage_ref=False)
                  code.putln("%s = &%s;" % (self.cpp_iterator_cname, self.sequence.result()))
                  begin_func = "%s->begin" % self.cpp_iterator_cname
              # TODO: Limit scope.
              code.putln("%s = %s();" % (self.result(), begin_func))
              return
          if sequence_type.is_array or sequence_type.is_ptr:
              raise InternalError("for in carray slice not transformed")
          is_builtin_sequence = sequence_type is list_type or \
                                sequence_type is tuple_type
          if not is_builtin_sequence:
              # reversed() not currently optimised (see Optimize.py)
              assert not self.reversed, "internal error: reversed() only implemented for list/tuple objects"
          self.may_be_a_sequence = not sequence_type.is_builtin_type
          if self.may_be_a_sequence:
              code.putln(
                  "if (PyList_CheckExact(%s) || PyTuple_CheckExact(%s)) {" % (
                      self.sequence.py_result(),
                      self.sequence.py_result()))
          if is_builtin_sequence or self.may_be_a_sequence:
              self.counter_cname = code.funcstate.allocate_temp(
                  PyrexTypes.c_py_ssize_t_type, manage_ref=False)
              if self.reversed:
                  if sequence_type is list_type:
                      init_value = 'PyList_GET_SIZE(%s) - 1' % self.result()
                  else:
                      init_value = 'PyTuple_GET_SIZE(%s) - 1' % self.result()
              else:
                  init_value = '0'
              code.putln(
                  "%s = %s; __Pyx_INCREF(%s); %s = %s;" % (
                      self.result(),
                      self.sequence.py_result(),
                      self.result(),
                      self.counter_cname,
                      init_value
                      ))
          if not is_builtin_sequence:
              self.iter_func_ptr = code.funcstate.allocate_temp(self._func_iternext_type, manage_ref=False)
              if self.may_be_a_sequence:
                  code.putln("%s = NULL;" % self.iter_func_ptr)
                  code.putln("} else {")
                  code.put("%s = -1; " % self.counter_cname)
              code.putln("%s = PyObject_GetIter(%s); %s" % (
                      self.result(),
                      self.sequence.py_result(),
                      code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.py_result())
              code.putln("%s = Py_TYPE(%s)->tp_iternext;" % (self.iter_func_ptr, self.py_result()))
          if self.may_be_a_sequence:
              code.putln("}")
  
      def generate_next_sequence_item(self, test_name, result_name, code):
          assert self.counter_cname, "internal error: counter_cname temp not prepared"
          final_size = 'Py%s_GET_SIZE(%s)' % (test_name, self.py_result())
          if self.sequence.is_sequence_constructor:
              item_count = len(self.sequence.args)
              if self.sequence.mult_factor is None:
                  final_size = item_count
              elif isinstance(self.sequence.mult_factor.constant_result, (int, long)):
                  final_size = item_count * self.sequence.mult_factor.constant_result
          code.putln("if (%s >= %s) break;" % (self.counter_cname, final_size))
          if self.reversed:
              inc_dec = '--'
          else:
              inc_dec = '++'
          code.putln("#if CYTHON_COMPILING_IN_CPYTHON")
          code.putln(
              "%s = Py%s_GET_ITEM(%s, %s); __Pyx_INCREF(%s); %s%s; %s" % (
                  result_name,
                  test_name,
                  self.py_result(),
                  self.counter_cname,
                  result_name,
                  self.counter_cname,
                  inc_dec,
                  # use the error label to avoid C compiler warnings if we only use it below
                  code.error_goto_if_neg('0', self.pos)
                  ))
          code.putln("#else")
          code.putln(
              "%s = PySequence_ITEM(%s, %s); %s%s; %s" % (
                  result_name,
                  self.py_result(),
                  self.counter_cname,
                  self.counter_cname,
                  inc_dec,
                  code.error_goto_if_null(result_name, self.pos)))
          code.putln("#endif")
  
      def generate_iter_next_result_code(self, result_name, code):
          sequence_type = self.sequence.type
          if self.reversed:
              code.putln("if (%s < 0) break;" % self.counter_cname)
          if sequence_type.is_cpp_class:
              if self.cpp_iterator_cname:
                  end_func = "%s->end" % self.cpp_iterator_cname
              else:
                  end_func = "%s.end" % self.sequence.result()
              # TODO: Cache end() call?
              code.putln("if (!(%s != %s())) break;" % (
                              self.result(),
                              end_func))
              code.putln("%s = *%s;" % (
                              result_name,
                              self.result()))
              code.putln("++%s;" % self.result())
              return
          elif sequence_type is list_type:
              self.generate_next_sequence_item('List', result_name, code)
              return
          elif sequence_type is tuple_type:
              self.generate_next_sequence_item('Tuple', result_name, code)
              return
  
          if self.may_be_a_sequence:
              for test_name in ('List', 'Tuple'):
                  code.putln("if (!%s && Py%s_CheckExact(%s)) {" % (
                      self.iter_func_ptr, test_name, self.py_result()))
                  self.generate_next_sequence_item(test_name, result_name, code)
                  code.put("} else ")
  
          code.putln("{")
          code.putln(
              "%s = %s(%s);" % (
                  result_name,
                  self.iter_func_ptr,
                  self.py_result()))
          code.putln("if (unlikely(!%s)) {" % result_name)
          code.putln("PyObject* exc_type = PyErr_Occurred();")
          code.putln("if (exc_type) {")
          code.putln("if (likely(exc_type == PyExc_StopIteration ||"
                     " PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();")
          code.putln("else %s" % code.error_goto(self.pos))
          code.putln("}")
          code.putln("break;")
          code.putln("}")
          code.put_gotref(result_name)
          code.putln("}")
  
      def free_temps(self, code):
          if self.counter_cname:
              code.funcstate.release_temp(self.counter_cname)
          if self.iter_func_ptr:
              code.funcstate.release_temp(self.iter_func_ptr)
              self.iter_func_ptr = None
          if self.cpp_iterator_cname:
              code.funcstate.release_temp(self.cpp_iterator_cname)
          ExprNode.free_temps(self, code)
  
  
  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   IteratorNode
  
      def __init__(self, iterator):
          AtomicExprNode.__init__(self, iterator.pos)
          self.iterator = iterator
  
      def type_dependencies(self, env):
          return self.iterator.type_dependencies(env)
  
      def infer_type(self, env, iterator_type = None):
          if iterator_type is None:
              iterator_type = self.iterator.infer_type(env)
          if iterator_type.is_ptr or iterator_type.is_array:
              return iterator_type.base_type
          elif iterator_type.is_cpp_class:
              item_type = env.lookup_operator_for_types(self.pos, "*", [iterator_type]).type.return_type
              if item_type.is_reference:
                  item_type = item_type.ref_base_type
              if item_type.is_const:
                  item_type = item_type.const_base_type
              return item_type
          else:
              # Avoid duplication of complicated logic.
              fake_index_node = IndexNode(
                  self.pos,
                  base=self.iterator.sequence,
                  index=IntNode(self.pos, value='PY_SSIZE_T_MAX',
                                type=PyrexTypes.c_py_ssize_t_type))
              return fake_index_node.infer_type(env)
  
      def analyse_types(self, env):
          self.type = self.infer_type(env, self.iterator.type)
          self.is_temp = 1
          return self
  
      def generate_result_code(self, code):
          self.iterator.generate_iter_next_result_code(self.result(), code)
  
  
  class WithExitCallNode(ExprNode):
      # The __exit__() call of a 'with' statement.  Used in both the
      # except and finally clauses.
  
      # with_stat  WithStatNode                the surrounding 'with' statement
      # args       TupleNode or ResultStatNode the exception info tuple
  
      subexprs = ['args']
      test_if_run = True
  
      def analyse_types(self, env):
          self.args = self.args.analyse_types(env)
          self.type = PyrexTypes.c_bint_type
          self.is_temp = True
          return self
  
      def generate_evaluation_code(self, code):
          if self.test_if_run:
              # call only if it was not already called (and decref-cleared)
              code.putln("if (%s) {" % self.with_stat.exit_var)
  
          self.args.generate_evaluation_code(code)
          result_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False)
  
          code.mark_pos(self.pos)
          code.globalstate.use_utility_code(UtilityCode.load_cached(
              "PyObjectCall", "ObjectHandling.c"))
          code.putln("%s = __Pyx_PyObject_Call(%s, %s, NULL);" % (
              result_var,
              self.with_stat.exit_var,
              self.args.result()))
          code.put_decref_clear(self.with_stat.exit_var, type=py_object_type)
          self.args.generate_disposal_code(code)
          self.args.free_temps(code)
  
          code.putln(code.error_goto_if_null(result_var, self.pos))
          code.put_gotref(result_var)
          if self.result_is_used:
              self.allocate_temp_result(code)
              code.putln("%s = __Pyx_PyObject_IsTrue(%s);" % (self.result(), result_var))
          code.put_decref_clear(result_var, type=py_object_type)
          if self.result_is_used:
              code.put_error_if_neg(self.pos, self.result())
          code.funcstate.release_temp(result_var)
          if self.test_if_run:
              code.putln("}")
  
  
  class ExcValueNode(AtomicExprNode):
      #  Node created during analyse_types phase
      #  of an ExceptClauseNode to fetch the current
      #  exception value.
  
      type = py_object_type
  
      def __init__(self, pos):
          ExprNode.__init__(self, pos)
  
      def set_var(self, var):
          self.var = var
  
      def calculate_result_code(self):
          return self.var
  
      def generate_result_code(self, code):
          pass
  
      def analyse_types(self, env):
          return self
  
  
  class TempNode(ExprNode):
      # Node created during analyse_types phase
      # of some nodes to hold a temporary value.
      #
      # Note: One must call "allocate" and "release" on
      # the node during code generation to get/release the temp.
      # This is because the temp result is often used outside of
      # the regular cycle.
  
      subexprs = []
  
      def __init__(self, pos, type, env=None):
          ExprNode.__init__(self, pos)
          self.type = type
          if type.is_pyobject:
              self.result_ctype = py_object_type
          self.is_temp = 1
  
      def analyse_types(self, env):
          return self
  
      def analyse_target_declaration(self, env):
          pass
  
      def generate_result_code(self, code):
          pass
  
      def allocate(self, code):
          self.temp_cname = code.funcstate.allocate_temp(self.type, manage_ref=True)
  
      def release(self, code):
          code.funcstate.release_temp(self.temp_cname)
          self.temp_cname = None
  
      def result(self):
          try:
              return self.temp_cname
          except:
              assert False, "Remember to call allocate/release on TempNode"
              raise
  
      # Do not participate in normal temp alloc/dealloc:
      def allocate_temp_result(self, code):
          pass
  
      def release_temp_result(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)
  
  class RawCNameExprNode(ExprNode):
      subexprs = []
  
      def __init__(self, pos, type=None, cname=None):
          ExprNode.__init__(self, pos, type=type)
          if cname is not None:
              self.cname = cname
  
      def analyse_types(self, env):
          return self
  
      def set_cname(self, cname):
          self.cname = cname
  
      def result(self):
          return self.cname
  
      def generate_result_code(self, code):
          pass
  
  
  #-------------------------------------------------------------------
  #
  #  Parallel nodes (cython.parallel.thread(savailable|id))
  #
  #-------------------------------------------------------------------
  
  class ParallelThreadsAvailableNode(AtomicExprNode):
      """
      Note: this is disabled and not a valid directive at this moment
  
      Implements cython.parallel.threadsavailable(). If we are called from the
      sequential part of the application, we need to call omp_get_max_threads(),
      and in the parallel part we can just call omp_get_num_threads()
      """
  
      type = PyrexTypes.c_int_type
  
      def analyse_types(self, env):
          self.is_temp = True
          # env.add_include_file("omp.h")
          return self
  
      def generate_result_code(self, code):
          code.putln("#ifdef _OPENMP")
          code.putln("if (omp_in_parallel()) %s = omp_get_max_threads();" %
                                                              self.temp_code)
          code.putln("else %s = omp_get_num_threads();" % self.temp_code)
          code.putln("#else")
          code.putln("%s = 1;" % self.temp_code)
          code.putln("#endif")
  
      def result(self):
          return self.temp_code
  
  
  class ParallelThreadIdNode(AtomicExprNode): #, Nodes.ParallelNode):
      """
      Implements cython.parallel.threadid()
      """
  
      type = PyrexTypes.c_int_type
  
      def analyse_types(self, env):
          self.is_temp = True
          # env.add_include_file("omp.h")
          return self
  
      def generate_result_code(self, code):
          code.putln("#ifdef _OPENMP")
          code.putln("%s = omp_get_thread_num();" % self.temp_code)
          code.putln("#else")
          code.putln("%s = 0;" % self.temp_code)
          code.putln("#endif")
  
      def result(self):
          return self.temp_code
  
  
  #-------------------------------------------------------------------
  #
  #  Trailer nodes
  #
  #-------------------------------------------------------------------
  
  class IndexNode(ExprNode):
      #  Sequence indexing.
      #
      #  base     ExprNode
      #  index    ExprNode
      #  indices  [ExprNode]
      #  type_indices  [PyrexType]
      #  is_buffer_access boolean Whether this is a buffer access.
      #
      #  indices is used on buffer access, index on non-buffer access.
      #  The former contains a clean list of index parameters, the
      #  latter whatever Python object is needed for index access.
      #
      #  is_fused_index boolean   Whether the index is used to specialize a
      #                           c(p)def function
  
      subexprs = ['base', 'index', 'indices']
      indices = None
      type_indices = None
  
      is_subscript = True
      is_fused_index = False
  
      # Whether we're assigning to a buffer (in that case it needs to be
      # writable)
      writable_needed = False
  
      # Whether we are indexing or slicing a memoryviewslice
      memslice_index = False
      memslice_slice = False
      is_memslice_copy = False
      memslice_ellipsis_noop = False
      warned_untyped_idx = False
      # set by SingleAssignmentNode after analyse_types()
      is_memslice_scalar_assignment = False
  
      def __init__(self, pos, index, **kw):
          ExprNode.__init__(self, pos, index=index, **kw)
          self._index = index
  
      def calculate_constant_result(self):
          self.constant_result = \
              self.base.constant_result[self.index.constant_result]
  
      def compile_time_value(self, denv):
          base = self.base.compile_time_value(denv)
          index = self.index.compile_time_value(denv)
          try:
              return base[index]
          except Exception, e:
              self.compile_time_value_error(e)
  
      def is_ephemeral(self):
          return self.base.is_ephemeral()
  
      def is_simple(self):
          if self.is_buffer_access or self.memslice_index:
              return False
          elif self.memslice_slice:
              return True
  
          base = self.base
          return (base.is_simple() and self.index.is_simple()
                  and base.type and (base.type.is_ptr or base.type.is_array))
  
      def may_be_none(self):
          base_type = self.base.type
          if base_type:
              if base_type.is_string:
                  return False
              if isinstance(self.index, SliceNode):
                  # slicing!
                  if base_type in (bytes_type, str_type, unicode_type,
                                   basestring_type, list_type, tuple_type):
                      return False
          return ExprNode.may_be_none(self)
  
      def analyse_target_declaration(self, env):
          pass
  
      def analyse_as_type(self, env):
          base_type = self.base.analyse_as_type(env)
          if base_type and not base_type.is_pyobject:
              if base_type.is_cpp_class:
                  if isinstance(self.index, TupleNode):
                      template_values = self.index.args
                  else:
                      template_values = [self.index]
                  import Nodes
                  type_node = Nodes.TemplatedTypeNode(
                      pos = self.pos,
                      positional_args = template_values,
                      keyword_args = None)
                  return type_node.analyse(env, base_type = base_type)
              else:
                  index = self.index.compile_time_value(env)
                  if index is not None:
                      return PyrexTypes.CArrayType(base_type, int(index))
                  error(self.pos, "Array size must be a compile time constant")
          return None
  
      def type_dependencies(self, env):
          return self.base.type_dependencies(env) + self.index.type_dependencies(env)
  
      def infer_type(self, env):
          base_type = self.base.infer_type(env)
          if isinstance(self.index, SliceNode):
              # slicing!
              if base_type.is_string:
                  # sliced C strings must coerce to Python
                  return bytes_type
              elif base_type.is_pyunicode_ptr:
                  # sliced Py_UNICODE* strings must coerce to Python
                  return unicode_type
              elif base_type in (unicode_type, bytes_type, str_type,
                                 bytearray_type, list_type, tuple_type):
                  # slicing these returns the same type
                  return base_type
              else:
                  # TODO: Handle buffers (hopefully without too much redundancy).
                  return py_object_type
  
          index_type = self.index.infer_type(env)
          if index_type and index_type.is_int or isinstance(self.index, IntNode):
              # indexing!
              if base_type is unicode_type:
                  # Py_UCS4 will automatically coerce to a unicode string
                  # if required, so this is safe.  We only infer Py_UCS4
                  # when the index is a C integer type.  Otherwise, we may
                  # need to use normal Python item access, in which case
                  # it's faster to return the one-char unicode string than
                  # to receive it, throw it away, and potentially rebuild it
                  # on a subsequent PyObject coercion.
                  return PyrexTypes.c_py_ucs4_type
              elif base_type is str_type:
                  # always returns str - Py2: bytes, Py3: unicode
                  return base_type
              elif base_type is bytearray_type:
                  return PyrexTypes.c_uchar_type
              elif isinstance(self.base, BytesNode):
                  #if env.global_scope().context.language_level >= 3:
                  #    # inferring 'char' can be made to work in Python 3 mode
                  #    return PyrexTypes.c_char_type
                  # Py2/3 return different types on indexing bytes objects
                  return py_object_type
              elif base_type in (tuple_type, list_type):
                  # if base is a literal, take a look at its values
                  item_type = infer_sequence_item_type(
                      env, self.base, self.index, seq_type=base_type)
                  if item_type is not None:
                      return item_type
              elif base_type.is_ptr or base_type.is_array:
                  return base_type.base_type
  
          if base_type.is_cpp_class:
              class FakeOperand:
                  def __init__(self, **kwds):
                      self.__dict__.update(kwds)
              operands = [
                  FakeOperand(pos=self.pos, type=base_type),
                  FakeOperand(pos=self.pos, type=index_type),
              ]
              index_func = env.lookup_operator('[]', operands)
              if index_func is not None:
                  return index_func.type.return_type
  
          # may be slicing or indexing, we don't know
          if base_type in (unicode_type, str_type):
              # these types always returns their own type on Python indexing/slicing
              return base_type
          else:
              # TODO: Handle buffers (hopefully without too much redundancy).
              return py_object_type
  
      def analyse_types(self, env):
          return self.analyse_base_and_index_types(env, getting=True)
  
      def analyse_target_types(self, env):
          node = self.analyse_base_and_index_types(env, setting=True)
          if node.type.is_const:
              error(self.pos, "Assignment to const dereference")
          if not node.is_lvalue():
              error(self.pos, "Assignment to non-lvalue of type '%s'" % node.type)
          return node
  
      def analyse_base_and_index_types(self, env, getting=False, setting=False,
                                       analyse_base=True):
          # Note: This might be cleaned up by having IndexNode
          # parsed in a saner way and only construct the tuple if
          # needed.
  
          # Note that this function must leave IndexNode in a cloneable state.
          # For buffers, self.index is packed out on the initial analysis, and
          # when cloning self.indices is copied.
          self.is_buffer_access = False
  
          # a[...] = b
          self.is_memslice_copy = False
          # incomplete indexing, Ellipsis indexing or slicing
          self.memslice_slice = False
          # integer indexing
          self.memslice_index = False
  
          if analyse_base:
              self.base = self.base.analyse_types(env)
  
          if self.base.type.is_error:
              # Do not visit child tree if base is undeclared to avoid confusing
              # error messages
              self.type = PyrexTypes.error_type
              return self
  
          is_slice = isinstance(self.index, SliceNode)
  
          if not env.directives['wraparound']:
              if is_slice:
                  check_negative_indices(self.index.start, self.index.stop)
              else:
                  check_negative_indices(self.index)
  
          # Potentially overflowing index value.
          if not is_slice and isinstance(self.index, IntNode) and Utils.long_literal(self.index.value):
              self.index = self.index.coerce_to_pyobject(env)
  
          is_memslice = self.base.type.is_memoryviewslice
  
          # Handle the case where base is a literal char* (and we expect a string, not an int)
          if not is_memslice and (isinstance(self.base, BytesNode) or is_slice):
              if self.base.type.is_string or not (self.base.type.is_ptr or self.base.type.is_array):
                  self.base = self.base.coerce_to_pyobject(env)
  
          skip_child_analysis = False
          buffer_access = False
  
          if self.indices:
              indices = self.indices
          elif isinstance(self.index, TupleNode):
              indices = self.index.args
          else:
              indices = [self.index]
  
          if (is_memslice and not self.indices and
                  isinstance(self.index, EllipsisNode)):
              # Memoryviewslice copying
              self.is_memslice_copy = True
  
          elif is_memslice:
              # memoryviewslice indexing or slicing
              import MemoryView
  
              skip_child_analysis = True
              newaxes = [newaxis for newaxis in indices if newaxis.is_none]
              have_slices, indices = MemoryView.unellipsify(indices,
                                                            newaxes,
                                                            self.base.type.ndim)
  
              self.memslice_index = (not newaxes and
                                     len(indices) == self.base.type.ndim)
              axes = []
  
              index_type = PyrexTypes.c_py_ssize_t_type
              new_indices = []
  
              if len(indices) - len(newaxes) > self.base.type.ndim:
                  self.type = error_type
                  error(indices[self.base.type.ndim].pos,
                        "Too many indices specified for type %s" %
                        self.base.type)
                  return self
  
              axis_idx = 0
              for i, index in enumerate(indices[:]):
                  index = index.analyse_types(env)
                  if not index.is_none:
                      access, packing = self.base.type.axes[axis_idx]
                      axis_idx += 1
  
                  if isinstance(index, SliceNode):
                      self.memslice_slice = True
                      if index.step.is_none:
                          axes.append((access, packing))
                      else:
                          axes.append((access, 'strided'))
  
                      # Coerce start, stop and step to temps of the right type
                      for attr in ('start', 'stop', 'step'):
                          value = getattr(index, attr)
                          if not value.is_none:
                              value = value.coerce_to(index_type, env)
                              #value = value.coerce_to_temp(env)
                              setattr(index, attr, value)
                              new_indices.append(value)
  
                  elif index.is_none:
                      self.memslice_slice = True
                      new_indices.append(index)
                      axes.append(('direct', 'strided'))
  
                  elif index.type.is_int or index.type.is_pyobject:
                      if index.type.is_pyobject and not self.warned_untyped_idx:
                          warning(index.pos, "Index should be typed for more "
                                             "efficient access", level=2)
                          IndexNode.warned_untyped_idx = True
  
                      self.memslice_index = True
                      index = index.coerce_to(index_type, env)
                      indices[i] = index
                      new_indices.append(index)
  
                  else:
                      self.type = error_type
                      error(index.pos, "Invalid index for memoryview specified")
                      return self
  
              self.memslice_index = self.memslice_index and not self.memslice_slice
              self.original_indices = indices
              # All indices with all start/stop/step for slices.
              # We need to keep this around
              self.indices = new_indices
              self.env = env
  
          elif self.base.type.is_buffer:
              # Buffer indexing
              if len(indices) == self.base.type.ndim:
                  buffer_access = True
                  skip_child_analysis = True
                  for x in indices:
                      x = x.analyse_types(env)
                      if not x.type.is_int:
                          buffer_access = False
  
              if buffer_access and not self.base.type.is_memoryviewslice:
                  assert hasattr(self.base, "entry") # Must be a NameNode-like node
  
          # On cloning, indices is cloned. Otherwise, unpack index into indices
          assert not (buffer_access and isinstance(self.index, CloneNode))
  
          self.nogil = env.nogil
  
          if buffer_access or self.memslice_index:
              #if self.base.type.is_memoryviewslice and not self.base.is_name:
              #    self.base = self.base.coerce_to_temp(env)
              self.base = self.base.coerce_to_simple(env)
  
              self.indices = indices
              self.index = None
              self.type = self.base.type.dtype
              self.is_buffer_access = True
              self.buffer_type = self.base.type #self.base.entry.type
  
              if getting and self.type.is_pyobject:
                  self.is_temp = True
  
              if setting and self.base.type.is_memoryviewslice:
                  self.base.type.writable_needed = True
              elif setting:
                  if not self.base.entry.type.writable:
                      error(self.pos, "Writing to readonly buffer")
                  else:
                      self.writable_needed = True
                      if self.base.type.is_buffer:
                          self.base.entry.buffer_aux.writable_needed = True
  
          elif self.is_memslice_copy:
              self.type = self.base.type
              if getting:
                  self.memslice_ellipsis_noop = True
              else:
                  self.memslice_broadcast = True
  
          elif self.memslice_slice:
              self.index = None
              self.is_temp = True
              self.use_managed_ref = True
  
              if not MemoryView.validate_axes(self.pos, axes):
                  self.type = error_type
                  return self
  
              self.type = PyrexTypes.MemoryViewSliceType(
                              self.base.type.dtype, axes)
  
              if (self.base.type.is_memoryviewslice and not
                      self.base.is_name and not
                      self.base.result_in_temp()):
                  self.base = self.base.coerce_to_temp(env)
  
              if setting:
                  self.memslice_broadcast = True
  
          else:
              base_type = self.base.type
  
              if not base_type.is_cfunction:
                  if isinstance(self.index, TupleNode):
                      self.index = self.index.analyse_types(
                          env, skip_children=skip_child_analysis)
                  elif not skip_child_analysis:
                      self.index = self.index.analyse_types(env)
                  self.original_index_type = self.index.type
  
              if base_type.is_unicode_char:
                  # we infer Py_UNICODE/Py_UCS4 for unicode strings in some
                  # cases, but indexing must still work for them
                  if setting:
                      warning(self.pos, "cannot assign to Unicode string index", level=1)
                  elif self.index.constant_result in (0, -1):
                      # uchar[0] => uchar
                      return self.base
                  self.base = self.base.coerce_to_pyobject(env)
                  base_type = self.base.type
              if base_type.is_pyobject:
                  if self.index.type.is_int and base_type is not dict_type:
                      if (getting
                          and (base_type in (list_type, tuple_type, bytearray_type))
                          and (not self.index.type.signed
                               or not env.directives['wraparound']
                               or (isinstance(self.index, IntNode) and
                                   self.index.has_constant_result() and self.index.constant_result >= 0))
                          and not env.directives['boundscheck']):
                          self.is_temp = 0
                      else:
                          self.is_temp = 1
                      self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env)
                      self.original_index_type.create_to_py_utility_code(env)
                  else:
                      self.index = self.index.coerce_to_pyobject(env)
                      self.is_temp = 1
                  if self.index.type.is_int and base_type is unicode_type:
                      # Py_UNICODE/Py_UCS4 will automatically coerce to a unicode string
                      # if required, so this is fast and safe
                      self.type = PyrexTypes.c_py_ucs4_type
                  elif self.index.type.is_int and base_type is bytearray_type:
                      if setting:
                          self.type = PyrexTypes.c_uchar_type
                      else:
                          # not using 'uchar' to enable fast and safe error reporting as '-1'
                          self.type = PyrexTypes.c_int_type
                  elif is_slice and base_type in (bytes_type, str_type, unicode_type, list_type, tuple_type):
                      self.type = base_type
                  else:
                      item_type = None
                      if base_type in (list_type, tuple_type) and self.index.type.is_int:
                          item_type = infer_sequence_item_type(
                              env, self.base, self.index, seq_type=base_type)
                      if item_type is None:
                          item_type = py_object_type
                      self.type = item_type
                      if base_type in (list_type, tuple_type, dict_type):
                          # do the None check explicitly (not in a helper) to allow optimising it away
                          self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable")
              else:
                  if base_type.is_ptr or base_type.is_array:
                      self.type = base_type.base_type
                      if is_slice:
                          self.type = base_type
                      elif self.index.type.is_pyobject:
                          self.index = self.index.coerce_to(
                              PyrexTypes.c_py_ssize_t_type, env)
                      elif not self.index.type.is_int:
                          error(self.pos,
                                "Invalid index type '%s'" %
                                self.index.type)
                  elif base_type.is_cpp_class:
                      function = env.lookup_operator("[]", [self.base, self.index])
                      if function is None:
                          error(self.pos, "Indexing '%s' not supported for index type '%s'" % (base_type, self.index.type))
                          self.type = PyrexTypes.error_type
                          self.result_code = "<error>"
                          return self
                      func_type = function.type
                      if func_type.is_ptr:
                          func_type = func_type.base_type
                      self.index = self.index.coerce_to(func_type.args[0].type, env)
                      self.type = func_type.return_type
                      if setting and not func_type.return_type.is_reference:
                          error(self.pos, "Can't set non-reference result '%s'" % self.type)
                  elif base_type.is_cfunction:
                      if base_type.is_fused:
                          self.parse_indexed_fused_cdef(env)
                      else:
                          self.type_indices = self.parse_index_as_types(env)
                          if base_type.templates is None:
                              error(self.pos, "Can only parameterize template functions.")
                          elif len(base_type.templates) != len(self.type_indices):
                              error(self.pos, "Wrong number of template arguments: expected %s, got %s" % (
                                      (len(base_type.templates), len(self.type_indices))))
                          self.type = base_type.specialize(dict(zip(base_type.templates, self.type_indices)))
                  else:
                      error(self.pos,
                            "Attempting to index non-array type '%s'" %
                            base_type)
                      self.type = PyrexTypes.error_type
  
          self.wrap_in_nonecheck_node(env, getting)
          return self
  
      def wrap_in_nonecheck_node(self, env, getting):
          if not env.directives['nonecheck'] or not self.base.may_be_none():
              return
  
          if self.base.type.is_memoryviewslice:
              if self.is_memslice_copy and not getting:
                  msg = "Cannot assign to None memoryview slice"
              elif self.memslice_slice:
                  msg = "Cannot slice None memoryview slice"
              else:
                  msg = "Cannot index None memoryview slice"
          else:
              msg = "'NoneType' object is not subscriptable"
  
          self.base = self.base.as_none_safe_node(msg)
  
      def parse_index_as_types(self, env, required=True):
          if isinstance(self.index, TupleNode):
              indices = self.index.args
          else:
              indices = [self.index]
          type_indices = []
          for index in indices:
              type_indices.append(index.analyse_as_type(env))
              if type_indices[-1] is None:
                  if required:
                      error(index.pos, "not parsable as a type")
                  return None
          return type_indices
  
      def parse_indexed_fused_cdef(self, env):
          """
          Interpret fused_cdef_func[specific_type1, ...]
  
          Note that if this method is called, we are an indexed cdef function
          with fused argument types, and this IndexNode will be replaced by the
          NameNode with specific entry just after analysis of expressions by
          AnalyseExpressionsTransform.
          """
          self.type = PyrexTypes.error_type
  
          self.is_fused_index = True
  
          base_type = self.base.type
          specific_types = []
          positions = []
  
          if self.index.is_name or self.index.is_attribute:
              positions.append(self.index.pos)
          elif isinstance(self.index, TupleNode):
              for arg in self.index.args:
                  positions.append(arg.pos)
          specific_types = self.parse_index_as_types(env, required=False)
  
          if specific_types is None:
              self.index = self.index.analyse_types(env)
  
              if not self.base.entry.as_variable:
                  error(self.pos, "Can only index fused functions with types")
              else:
                  # A cpdef function indexed with Python objects
                  self.base.entry = self.entry = self.base.entry.as_variable
                  self.base.type = self.type = self.entry.type
  
                  self.base.is_temp = True
                  self.is_temp = True
  
                  self.entry.used = True
  
              self.is_fused_index = False
              return
  
          for i, type in enumerate(specific_types):
              specific_types[i] = type.specialize_fused(env)
  
          fused_types = base_type.get_fused_types()
          if len(specific_types) > len(fused_types):
              return error(self.pos, "Too many types specified")
          elif len(specific_types) < len(fused_types):
              t = fused_types[len(specific_types)]
              return error(self.pos, "Not enough types specified to specialize "
                                     "the function, %s is still fused" % t)
  
          # See if our index types form valid specializations
          for pos, specific_type, fused_type in zip(positions,
                                                    specific_types,
                                                    fused_types):
              if not Utils.any([specific_type.same_as(t)
                                    for t in fused_type.types]):
                  return error(pos, "Type not in fused type")
  
              if specific_type is None or specific_type.is_error:
                  return
  
          fused_to_specific = dict(zip(fused_types, specific_types))
          type = base_type.specialize(fused_to_specific)
  
          if type.is_fused:
              # Only partially specific, this is invalid
              error(self.pos,
                    "Index operation makes function only partially specific")
          else:
              # Fully specific, find the signature with the specialized entry
              for signature in self.base.type.get_all_specialized_function_types():
                  if type.same_as(signature):
                      self.type = signature
  
                      if self.base.is_attribute:
                          # Pretend to be a normal attribute, for cdef extension
                          # methods
                          self.entry = signature.entry
                          self.is_attribute = True
                          self.obj = self.base.obj
  
                      self.type.entry.used = True
                      self.base.type = signature
                      self.base.entry = signature.entry
  
                      break
              else:
                  # This is a bug
                  raise InternalError("Couldn't find the right signature")
  
      gil_message = "Indexing Python object"
  
      def nogil_check(self, env):
          if self.is_buffer_access or self.memslice_index or self.memslice_slice:
              if not self.memslice_slice and env.directives['boundscheck']:
                  # error(self.pos, "Cannot check buffer index bounds without gil; "
                  #                 "use boundscheck(False) directive")
                  warning(self.pos, "Use boundscheck(False) for faster access",
                          level=1)
              if self.type.is_pyobject:
                  error(self.pos, "Cannot access buffer with object dtype without gil")
                  return
          super(IndexNode, self).nogil_check(env)
  
  
      def check_const_addr(self):
          return self.base.check_const_addr() and self.index.check_const()
  
      def is_lvalue(self):
          # NOTE: references currently have both is_reference and is_ptr
          # set.  Since pointers and references have different lvalue
          # rules, we must be careful to separate the two.
          if self.type.is_reference:
              if self.type.ref_base_type.is_array:
                  # fixed-sized arrays aren't l-values
                  return False
          elif self.type.is_ptr:
              # non-const pointers can always be reassigned
              return True
          elif self.type.is_array:
              # fixed-sized arrays aren't l-values
              return False
          # Just about everything else returned by the index operator
          # can be an lvalue.
          return True
  
      def calculate_result_code(self):
          if self.is_buffer_access:
              return "(*%s)" % self.buffer_ptr_code
          elif self.is_memslice_copy:
              return self.base.result()
          elif self.base.type in (list_type, tuple_type, bytearray_type):
              if self.base.type is list_type:
                  index_code = "PyList_GET_ITEM(%s, %s)"
              elif self.base.type is tuple_type:
                  index_code = "PyTuple_GET_ITEM(%s, %s)"
              elif self.base.type is bytearray_type:
                  index_code = "((unsigned char)(PyByteArray_AS_STRING(%s)[%s]))"
              else:
                  assert False, "unexpected base type in indexing: %s" % self.base.type
          elif self.base.type.is_cfunction:
              return "%s<%s>" % (
                  self.base.result(),
                  ",".join([param.declaration_code("") for param in self.type_indices]))
          else:
              if (self.type.is_ptr or self.type.is_array) and self.type == self.base.type:
                  error(self.pos, "Invalid use of pointer slice")
                  return
              index_code = "(%s[%s])"
          return index_code % (self.base.result(), self.index.result())
  
      def extra_index_params(self, code):
          if self.index.type.is_int:
              is_list = self.base.type is list_type
              wraparound = (
                  bool(code.globalstate.directives['wraparound']) and
                  self.original_index_type.signed and
                  not (isinstance(self.index.constant_result, (int, long))
                       and self.index.constant_result >= 0))
              boundscheck = bool(code.globalstate.directives['boundscheck'])
              return ", %s, %d, %s, %d, %d, %d" % (
                  self.original_index_type.declaration_code(""),
                  self.original_index_type.signed and 1 or 0,
                  self.original_index_type.to_py_function,
                  is_list, wraparound, boundscheck)
          else:
              return ""
  
      def generate_subexpr_evaluation_code(self, code):
          self.base.generate_evaluation_code(code)
          if self.type_indices is not None:
              pass
          elif self.indices is None:
              self.index.generate_evaluation_code(code)
          else:
              for i in self.indices:
                  i.generate_evaluation_code(code)
  
      def generate_subexpr_disposal_code(self, code):
          self.base.generate_disposal_code(code)
          if self.type_indices is not None:
              pass
          elif self.indices is None:
              self.index.generate_disposal_code(code)
          else:
              for i in self.indices:
                  i.generate_disposal_code(code)
  
      def free_subexpr_temps(self, code):
          self.base.free_temps(code)
          if self.indices is None:
              self.index.free_temps(code)
          else:
              for i in self.indices:
                  i.free_temps(code)
  
      def generate_result_code(self, code):
          if self.is_buffer_access or self.memslice_index:
              buffer_entry, self.buffer_ptr_code = self.buffer_lookup_code(code)
              if self.type.is_pyobject:
                  # is_temp is True, so must pull out value and incref it.
                  # NOTE: object temporary results for nodes are declared
                  #       as PyObject *, so we need a cast
                  code.putln("%s = (PyObject *) *%s;" % (self.temp_code,
                                                         self.buffer_ptr_code))
                  code.putln("__Pyx_INCREF((PyObject*)%s);" % self.temp_code)
  
          elif self.memslice_slice:
              self.put_memoryviewslice_slice_code(code)
  
          elif self.is_temp:
              if self.type.is_pyobject:
                  error_value = 'NULL'
                  if self.index.type.is_int:
                      if self.base.type is list_type:
                          function = "__Pyx_GetItemInt_List"
                      elif self.base.type is tuple_type:
                          function = "__Pyx_GetItemInt_Tuple"
                      else:
                          function = "__Pyx_GetItemInt"
                      code.globalstate.use_utility_code(
                          TempitaUtilityCode.load_cached("GetItemInt", "ObjectHandling.c"))
                  else:
                      if self.base.type is dict_type:
                          function = "__Pyx_PyDict_GetItem"
                          code.globalstate.use_utility_code(
                              UtilityCode.load_cached("DictGetItem", "ObjectHandling.c"))
                      else:
                          function = "PyObject_GetItem"
              elif self.type.is_unicode_char and self.base.type is unicode_type:
                  assert self.index.type.is_int
                  function = "__Pyx_GetItemInt_Unicode"
                  error_value = '(Py_UCS4)-1'
                  code.globalstate.use_utility_code(
                      UtilityCode.load_cached("GetItemIntUnicode", "StringTools.c"))
              elif self.base.type is bytearray_type:
                  assert self.index.type.is_int
                  assert self.type.is_int
                  function = "__Pyx_GetItemInt_ByteArray"
                  error_value = '-1'
                  code.globalstate.use_utility_code(
                      UtilityCode.load_cached("GetItemIntByteArray", "StringTools.c"))
              else:
                  assert False, "unexpected type %s and base type %s for indexing" % (
                      self.type, self.base.type)
  
              if self.index.type.is_int:
                  index_code = self.index.result()
              else:
                  index_code = self.index.py_result()
  
              code.putln(
                  "%s = %s(%s, %s%s); if (unlikely(%s == %s)) %s;" % (
                      self.result(),
                      function,
                      self.base.py_result(),
                      index_code,
                      self.extra_index_params(code),
                      self.result(),
                      error_value,
                      code.error_goto(self.pos)))
              if self.type.is_pyobject:
                  code.put_gotref(self.py_result())
  
      def generate_setitem_code(self, value_code, code):
          if self.index.type.is_int:
              if self.base.type is bytearray_type:
                  code.globalstate.use_utility_code(
                      UtilityCode.load_cached("SetItemIntByteArray", "StringTools.c"))
                  function = "__Pyx_SetItemInt_ByteArray"
              else:
                  code.globalstate.use_utility_code(
                      UtilityCode.load_cached("SetItemInt", "ObjectHandling.c"))
                  function = "__Pyx_SetItemInt"
              index_code = self.index.result()
          else:
              index_code = self.index.py_result()
              if self.base.type is dict_type:
                  function = "PyDict_SetItem"
              # It would seem that we could specialized lists/tuples, but that
              # shouldn't happen here.
              # Both PyList_SetItem() and PyTuple_SetItem() take a Py_ssize_t as
              # index instead of an object, and bad conversion here would give
              # the wrong exception. Also, tuples are supposed to be immutable,
              # and raise a TypeError when trying to set their entries
              # (PyTuple_SetItem() is for creating new tuples from scratch).
              else:
                  function = "PyObject_SetItem"
          code.putln(
              "if (unlikely(%s(%s, %s, %s%s) < 0)) %s" % (
                  function,
                  self.base.py_result(),
                  index_code,
                  value_code,
                  self.extra_index_params(code),
                  code.error_goto(self.pos)))
  
      def generate_buffer_setitem_code(self, rhs, code, op=""):
          # Used from generate_assignment_code and InPlaceAssignmentNode
          buffer_entry, ptrexpr = self.buffer_lookup_code(code)
  
          if self.buffer_type.dtype.is_pyobject:
              # Must manage refcounts. Decref what is already there
              # and incref what we put in.
              ptr = code.funcstate.allocate_temp(buffer_entry.buf_ptr_type,
                                                 manage_ref=False)
              rhs_code = rhs.result()
              code.putln("%s = %s;" % (ptr, ptrexpr))
              code.put_gotref("*%s" % ptr)
              code.putln("__Pyx_INCREF(%s); __Pyx_DECREF(*%s);" % (
                  rhs_code, ptr))
              code.putln("*%s %s= %s;" % (ptr, op, rhs_code))
              code.put_giveref("*%s" % ptr)
              code.funcstate.release_temp(ptr)
          else:
              # Simple case
              code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result()))
  
      def generate_assignment_code(self, rhs, code):
          generate_evaluation_code = (self.is_memslice_scalar_assignment or
                                      self.memslice_slice)
          if generate_evaluation_code:
              self.generate_evaluation_code(code)
          else:
              self.generate_subexpr_evaluation_code(code)
  
          if self.is_buffer_access or self.memslice_index:
              self.generate_buffer_setitem_code(rhs, code)
          elif self.is_memslice_scalar_assignment:
              self.generate_memoryviewslice_assign_scalar_code(rhs, code)
          elif self.memslice_slice or self.is_memslice_copy:
              self.generate_memoryviewslice_setslice_code(rhs, code)
          elif self.type.is_pyobject:
              self.generate_setitem_code(rhs.py_result(), code)
          elif self.base.type is bytearray_type:
              value_code = self._check_byte_value(code, rhs)
              self.generate_setitem_code(value_code, code)
          else:
              code.putln(
                  "%s = %s;" % (
                      self.result(), rhs.result()))
  
          if generate_evaluation_code:
              self.generate_disposal_code(code)
          else:
              self.generate_subexpr_disposal_code(code)
              self.free_subexpr_temps(code)
  
          rhs.generate_disposal_code(code)
          rhs.free_temps(code)
  
      def _check_byte_value(self, code, rhs):
          # TODO: should we do this generally on downcasts, or just here?
          assert rhs.type.is_int, repr(rhs.type)
          value_code = rhs.result()
          if rhs.has_constant_result():
              if 0 <= rhs.constant_result < 256:
                  return value_code
              needs_cast = True  # make at least the C compiler happy
              warning(rhs.pos,
                      "value outside of range(0, 256)"
                      " when assigning to byte: %s" % rhs.constant_result,
                      level=1)
          else:
              needs_cast = rhs.type != PyrexTypes.c_uchar_type
  
          if not self.nogil:
              conditions = []
              if rhs.is_literal or rhs.type.signed:
                  conditions.append('%s < 0' % value_code)
              if (rhs.is_literal or not
                      (rhs.is_temp and rhs.type in (
                          PyrexTypes.c_uchar_type, PyrexTypes.c_char_type,
                          PyrexTypes.c_schar_type))):
                  conditions.append('%s > 255' % value_code)
              if conditions:
                  code.putln("if (unlikely(%s)) {" % ' || '.join(conditions))
                  code.putln(
                      'PyErr_SetString(PyExc_ValueError,'
                      ' "byte must be in range(0, 256)"); %s' %
                      code.error_goto(self.pos))
                  code.putln("}")
  
          if needs_cast:
              value_code = '((unsigned char)%s)' % value_code
          return value_code
  
      def generate_deletion_code(self, code, ignore_nonexisting=False):
          self.generate_subexpr_evaluation_code(code)
          #if self.type.is_pyobject:
          if self.index.type.is_int:
              function = "__Pyx_DelItemInt"
              index_code = self.index.result()
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("DelItemInt", "ObjectHandling.c"))
          else:
              index_code = self.index.py_result()
              if self.base.type is dict_type:
                  function = "PyDict_DelItem"
              else:
                  function = "PyObject_DelItem"
          code.putln(
              "if (%s(%s, %s%s) < 0) %s" % (
                  function,
                  self.base.py_result(),
                  index_code,
                  self.extra_index_params(code),
                  code.error_goto(self.pos)))
          self.generate_subexpr_disposal_code(code)
          self.free_subexpr_temps(code)
  
      def buffer_entry(self):
          import Buffer, MemoryView
  
          base = self.base
          if self.base.is_nonecheck:
              base = base.arg
  
          if base.is_name:
              entry = base.entry
          else:
              # SimpleCallNode is_simple is not consistent with coerce_to_simple
              assert base.is_simple() or base.is_temp
              cname = base.result()
              entry = Symtab.Entry(cname, cname, self.base.type, self.base.pos)
  
          if entry.type.is_buffer:
              buffer_entry = Buffer.BufferEntry(entry)
          else:
              buffer_entry = MemoryView.MemoryViewSliceBufferEntry(entry)
  
          return buffer_entry
  
      def buffer_lookup_code(self, code):
          "ndarray[1, 2, 3] and memslice[1, 2, 3]"
          # Assign indices to temps
          index_temps = [code.funcstate.allocate_temp(i.type, manage_ref=False)
                             for i in self.indices]
  
          for temp, index in zip(index_temps, self.indices):
              code.putln("%s = %s;" % (temp, index.result()))
  
          # Generate buffer access code using these temps
          import Buffer
          buffer_entry = self.buffer_entry()
          if buffer_entry.type.is_buffer:
              negative_indices = buffer_entry.type.negative_indices
          else:
              negative_indices = Buffer.buffer_defaults['negative_indices']
  
          return buffer_entry, Buffer.put_buffer_lookup_code(
                 entry=buffer_entry,
                 index_signeds=[i.type.signed for i in self.indices],
                 index_cnames=index_temps,
                 directives=code.globalstate.directives,
                 pos=self.pos, code=code,
                 negative_indices=negative_indices,
                 in_nogil_context=self.in_nogil_context)
  
      def put_memoryviewslice_slice_code(self, code):
          "memslice[:]"
          buffer_entry = self.buffer_entry()
          have_gil = not self.in_nogil_context
  
          if sys.version_info < (3,):
              def next_(it):
                  return it.next()
          else:
              next_ = next
  
          have_slices = False
          it = iter(self.indices)
          for index in self.original_indices:
              is_slice = isinstance(index, SliceNode)
              have_slices = have_slices or is_slice
              if is_slice:
                  if not index.start.is_none:
                      index.start = next_(it)
                  if not index.stop.is_none:
                      index.stop = next_(it)
                  if not index.step.is_none:
                      index.step = next_(it)
              else:
                  next_(it)
  
          assert not list(it)
  
          buffer_entry.generate_buffer_slice_code(code, self.original_indices,
                                                  self.result(),
                                                  have_gil=have_gil,
                                                  have_slices=have_slices,
                                                  directives=code.globalstate.directives)
  
      def generate_memoryviewslice_setslice_code(self, rhs, code):
          "memslice1[...] = memslice2 or memslice1[:] = memslice2"
          import MemoryView
          MemoryView.copy_broadcast_memview_src_to_dst(rhs, self, code)
  
      def generate_memoryviewslice_assign_scalar_code(self, rhs, code):
          "memslice1[...] = 0.0 or memslice1[:] = 0.0"
          import MemoryView
          MemoryView.assign_scalar(self, rhs, code)
  
  
  class SliceIndexNode(ExprNode):
      #  2-element slice indexing
      #
      #  base      ExprNode
      #  start     ExprNode or None
      #  stop      ExprNode or None
      #  slice     ExprNode or None   constant slice object
  
      subexprs = ['base', 'start', 'stop', 'slice']
  
      slice = None
  
      def infer_type(self, env):
          base_type = self.base.infer_type(env)
          if base_type.is_string or base_type.is_cpp_class:
              return bytes_type
          elif base_type.is_pyunicode_ptr:
              return unicode_type
          elif base_type in (bytes_type, str_type, unicode_type,
                             basestring_type, list_type, tuple_type):
              return base_type
          elif base_type.is_ptr or base_type.is_array:
              return PyrexTypes.c_array_type(base_type.base_type, None)
          return py_object_type
  
      def may_be_none(self):
          base_type = self.base.type
          if base_type:
              if base_type.is_string:
                  return False
              if base_type in (bytes_type, str_type, unicode_type,
                               basestring_type, list_type, tuple_type):
                  return False
          return ExprNode.may_be_none(self)
  
      def calculate_constant_result(self):
          if self.start is None:
              start = None
          else:
              start = self.start.constant_result
          if self.stop is None:
              stop = None
          else:
              stop = self.stop.constant_result
          self.constant_result = self.base.constant_result[start:stop]
  
      def compile_time_value(self, denv):
          base = self.base.compile_time_value(denv)
          if self.start is None:
              start = 0
          else:
              start = self.start.compile_time_value(denv)
          if self.stop is None:
              stop = None
          else:
              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_target_types(self, env):
          node = self.analyse_types(env, getting=False)
          # when assigning, we must accept any Python type
          if node.type.is_pyobject:
              node.type = py_object_type
          return node
  
      def analyse_types(self, env, getting=True):
          self.base = self.base.analyse_types(env)
  
          if self.base.type.is_memoryviewslice:
              none_node = NoneNode(self.pos)
              index = SliceNode(self.pos,
                                start=self.start or none_node,
                                stop=self.stop or none_node,
                                step=none_node)
              index_node = IndexNode(self.pos, index, base=self.base)
              return index_node.analyse_base_and_index_types(
                  env, getting=getting, setting=not getting,
                  analyse_base=False)
  
          if self.start:
              self.start = self.start.analyse_types(env)
          if self.stop:
              self.stop = self.stop.analyse_types(env)
  
          if not env.directives['wraparound']:
              check_negative_indices(self.start, self.stop)
  
          base_type = self.base.type
          if base_type.is_string or base_type.is_cpp_string:
              self.type = default_str_type(env)
          elif base_type.is_pyunicode_ptr:
              self.type = unicode_type
          elif base_type.is_ptr:
              self.type = base_type
          elif base_type.is_array:
              # we need a ptr type here instead of an array type, as
              # array types can result in invalid type casts in the C
              # code
              self.type = PyrexTypes.CPtrType(base_type.base_type)
          else:
              self.base = self.base.coerce_to_pyobject(env)
              self.type = py_object_type
          if base_type.is_builtin_type:
              # slicing builtin types returns something of the same type
              self.type = base_type
              self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable")
  
          if self.type is py_object_type:
              if (not self.start or self.start.is_literal) and \
                      (not self.stop or self.stop.is_literal):
                  # cache the constant slice object, in case we need it
                  none_node = NoneNode(self.pos)
                  self.slice = SliceNode(
                      self.pos,
                      start=copy.deepcopy(self.start or none_node),
                      stop=copy.deepcopy(self.stop or none_node),
                      step=none_node
                  ).analyse_types(env)
          else:
              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.is_temp = 1
          return self
  
      nogil_check = Node.gil_error
      gil_message = "Slicing Python object"
  
      get_slice_utility_code = TempitaUtilityCode.load(
          "SliceObject", "ObjectHandling.c", context={'access': 'Get'})
  
      set_slice_utility_code = TempitaUtilityCode.load(
          "SliceObject", "ObjectHandling.c", context={'access': 'Set'})
  
      def coerce_to(self, dst_type, env):
          if ((self.base.type.is_string or self.base.type.is_cpp_string)
                  and dst_type in (bytes_type, bytearray_type, str_type, unicode_type)):
              if (dst_type not in (bytes_type, bytearray_type)
                      and not env.directives['c_string_encoding']):
                  error(self.pos,
                      "default encoding required for conversion from '%s' to '%s'" %
                      (self.base.type, dst_type))
              self.type = dst_type
          return super(SliceIndexNode, self).coerce_to(dst_type, env)
  
      def generate_result_code(self, code):
          if not self.type.is_pyobject:
              error(self.pos,
                    "Slicing is not currently supported for '%s'." % self.type)
              return
  
          base_result = self.base.result()
          result = self.result()
          start_code = self.start_code()
          stop_code = self.stop_code()
          if self.base.type.is_string:
              base_result = self.base.result()
              if self.base.type != PyrexTypes.c_char_ptr_type:
                  base_result = '((const char*)%s)' % base_result
              if self.type is bytearray_type:
                  type_name = 'ByteArray'
              else:
                  type_name = self.type.name.title()
              if self.stop is None:
                  code.putln(
                      "%s = __Pyx_Py%s_FromString(%s + %s); %s" % (
                          result,
                          type_name,
                          base_result,
                          start_code,
                          code.error_goto_if_null(result, self.pos)))
              else:
                  code.putln(
                      "%s = __Pyx_Py%s_FromStringAndSize(%s + %s, %s - %s); %s" % (
                          result,
                          type_name,
                          base_result,
                          start_code,
                          stop_code,
                          start_code,
                          code.error_goto_if_null(result, self.pos)))
          elif self.base.type.is_pyunicode_ptr:
              base_result = self.base.result()
              if self.base.type != PyrexTypes.c_py_unicode_ptr_type:
                  base_result = '((const Py_UNICODE*)%s)' % base_result
              if self.stop is None:
                  code.putln(
                      "%s = __Pyx_PyUnicode_FromUnicode(%s + %s); %s" % (
                          result,
                          base_result,
                          start_code,
                          code.error_goto_if_null(result, self.pos)))
              else:
                  code.putln(
                      "%s = __Pyx_PyUnicode_FromUnicodeAndLength(%s + %s, %s - %s); %s" % (
                          result,
                          base_result,
                          start_code,
                          stop_code,
                          start_code,
                          code.error_goto_if_null(result, self.pos)))
  
          elif self.base.type is unicode_type:
              code.globalstate.use_utility_code(
                            UtilityCode.load_cached("PyUnicode_Substring", "StringTools.c"))
              code.putln(
                  "%s = __Pyx_PyUnicode_Substring(%s, %s, %s); %s" % (
                      result,
                      base_result,
                      start_code,
                      stop_code,
                      code.error_goto_if_null(result, self.pos)))
          elif self.type is py_object_type:
              code.globalstate.use_utility_code(self.get_slice_utility_code)
              (has_c_start, has_c_stop, c_start, c_stop,
               py_start, py_stop, py_slice) = self.get_slice_config()
              code.putln(
                  "%s = __Pyx_PyObject_GetSlice(%s, %s, %s, %s, %s, %s, %d, %d, %d); %s" % (
                      result,
                      self.base.py_result(),
                      c_start, c_stop,
                      py_start, py_stop, py_slice,
                      has_c_start, has_c_stop,
                      bool(code.globalstate.directives['wraparound']),
                      code.error_goto_if_null(result, self.pos)))
          else:
              if self.base.type is list_type:
                  code.globalstate.use_utility_code(
                      TempitaUtilityCode.load_cached("SliceTupleAndList", "ObjectHandling.c"))
                  cfunc = '__Pyx_PyList_GetSlice'
              elif self.base.type is tuple_type:
                  code.globalstate.use_utility_code(
                      TempitaUtilityCode.load_cached("SliceTupleAndList", "ObjectHandling.c"))
                  cfunc = '__Pyx_PyTuple_GetSlice'
              else:
                  cfunc = '__Pyx_PySequence_GetSlice'
              code.putln(
                  "%s = %s(%s, %s, %s); %s" % (
                      result,
                      cfunc,
                      self.base.py_result(),
                      start_code,
                      stop_code,
                      code.error_goto_if_null(result, self.pos)))
          code.put_gotref(self.py_result())
  
      def generate_assignment_code(self, rhs, code):
          self.generate_subexpr_evaluation_code(code)
          if self.type.is_pyobject:
              code.globalstate.use_utility_code(self.set_slice_utility_code)
              (has_c_start, has_c_stop, c_start, c_stop,
               py_start, py_stop, py_slice) = self.get_slice_config()
              code.put_error_if_neg(self.pos,
                  "__Pyx_PyObject_SetSlice(%s, %s, %s, %s, %s, %s, %s, %d, %d, %d)" % (
                      self.base.py_result(),
                      rhs.py_result(),
                      c_start, c_stop,
                      py_start, py_stop, py_slice,
                      has_c_start, has_c_stop,
                      bool(code.globalstate.directives['wraparound'])))
          else:
              start_offset = ''
              if self.start:
                  start_offset = self.start_code()
                  if start_offset == '0':
                      start_offset = ''
                  else:
                      start_offset += '+'
              if rhs.type.is_array:
                  array_length = rhs.type.size
                  self.generate_slice_guard_code(code, array_length)
              else:
                  error(self.pos,
                        "Slice assignments from pointers are not yet supported.")
                  # FIXME: fix the array size according to start/stop
                  array_length = self.base.type.size
              for i in range(array_length):
                  code.putln("%s[%s%s] = %s[%d];" % (
                          self.base.result(), start_offset, i,
                          rhs.result(), i))
          self.generate_subexpr_disposal_code(code)
          self.free_subexpr_temps(code)
          rhs.generate_disposal_code(code)
          rhs.free_temps(code)
  
      def generate_deletion_code(self, code, ignore_nonexisting=False):
          if not self.base.type.is_pyobject:
              error(self.pos,
                    "Deleting slices is only supported for Python types, not '%s'." % self.type)
              return
          self.generate_subexpr_evaluation_code(code)
          code.globalstate.use_utility_code(self.set_slice_utility_code)
          (has_c_start, has_c_stop, c_start, c_stop,
           py_start, py_stop, py_slice) = self.get_slice_config()
          code.put_error_if_neg(self.pos,
              "__Pyx_PyObject_DelSlice(%s, %s, %s, %s, %s, %s, %d, %d, %d)" % (
                  self.base.py_result(),
                  c_start, c_stop,
                  py_start, py_stop, py_slice,
                  has_c_start, has_c_stop,
                  bool(code.globalstate.directives['wraparound'])))
          self.generate_subexpr_disposal_code(code)
          self.free_subexpr_temps(code)
  
      def get_slice_config(self):
          has_c_start, c_start, py_start = False, '0', 'NULL'
          if self.start:
              has_c_start = not self.start.type.is_pyobject
              if has_c_start:
                  c_start = self.start.result()
              else:
                  py_start = '&%s' % self.start.py_result()
          has_c_stop, c_stop, py_stop = False, '0', 'NULL'
          if self.stop:
              has_c_stop = not self.stop.type.is_pyobject
              if has_c_stop:
                  c_stop = self.stop.result()
              else:
                  py_stop = '&%s' % self.stop.py_result()
          py_slice = self.slice and '&%s' % self.slice.py_result() or 'NULL'
          return (has_c_start, has_c_stop, c_start, c_stop,
                  py_start, py_stop, py_slice)
  
      def generate_slice_guard_code(self, code, target_size):
          if not self.base.type.is_array:
              return
          slice_size = self.base.type.size
          start = stop = None
          if self.stop:
              stop = self.stop.result()
              try:
                  stop = int(stop)
                  if stop < 0:
                      slice_size = self.base.type.size + stop
                  else:
                      slice_size = stop
                  stop = None
              except ValueError:
                  pass
          if self.start:
              start = self.start.result()
              try:
                  start = int(start)
                  if start < 0:
                      start = self.base.type.size + start
                  slice_size -= start
                  start = None
              except ValueError:
                  pass
          check = None
          if slice_size < 0:
              if target_size > 0:
                  error(self.pos, "Assignment to empty slice.")
          elif start is None and stop is None:
              # we know the exact slice length
              if target_size != slice_size:
                  error(self.pos, "Assignment to slice of wrong length, expected %d, got %d" % (
                          slice_size, target_size))
          elif start is not None:
              if stop is None:
                  stop = slice_size
              check = "(%s)-(%s)" % (stop, start)
          else: # stop is not None:
              check = stop
          if check:
              code.putln("if (unlikely((%s) != %d)) {" % (check, target_size))
              code.putln('PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length, expected %%" CYTHON_FORMAT_SSIZE_T "d, got %%" CYTHON_FORMAT_SSIZE_T "d", (Py_ssize_t)%d, (Py_ssize_t)(%s));' % (
                          target_size, check))
              code.putln(code.error_goto(self.pos))
              code.putln("}")
  
      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()
          elif self.base.type.is_array:
              return self.base.type.size
          else:
              return "PY_SSIZE_T_MAX"
  
      def calculate_result_code(self):
          # self.result() 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
  
      subexprs = ['start', 'stop', 'step']
  
      type = slice_type
      is_temp = 1
  
      def calculate_constant_result(self):
          self.constant_result = slice(
              self.start.constant_result,
              self.stop.constant_result,
              self.step.constant_result)
  
      def compile_time_value(self, denv):
          start = self.start.compile_time_value(denv)
          stop = self.stop.compile_time_value(denv)
          step = self.step.compile_time_value(denv)
          try:
              return slice(start, stop, step)
          except Exception, e:
              self.compile_time_value_error(e)
  
      def may_be_none(self):
          return False
  
      def analyse_types(self, env):
          start = self.start.analyse_types(env)
          stop = self.stop.analyse_types(env)
          step = self.step.analyse_types(env)
          self.start = start.coerce_to_pyobject(env)
          self.stop = stop.coerce_to_pyobject(env)
          self.step = step.coerce_to_pyobject(env)
          if self.start.is_literal and self.stop.is_literal and self.step.is_literal:
              self.is_literal = True
              self.is_temp = False
          return self
  
      gil_message = "Constructing Python slice object"
  
      def calculate_result_code(self):
          return self.result_code
  
      def generate_result_code(self, code):
          if self.is_literal:
              self.result_code = code.get_py_const(py_object_type, 'slice', cleanup_level=2)
              code = code.get_cached_constants_writer()
              code.mark_pos(self.pos)
  
          code.putln(
              "%s = PySlice_New(%s, %s, %s); %s" % (
                  self.result(),
                  self.start.py_result(),
                  self.stop.py_result(),
                  self.step.py_result(),
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
          if self.is_literal:
              code.put_giveref(self.py_result())
  
      def __deepcopy__(self, memo):
          """
          There is a copy bug in python 2.4 for slice objects.
          """
          return SliceNode(
              self.pos,
              start=copy.deepcopy(self.start, memo),
              stop=copy.deepcopy(self.stop, memo),
              step=copy.deepcopy(self.step, memo),
              is_temp=self.is_temp,
              is_literal=self.is_literal,
              constant_result=self.constant_result)
  
  
  class CallNode(ExprNode):
  
      # allow overriding the default 'may_be_none' behaviour
      may_return_none = None
  
      def infer_type(self, env):
          function = self.function
          func_type = function.infer_type(env)
          if isinstance(function, NewExprNode):
              # note: needs call to infer_type() above
              return PyrexTypes.CPtrType(function.class_type)
          if func_type is py_object_type:
              # function might have lied for safety => try to find better type
              entry = getattr(function, 'entry', None)
              if entry is not None:
                  func_type = entry.type or func_type
          if func_type.is_ptr:
              func_type = func_type.base_type
          if func_type.is_cfunction:
              return func_type.return_type
          elif func_type is type_type:
              if function.is_name and function.entry and function.entry.type:
                  result_type = function.entry.type
                  if result_type.is_extension_type:
                      return result_type
                  elif result_type.is_builtin_type:
                      if function.entry.name == 'float':
                          return PyrexTypes.c_double_type
                      elif function.entry.name in Builtin.types_that_construct_their_instance:
                          return result_type
          return py_object_type
  
      def type_dependencies(self, env):
          # TODO: Update when Danilo's C++ code merged in to handle the
          # the case of function overloading.
          return self.function.type_dependencies(env)
  
      def is_simple(self):
          # C function calls could be considered simple, but they may
          # have side-effects that may hit when multiple operations must
          # be effected in order, e.g. when constructing the argument
          # sequence for a function call or comparing values.
          return False
  
      def may_be_none(self):
          if self.may_return_none is not None:
              return self.may_return_none
          func_type = self.function.type
          if func_type is type_type and self.function.is_name:
              entry = self.function.entry
              if entry.type.is_extension_type:
                  return False
              if (entry.type.is_builtin_type and
                      entry.name in Builtin.types_that_construct_their_instance):
                  return False
          return ExprNode.may_be_none(self)
  
      def analyse_as_type_constructor(self, env):
          type = self.function.analyse_as_type(env)
          if type and type.is_struct_or_union:
              args, kwds = self.explicit_args_kwds()
              items = []
              for arg, member in zip(args, type.scope.var_entries):
                  items.append(DictItemNode(pos=arg.pos, key=StringNode(pos=arg.pos, value=member.name), value=arg))
              if kwds:
                  items += kwds.key_value_pairs
              self.key_value_pairs = items
              self.__class__ = DictNode
              self.analyse_types(env)    # FIXME
              self.coerce_to(type, env)
              return True
          elif type and type.is_cpp_class:
              self.args = [ arg.analyse_types(env) for arg in self.args ]
              constructor = type.scope.lookup("<init>")
              self.function = RawCNameExprNode(self.function.pos, constructor.type)
              self.function.entry = constructor
              self.function.set_cname(type.declaration_code(""))
              self.analyse_c_function_call(env)
              self.type = type
              return True
  
      def is_lvalue(self):
          return self.type.is_reference
  
      def nogil_check(self, env):
          func_type = self.function_type()
          if func_type.is_pyobject:
              self.gil_error()
          elif not getattr(func_type, 'nogil', False):
              self.gil_error()
  
      gil_message = "Calling gil-requiring function"
  
  
  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
      #  wrapper_call   bool                 used internally
      #  has_optional_args   bool            used internally
      #  nogil          bool                 used internally
  
      subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple']
  
      self = None
      coerced_self = None
      arg_tuple = None
      wrapper_call = False
      has_optional_args = False
      nogil = False
      analysed = False
  
      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_as_type(self, env):
          attr = self.function.as_cython_attribute()
          if attr == 'pointer':
              if len(self.args) != 1:
                  error(self.args.pos, "only one type allowed.")
              else:
                  type = self.args[0].analyse_as_type(env)
                  if not type:
                      error(self.args[0].pos, "Unknown type")
                  else:
                      return PyrexTypes.CPtrType(type)
  
      def explicit_args_kwds(self):
          return self.args, None
  
      def analyse_types(self, env):
          if self.analyse_as_type_constructor(env):
              return self
          if self.analysed:
              return self
          self.analysed = True
          self.function.is_called = 1
          self.function = self.function.analyse_types(env)
          function = self.function
  
          if function.is_attribute and function.entry and function.entry.is_cmethod:
              # Take ownership of the object from which the attribute
              # was obtained, because we need to pass it as 'self'.
              self.self = function.obj
              function.obj = CloneNode(self.self)
  
          func_type = self.function_type()
          if func_type.is_pyobject:
              self.arg_tuple = TupleNode(self.pos, args = self.args)
              self.arg_tuple = self.arg_tuple.analyse_types(env)
              self.args = None
              if func_type is Builtin.type_type and function.is_name and \
                     function.entry and \
                     function.entry.is_builtin and \
                     function.entry.name in Builtin.types_that_construct_their_instance:
                  # calling a builtin type that returns a specific object type
                  if function.entry.name == 'float':
                      # the following will come true later on in a transform
                      self.type = PyrexTypes.c_double_type
                      self.result_ctype = PyrexTypes.c_double_type
                  else:
                      self.type = Builtin.builtin_types[function.entry.name]
                      self.result_ctype = py_object_type
                  self.may_return_none = False
              elif function.is_name and function.type_entry:
                  # We are calling an extension type constructor.  As
                  # long as we do not support __new__(), the result type
                  # is clear
                  self.type = function.type_entry.type
                  self.result_ctype = py_object_type
                  self.may_return_none = False
              else:
                  self.type = py_object_type
              self.is_temp = 1
          else:
              self.args = [ arg.analyse_types(env) for arg in self.args ]
              self.analyse_c_function_call(env)
          return self
  
      def function_type(self):
          # Return the type of the function being called, coercing a function
          # pointer to a function if necessary. If the function has fused
          # arguments, return the specific type.
          func_type = self.function.type
  
          if func_type.is_ptr:
              func_type = func_type.base_type
  
          return func_type
  
      def analyse_c_function_call(self, env):
          if self.function.type is error_type:
              self.type = error_type
              return
  
          if self.self:
              args = [self.self] + self.args
          else:
              args = self.args
  
          if self.function.type.is_cpp_class:
              overloaded_entry = self.function.type.scope.lookup("operator()")
              if overloaded_entry is None:
                  self.type = PyrexTypes.error_type
                  self.result_code = "<error>"
                  return
          elif hasattr(self.function, 'entry'):
              overloaded_entry = self.function.entry
          elif (isinstance(self.function, IndexNode) and
                self.function.is_fused_index):
              overloaded_entry = self.function.type.entry
          else:
              overloaded_entry = None
  
          if overloaded_entry:
              if self.function.type.is_fused:
                  functypes = self.function.type.get_all_specialized_function_types()
                  alternatives = [f.entry for f in functypes]
              else:
                  alternatives = overloaded_entry.all_alternatives()
  
              entry = PyrexTypes.best_match(args, alternatives, self.pos, env)
  
              if not entry:
                  self.type = PyrexTypes.error_type
                  self.result_code = "<error>"
                  return
  
              entry.used = True
              self.function.entry = entry
              self.function.type = entry.type
              func_type = self.function_type()
          else:
              entry = None
              func_type = self.function_type()
              if not func_type.is_cfunction:
                  error(self.pos, "Calling non-function type '%s'" % func_type)
                  self.type = PyrexTypes.error_type
                  self.result_code = "<error>"
                  return
  
          # Check no. of args
          max_nargs = len(func_type.args)
          expected_nargs = max_nargs - func_type.optional_arg_count
          actual_nargs = len(args)
          if func_type.optional_arg_count and expected_nargs != actual_nargs:
              self.has_optional_args = 1
              self.is_temp = 1
  
          # check 'self' argument
          if entry and entry.is_cmethod and func_type.args:
              formal_arg = func_type.args[0]
              arg = args[0]
              if formal_arg.not_none:
                  if self.self:
                      self.self = self.self.as_none_safe_node(
                          "'NoneType' object has no attribute '%s'",
                          error='PyExc_AttributeError',
                          format_args=[entry.name])
                  else:
                      # unbound method
                      arg = arg.as_none_safe_node(
                          "descriptor '%s' requires a '%s' object but received a 'NoneType'",
                          format_args=[entry.name, formal_arg.type.name])
              if self.self:
                  if formal_arg.accept_builtin_subtypes:
                      arg = CMethodSelfCloneNode(self.self)
                  else:
                      arg = CloneNode(self.self)
                  arg = self.coerced_self = arg.coerce_to(formal_arg.type, env)
              elif formal_arg.type.is_builtin_type:
                  # special case: unbound methods of builtins accept subtypes
                  arg = arg.coerce_to(formal_arg.type, env)
                  if arg.type.is_builtin_type and isinstance(arg, PyTypeTestNode):
                      arg.exact_builtin_type = False
              args[0] = arg
  
          # Coerce arguments
          some_args_in_temps = False
          for i in xrange(min(max_nargs, actual_nargs)):
              formal_arg = func_type.args[i]
              formal_type = formal_arg.type
              arg = args[i].coerce_to(formal_type, env)
              if formal_arg.not_none:
                  # C methods must do the None checks at *call* time
                  arg = arg.as_none_safe_node(
                      "cannot pass None into a C function argument that is declared 'not None'")
              if arg.is_temp:
                  if i > 0:
                      # first argument in temp doesn't impact subsequent arguments
                      some_args_in_temps = True
              elif arg.type.is_pyobject and not env.nogil:
                  if i == 0 and self.self is not None:
                      # a method's cloned "self" argument is ok
                      pass
                  elif arg.nonlocally_immutable():
                      # plain local variables are ok
                      pass
                  else:
                      # we do not safely own the argument's reference,
                      # but we must make sure it cannot be collected
                      # before we return from the function, so we create
                      # an owned temp reference to it
                      if i > 0: # first argument doesn't matter
                          some_args_in_temps = True
                      arg = arg.coerce_to_temp(env)
              args[i] = arg
  
          # handle additional varargs parameters
          for i in xrange(max_nargs, actual_nargs):
              arg = args[i]
              if arg.type.is_pyobject:
                  arg_ctype = arg.type.default_coerced_ctype()
                  if arg_ctype is None:
                      error(self.args[i].pos,
                            "Python object cannot be passed as a varargs parameter")
                  else:
                      args[i] = arg = arg.coerce_to(arg_ctype, env)
              if arg.is_temp and i > 0:
                  some_args_in_temps = True
  
          if some_args_in_temps:
              # if some args are temps and others are not, they may get
              # constructed in the wrong order (temps first) => make
              # sure they are either all temps or all not temps (except
              # for the last argument, which is evaluated last in any
              # case)
              for i in xrange(actual_nargs-1):
                  if i == 0 and self.self is not None:
                      continue # self is ok
                  arg = args[i]
                  if arg.nonlocally_immutable():
                      # locals, C functions, unassignable types are safe.
                      pass
                  elif arg.type.is_cpp_class:
                      # Assignment has side effects, avoid.
                      pass
                  elif env.nogil and arg.type.is_pyobject:
                      # can't copy a Python reference into a temp in nogil
                      # env (this is safe: a construction would fail in
                      # nogil anyway)
                      pass
                  else:
                      #self.args[i] = arg.coerce_to_temp(env)
                      # instead: issue a warning
                      if i > 0 or i == 1 and self.self is not None: # skip first arg
                          warning(arg.pos, "Argument evaluation order in C function call is undefined and may not be as expected", 0)
                          break
  
          self.args[:] = args
  
          # Calc result type and code fragment
          if isinstance(self.function, NewExprNode):
              self.type = PyrexTypes.CPtrType(self.function.class_type)
          else:
              self.type = func_type.return_type
  
          if self.function.is_name or self.function.is_attribute:
              if self.function.entry and self.function.entry.utility_code:
                  self.is_temp = 1 # currently doesn't work for self.calculate_result_code()
  
          if self.type.is_pyobject:
              self.result_ctype = py_object_type
              self.is_temp = 1
          elif func_type.exception_value is not None \
                   or func_type.exception_check:
              self.is_temp = 1
          elif self.type.is_memoryviewslice:
              self.is_temp = 1
              # func_type.exception_check = True
  
          # Called in 'nogil' context?
          self.nogil = env.nogil
          if (self.nogil and
              func_type.exception_check and
              func_type.exception_check != '+'):
              env.use_utility_code(pyerr_occurred_withgil_utility_code)
          # C++ exception handler
          if func_type.exception_check == '+':
              if func_type.exception_value is None:
                  env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp"))
  
      def calculate_result_code(self):
          return self.c_call_code()
  
      def c_call_code(self):
          func_type = self.function_type()
          if self.type is PyrexTypes.error_type or not func_type.is_cfunction:
              return "<error>"
          formal_args = func_type.args
          arg_list_code = []
          args = list(zip(formal_args, self.args))
          max_nargs = len(func_type.args)
          expected_nargs = max_nargs - func_type.optional_arg_count
          actual_nargs = len(self.args)
          for formal_arg, actual_arg in args[:expected_nargs]:
                  arg_code = actual_arg.result_as(formal_arg.type)
                  arg_list_code.append(arg_code)
  
          if func_type.is_overridable:
              arg_list_code.append(str(int(self.wrapper_call or self.function.entry.is_unbound_cmethod)))
  
          if func_type.optional_arg_count:
              if expected_nargs == actual_nargs:
                  optional_args = 'NULL'
              else:
                  optional_args = "&%s" % self.opt_arg_struct
              arg_list_code.append(optional_args)
  
          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))
          return result
  
      def generate_result_code(self, code):
          func_type = self.function_type()
          if self.function.is_name or self.function.is_attribute:
              if self.function.entry and self.function.entry.utility_code:
                  code.globalstate.use_utility_code(self.function.entry.utility_code)
          if func_type.is_pyobject:
              arg_code = self.arg_tuple.py_result()
              code.globalstate.use_utility_code(UtilityCode.load_cached(
                  "PyObjectCall", "ObjectHandling.c"))
              code.putln(
                  "%s = __Pyx_PyObject_Call(%s, %s, NULL); %s" % (
                      self.result(),
                      self.function.py_result(),
                      arg_code,
                      code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.py_result())
          elif func_type.is_cfunction:
              if self.has_optional_args:
                  actual_nargs = len(self.args)
                  expected_nargs = len(func_type.args) - func_type.optional_arg_count
                  self.opt_arg_struct = code.funcstate.allocate_temp(
                      func_type.op_arg_struct.base_type, manage_ref=True)
                  code.putln("%s.%s = %s;" % (
                          self.opt_arg_struct,
                          Naming.pyrex_prefix + "n",
                          len(self.args) - expected_nargs))
                  args = list(zip(func_type.args, self.args))
                  for formal_arg, actual_arg in args[expected_nargs:actual_nargs]:
                      code.putln("%s.%s = %s;" % (
                              self.opt_arg_struct,
                              func_type.opt_arg_cname(formal_arg.name),
                              actual_arg.result_as(formal_arg.type)))
              exc_checks = []
              if self.type.is_pyobject and self.is_temp:
                  exc_checks.append("!%s" % self.result())
              elif self.type.is_memoryviewslice:
                  assert self.is_temp
                  exc_checks.append(self.type.error_condition(self.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:
                      if self.nogil:
                          exc_checks.append("__Pyx_ErrOccurredWithGIL()")
                      else:
                          exc_checks.append("PyErr_Occurred()")
              if self.is_temp or exc_checks:
                  rhs = self.c_call_code()
                  if self.result():
                      lhs = "%s = " % self.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 = ""
                  if func_type.exception_check == '+':
                      if func_type.exception_value is None:
                          raise_py_exception = "__Pyx_CppExn2PyErr();"
                      elif func_type.exception_value.type.is_pyobject:
                          raise_py_exception = 'try { throw; } catch(const std::exception& exn) { PyErr_SetString(%s, exn.what()); } catch(...) { PyErr_SetNone(%s); }' % (
                              func_type.exception_value.entry.cname,
                              func_type.exception_value.entry.cname)
                      else:
                          raise_py_exception = '%s(); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError , "Error converting c++ exception.");' % func_type.exception_value.entry.cname
                      code.putln("try {")
                      code.putln("%s%s;" % (lhs, rhs))
                      code.putln("} catch(...) {")
                      if self.nogil:
                          code.put_ensure_gil(declare_gilstate=True)
                      code.putln(raise_py_exception)
                      if self.nogil:
                          code.put_release_ensured_gil()
                      code.putln(code.error_goto(self.pos))
                      code.putln("}")
                  else:
                      if exc_checks:
                          goto_error = code.error_goto_if(" && ".join(exc_checks), self.pos)
                      else:
                          goto_error = ""
                      code.putln("%s%s; %s" % (lhs, rhs, goto_error))
                  if self.type.is_pyobject and self.result():
                      code.put_gotref(self.py_result())
              if self.has_optional_args:
                  code.funcstate.release_temp(self.opt_arg_struct)
  
  
  class InlinedDefNodeCallNode(CallNode):
      #  Inline call to defnode
      #
      #  function       PyCFunctionNode
      #  function_name  NameNode
      #  args           [ExprNode]
  
      subexprs = ['args', 'function_name']
      is_temp = 1
      type = py_object_type
      function = None
      function_name = None
  
      def can_be_inlined(self):
          func_type= self.function.def_node
          if func_type.star_arg or func_type.starstar_arg:
              return False
          if len(func_type.args) != len(self.args):
              return False
          return True
  
      def analyse_types(self, env):
          self.function_name = self.function_name.analyse_types(env)
  
          self.args = [ arg.analyse_types(env) for arg in self.args ]
          func_type = self.function.def_node
          actual_nargs = len(self.args)
  
          # Coerce arguments
          some_args_in_temps = False
          for i in xrange(actual_nargs):
              formal_type = func_type.args[i].type
              arg = self.args[i].coerce_to(formal_type, env)
              if arg.is_temp:
                  if i > 0:
                      # first argument in temp doesn't impact subsequent arguments
                      some_args_in_temps = True
              elif arg.type.is_pyobject and not env.nogil:
                  if arg.nonlocally_immutable():
                      # plain local variables are ok
                      pass
                  else:
                      # we do not safely own the argument's reference,
                      # but we must make sure it cannot be collected
                      # before we return from the function, so we create
                      # an owned temp reference to it
                      if i > 0: # first argument doesn't matter
                          some_args_in_temps = True
                      arg = arg.coerce_to_temp(env)
              self.args[i] = arg
  
          if some_args_in_temps:
              # if some args are temps and others are not, they may get
              # constructed in the wrong order (temps first) => make
              # sure they are either all temps or all not temps (except
              # for the last argument, which is evaluated last in any
              # case)
              for i in xrange(actual_nargs-1):
                  arg = self.args[i]
                  if arg.nonlocally_immutable():
                      # locals, C functions, unassignable types are safe.
                      pass
                  elif arg.type.is_cpp_class:
                      # Assignment has side effects, avoid.
                      pass
                  elif env.nogil and arg.type.is_pyobject:
                      # can't copy a Python reference into a temp in nogil
                      # env (this is safe: a construction would fail in
                      # nogil anyway)
                      pass
                  else:
                      #self.args[i] = arg.coerce_to_temp(env)
                      # instead: issue a warning
                      if i > 0:
                          warning(arg.pos, "Argument evaluation order in C function call is undefined and may not be as expected", 0)
                          break
          return self
  
      def generate_result_code(self, code):
          arg_code = [self.function_name.py_result()]
          func_type = self.function.def_node
          for arg, proto_arg in zip(self.args, func_type.args):
              if arg.type.is_pyobject:
                  arg_code.append(arg.result_as(proto_arg.type))
              else:
                  arg_code.append(arg.result())
          arg_code = ', '.join(arg_code)
          code.putln(
              "%s = %s(%s); %s" % (
                  self.result(),
                  self.function.def_node.entry.pyfunc_cname,
                  arg_code,
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  
  class PythonCapiFunctionNode(ExprNode):
      subexprs = []
  
      def __init__(self, pos, py_name, cname, func_type, utility_code = None):
          ExprNode.__init__(self, pos, name=py_name, cname=cname,
                            type=func_type, utility_code=utility_code)
  
      def analyse_types(self, env):
          return self
  
      def generate_result_code(self, code):
          if self.utility_code:
              code.globalstate.use_utility_code(self.utility_code)
  
      def calculate_result_code(self):
          return self.cname
  
  
  class PythonCapiCallNode(SimpleCallNode):
      # Python C-API Function call (only created in transforms)
  
      # By default, we assume that the call never returns None, as this
      # is true for most C-API functions in CPython.  If this does not
      # apply to a call, set the following to True (or None to inherit
      # the default behaviour).
      may_return_none = False
  
      def __init__(self, pos, function_name, func_type,
                   utility_code = None, py_name=None, **kwargs):
          self.type = func_type.return_type
          self.result_ctype = self.type
          self.function = PythonCapiFunctionNode(
              pos, py_name, function_name, func_type,
              utility_code = utility_code)
          # call this last so that we can override the constructed
          # attributes above with explicit keyword arguments if required
          SimpleCallNode.__init__(self, pos, **kwargs)
  
  
  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
  
      type = py_object_type
  
      subexprs = ['function', 'positional_args', 'keyword_args']
  
      nogil_check = Node.gil_error
  
      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)
          try:
              return function(*positional_args, **keyword_args)
          except Exception, e:
              self.compile_time_value_error(e)
  
      def explicit_args_kwds(self):
          if (self.keyword_args and not isinstance(self.keyword_args, DictNode) or
              not isinstance(self.positional_args, TupleNode)):
              raise CompileError(self.pos,
                  'Compile-time keyword arguments must be explicit.')
          return self.positional_args.args, self.keyword_args
  
      def analyse_types(self, env):
          if self.analyse_as_type_constructor(env):
              return self
          self.function = self.function.analyse_types(env)
          if not self.function.type.is_pyobject:
              if self.function.type.is_error:
                  self.type = error_type
                  return self
              if hasattr(self.function, 'entry'):
                  node = self.map_to_simple_call_node()
                  if node is not None and node is not self:
                      return node.analyse_types(env)
                  elif self.function.entry.as_variable:
                      self.function = self.function.coerce_to_pyobject(env)
                  elif node is self:
                      error(self.pos,
                            "Non-trivial keyword arguments and starred "
                            "arguments not allowed in cdef functions.")
                  else:
                      # error was already reported
                      pass
              else:
                  self.function = self.function.coerce_to_pyobject(env)
          if self.keyword_args:
              self.keyword_args = self.keyword_args.analyse_types(env)
          self.positional_args = self.positional_args.analyse_types(env)
          self.positional_args = \
              self.positional_args.coerce_to_pyobject(env)
          function = self.function
          if function.is_name and function.type_entry:
              # We are calling an extension type constructor.  As long
              # as we do not support __new__(), the result type is clear
              self.type = function.type_entry.type
              self.result_ctype = py_object_type
              self.may_return_none = False
          else:
              self.type = py_object_type
          self.is_temp = 1
          return self
  
      def map_to_simple_call_node(self):
          """
          Tries to map keyword arguments to declared positional arguments.
          Returns self to try a Python call, None to report an error
          or a SimpleCallNode if the mapping succeeds.
          """
          if not isinstance(self.positional_args, TupleNode):
              # has starred argument
              return self
          if not isinstance(self.keyword_args, DictNode):
              # keywords come from arbitrary expression => nothing to do here
              return self
          function = self.function
          entry = getattr(function, 'entry', None)
          if not entry:
              return self
          function_type = entry.type
          if function_type.is_ptr:
              function_type = function_type.base_type
          if not function_type.is_cfunction:
              return self
  
          pos_args = self.positional_args.args
          kwargs = self.keyword_args
          declared_args = function_type.args
          if entry.is_cmethod:
              declared_args = declared_args[1:] # skip 'self'
  
          if len(pos_args) > len(declared_args):
              error(self.pos, "function call got too many positional arguments, "
                              "expected %d, got %s" % (len(declared_args),
                                                       len(pos_args)))
              return None
  
          matched_args = set([ arg.name for arg in declared_args[:len(pos_args)]
                               if arg.name ])
          unmatched_args = declared_args[len(pos_args):]
          matched_kwargs_count = 0
          args = list(pos_args)
  
          # check for duplicate keywords
          seen = set(matched_args)
          has_errors = False
          for arg in kwargs.key_value_pairs:
              name = arg.key.value
              if name in seen:
                  error(arg.pos, "argument '%s' passed twice" % name)
                  has_errors = True
                  # continue to report more errors if there are any
              seen.add(name)
  
          # match keywords that are passed in order
          for decl_arg, arg in zip(unmatched_args, kwargs.key_value_pairs):
              name = arg.key.value
              if decl_arg.name == name:
                  matched_args.add(name)
                  matched_kwargs_count += 1
                  args.append(arg.value)
              else:
                  break
  
          # match keyword arguments that are passed out-of-order, but keep
          # the evaluation of non-simple arguments in order by moving them
          # into temps
          from Cython.Compiler.UtilNodes import EvalWithTempExprNode, LetRefNode
          temps = []
          if len(kwargs.key_value_pairs) > matched_kwargs_count:
              unmatched_args = declared_args[len(args):]
              keywords = dict([ (arg.key.value, (i+len(pos_args), arg))
                                for i, arg in enumerate(kwargs.key_value_pairs) ])
              first_missing_keyword = None
              for decl_arg in unmatched_args:
                  name = decl_arg.name
                  if name not in keywords:
                      # missing keyword argument => either done or error
                      if not first_missing_keyword:
                          first_missing_keyword = name
                      continue
                  elif first_missing_keyword:
                      if entry.as_variable:
                          # we might be able to convert the function to a Python
                          # object, which then allows full calling semantics
                          # with default values in gaps - currently, we only
                          # support optional arguments at the end
                          return self
                      # wasn't the last keyword => gaps are not supported
                      error(self.pos, "C function call is missing "
                                      "argument '%s'" % first_missing_keyword)
                      return None
                  pos, arg = keywords[name]
                  matched_args.add(name)
                  matched_kwargs_count += 1
                  if arg.value.is_simple():
                      args.append(arg.value)
                  else:
                      temp = LetRefNode(arg.value)
                      assert temp.is_simple()
                      args.append(temp)
                      temps.append((pos, temp))
  
              if temps:
                  # may have to move preceding non-simple args into temps
                  final_args = []
                  new_temps = []
                  first_temp_arg = temps[0][-1]
                  for arg_value in args:
                      if arg_value is first_temp_arg:
                          break  # done
                      if arg_value.is_simple():
                          final_args.append(arg_value)
                      else:
                          temp = LetRefNode(arg_value)
                          new_temps.append(temp)
                          final_args.append(temp)
                  if new_temps:
                      args = final_args
                  temps = new_temps + [ arg for i,arg in sorted(temps) ]
  
          # check for unexpected keywords
          for arg in kwargs.key_value_pairs:
              name = arg.key.value
              if name not in matched_args:
                  has_errors = True
                  error(arg.pos,
                        "C function got unexpected keyword argument '%s'" %
                        name)
  
          if has_errors:
              # error was reported already
              return None
  
          # all keywords mapped to positional arguments
          # if we are missing arguments, SimpleCallNode will figure it out
          node = SimpleCallNode(self.pos, function=function, args=args)
          for temp in temps[::-1]:
              node = EvalWithTempExprNode(temp, node)
          return node
  
      def generate_result_code(self, code):
          if self.type.is_error: return
          if self.keyword_args:
              kwargs = self.keyword_args.py_result()
          else:
              kwargs = 'NULL'
          code.globalstate.use_utility_code(UtilityCode.load_cached(
              "PyObjectCall", "ObjectHandling.c"))
          code.putln(
              "%s = __Pyx_PyObject_Call(%s, %s, %s); %s" % (
                  self.result(),
                  self.function.py_result(),
                  self.positional_args.py_result(),
                  kwargs,
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  
  class AsTupleNode(ExprNode):
      #  Convert argument to tuple. Used for normalising
      #  the * argument of a function call.
      #
      #  arg    ExprNode
  
      subexprs = ['arg']
  
      def calculate_constant_result(self):
          self.constant_result = tuple(self.arg.constant_result)
  
      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 = self.arg.analyse_types(env)
          self.arg = self.arg.coerce_to_pyobject(env)
          self.type = tuple_type
          self.is_temp = 1
          return self
  
      def may_be_none(self):
          return False
  
      nogil_check = Node.gil_error
      gil_message = "Constructing Python tuple"
  
      def generate_result_code(self, code):
          code.putln(
              "%s = PySequence_Tuple(%s); %s" % (
                  self.result(),
                  self.arg.py_result(),
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  
  class AttributeNode(ExprNode):
      #  obj.attribute
      #
      #  obj          ExprNode
      #  attribute    string
      #  needs_none_check boolean        Used if obj is an extension type.
      #                                  If set to True, it is known that the type is not None.
      #
      #  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
  
      is_attribute = 1
      subexprs = ['obj']
  
      type = PyrexTypes.error_type
      entry = None
      is_called = 0
      needs_none_check = True
      is_memslice_transpose = False
      is_special_lookup = False
  
      def as_cython_attribute(self):
          if (isinstance(self.obj, NameNode) and
                  self.obj.is_cython_module and not
                  self.attribute == u"parallel"):
              return self.attribute
  
          cy = self.obj.as_cython_attribute()
          if cy:
              return "%s.%s" % (cy, self.attribute)
          return None
  
      def coerce_to(self, dst_type, env):
          #  If coercing to a generic pyobject and this is a cpdef function
          #  we can create the corresponding attribute
          if dst_type is py_object_type:
              entry = self.entry
              if entry and entry.is_cfunction and entry.as_variable:
                  # must be a cpdef function
                  self.is_temp = 1
                  self.entry = entry.as_variable
                  self.analyse_as_python_attribute(env)
                  return self
          return ExprNode.coerce_to(self, dst_type, env)
  
      def calculate_constant_result(self):
          attr = self.attribute
          if attr.startswith("__") and attr.endswith("__"):
              return
          self.constant_result = getattr(self.obj.constant_result, attr)
  
      def compile_time_value(self, denv):
          attr = self.attribute
          if attr.startswith("__") and attr.endswith("__"):
              error(self.pos,
                    "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 type_dependencies(self, env):
          return self.obj.type_dependencies(env)
  
      def infer_type(self, env):
          # FIXME: this is way too redundant with analyse_types()
          node = self.analyse_as_cimported_attribute_node(env, target=False)
          if node is not None:
              return node.entry.type
          node = self.analyse_as_unbound_cmethod_node(env)
          if node is not None:
              return node.entry.type
          obj_type = self.obj.infer_type(env)
          self.analyse_attribute(env, obj_type=obj_type)
          if obj_type.is_builtin_type and self.type.is_cfunction:
              # special case: C-API replacements for C methods of
              # builtin types cannot be inferred as C functions as
              # that would prevent their use as bound methods
              return py_object_type
          return self.type
  
      def analyse_target_declaration(self, env):
          pass
  
      def analyse_target_types(self, env):
          node = self.analyse_types(env, target = 1)
          if node.type.is_const:
              error(self.pos, "Assignment to const attribute '%s'" % self.attribute)
          if not node.is_lvalue():
              error(self.pos, "Assignment to non-lvalue of type '%s'" % self.type)
          return node
  
      def analyse_types(self, env, target = 0):
          self.initialized_check = env.directives['initializedcheck']
          node = self.analyse_as_cimported_attribute_node(env, target)
          if node is None and not target:
              node = self.analyse_as_unbound_cmethod_node(env)
          if node is None:
              node = self.analyse_as_ordinary_attribute_node(env, target)
              assert node is not None
          if node.entry:
              node.entry.used = True
          if node.is_attribute:
              node.wrap_obj_in_nonecheck(env)
          return node
  
      def analyse_as_cimported_attribute_node(self, env, target):
          # 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):
                  return self.as_name_node(env, entry, target)
          return None
  
      def analyse_as_unbound_cmethod_node(self, env):
          # Try to interpret this as a reference to an unbound
          # C method of an extension type or builtin type.  If successful,
          # creates a corresponding NameNode and returns it, otherwise
          # returns None.
          type = self.obj.analyse_as_extension_type(env)
          if type:
              entry = type.scope.lookup_here(self.attribute)
              if entry and entry.is_cmethod:
                  if type.is_builtin_type:
                      if not self.is_called:
                          # must handle this as Python object
                          return None
                      ubcm_entry = entry
                  else:
                      # Create a temporary entry describing the C method
                      # as an ordinary function.
                      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
                      ubcm_entry.is_unbound_cmethod = 1
                  return self.as_name_node(env, ubcm_entry, target=False)
          return None
  
      def analyse_as_type(self, env):
          module_scope = self.obj.analyse_as_module(env)
          if module_scope:
              return module_scope.lookup_type(self.attribute)
          if not self.obj.is_string_literal:
              base_type = self.obj.analyse_as_type(env)
              if base_type and hasattr(base_type, 'scope') and base_type.scope is not None:
                  return base_type.scope.lookup_type(self.attribute)
          return None
  
      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:
                  if entry.type.is_extension_type or entry.type.is_builtin_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 as_name_node(self, env, entry, target):
          # Create a corresponding NameNode from this node and complete the
          # analyse_types phase.
          node = NameNode.from_node(self, name=self.attribute, entry=entry)
          if target:
              node = node.analyse_target_types(env)
          else:
              node = node.analyse_rvalue_entry(env)
          node.entry.used = 1
          return node
  
      def analyse_as_ordinary_attribute_node(self, env, target):
          self.obj = 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")
              pass
          ## Reference to C array turns into pointer to first element.
          #while self.type.is_array:
          #    self.type = self.type.element_ptr_type()
          if self.is_py_attr:
              if not target:
                  self.is_temp = 1
                  self.result_ctype = py_object_type
          elif target and self.obj.type.is_builtin_type:
              error(self.pos, "Assignment to an immutable object field")
          #elif self.type.is_memoryviewslice and not target:
          #    self.is_temp = True
          return self
  
      def analyse_attribute(self, env, obj_type = None):
          # Look up attribute and set self.type and self.member.
          immutable_obj = obj_type is not None # used during type inference
          self.is_py_attr = 0
          self.member = self.attribute
          if obj_type is None:
              if self.obj.type.is_string or self.obj.type.is_pyunicode_ptr:
                  self.obj = self.obj.coerce_to_pyobject(env)
              obj_type = self.obj.type
          else:
              if obj_type.is_string or obj_type.is_pyunicode_ptr:
                  obj_type = py_object_type
          if obj_type.is_ptr or obj_type.is_array:
              obj_type = obj_type.base_type
              self.op = "->"
          elif obj_type.is_extension_type or obj_type.is_builtin_type:
              self.op = "->"
          else:
              self.op = "."
          if obj_type.has_attributes:
              if obj_type.attributes_known():
                  if (obj_type.is_memoryviewslice and not
                          obj_type.scope.lookup_here(self.attribute)):
                      if self.attribute == 'T':
                          self.is_memslice_transpose = True
                          self.is_temp = True
                          self.use_managed_ref = True
                          self.type = self.obj.type
                          return
                      else:
                          obj_type.declare_attribute(self.attribute, env, self.pos)
                  entry = obj_type.scope.lookup_here(self.attribute)
                  if entry and entry.is_member:
                      entry = None
              else:
                  error(self.pos,
                      "Cannot select attribute of incomplete type '%s'"
                      % obj_type)
                  self.type = PyrexTypes.error_type
                  return
              self.entry = entry
              if entry:
                  if obj_type.is_extension_type and entry.name == "__weakref__":
                      error(self.pos, "Illegal use of special attribute __weakref__")
  
                  # def methods need the normal attribute lookup
                  # because they do not have struct entries
                  # fused function go through assignment synthesis
                  # (foo = pycfunction(foo_func_obj)) and need to go through
                  # regular Python lookup as well
                  if (entry.is_variable and not entry.fused_cfunction) or entry.is_cmethod:
                      self.type = entry.type
                      self.member = entry.cname
                      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.
          self.analyse_as_python_attribute(env, obj_type, immutable_obj)
  
      def analyse_as_python_attribute(self, env, obj_type=None, immutable_obj=False):
          if obj_type is None:
              obj_type = self.obj.type
          # mangle private '__*' Python attributes used inside of a class
          self.attribute = env.mangle_class_private_name(self.attribute)
          self.member = self.attribute
          self.type = py_object_type
          self.is_py_attr = 1
          if not obj_type.is_pyobject and not obj_type.is_error:
              if obj_type.can_coerce_to_pyobject(env):
                  if not immutable_obj:
                      self.obj = self.obj.coerce_to_pyobject(env)
              elif (obj_type.is_cfunction and self.obj.is_name
                    and self.obj.entry.as_variable
                    and self.obj.entry.as_variable.type.is_pyobject):
                  # might be an optimised builtin function => unpack it
                  if not immutable_obj:
                      self.obj = self.obj.coerce_to_pyobject(env)
              else:
                  error(self.pos,
                        "Object of type '%s' has no attribute '%s'" %
                        (obj_type, self.attribute))
  
      def wrap_obj_in_nonecheck(self, env):
          if not env.directives['nonecheck']:
              return
  
          msg = None
          format_args = ()
          if (self.obj.type.is_extension_type and self.needs_none_check and not
                  self.is_py_attr):
              msg = "'NoneType' object has no attribute '%s'"
              format_args = (self.attribute,)
          elif self.obj.type.is_memoryviewslice:
              if self.is_memslice_transpose:
                  msg = "Cannot transpose None memoryview slice"
              else:
                  entry = self.obj.type.scope.lookup_here(self.attribute)
                  if entry:
                      # copy/is_c_contig/shape/strides etc
                      msg = "Cannot access '%s' attribute of None memoryview slice"
                      format_args = (entry.name,)
  
          if msg:
              self.obj = self.obj.as_none_safe_node(msg, 'PyExc_AttributeError',
                                                    format_args=format_args)
  
  
      def nogil_check(self, env):
          if self.is_py_attr:
              self.gil_error()
          elif self.type.is_memoryviewslice:
              import MemoryView
              MemoryView.err_if_nogil_initialized_check(self.pos, env, '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 not self.type.is_array
          else:
              return NameNode.is_lvalue(self)
  
      def is_ephemeral(self):
          if self.obj:
              return self.obj.is_ephemeral()
          else:
              return NameNode.is_ephemeral(self)
  
      def calculate_result_code(self):
          #print "AttributeNode.calculate_result_code:", self.member ###
          #print "...obj node =", self.obj, "code", self.obj.result() ###
          #print "...obj type", self.obj.type, "ctype", self.obj.ctype() ###
          obj = self.obj
          obj_code = obj.result_as(obj.type)
          #print "...obj_code =", obj_code ###
          if self.entry and self.entry.is_cmethod:
              if obj.type.is_extension_type and not self.entry.is_builtin_cmethod:
                  if self.entry.final_func_cname:
                      return self.entry.final_func_cname
  
                  if self.type.from_fused:
                      # If the attribute was specialized through indexing, make
                      # sure to get the right fused name, as our entry was
                      # replaced by our parent index node
                      # (AnalyseExpressionsTransform)
                      self.member = self.entry.cname
  
                  return "((struct %s *)%s%s%s)->%s" % (
                      obj.type.vtabstruct_cname, obj_code, self.op,
                      obj.type.vtabslot_cname, self.member)
              elif self.result_is_used:
                  return self.member
              # Generating no code at all for unused access to optimised builtin
              # methods fixes the problem that some optimisations only exist as
              # macros, i.e. there is no function pointer to them, so we would
              # generate invalid C code here.
              return
          elif obj.type.is_complex:
              return "__Pyx_C%s(%s)" % (self.member.upper(), obj_code)
          else:
              if obj.type.is_builtin_type and self.entry and self.entry.is_variable:
                  # accessing a field of a builtin type, need to cast better than result_as() does
                  obj_code = obj.type.cast_code(obj.result(), to_object_struct = True)
              return "%s%s%s" % (obj_code, self.op, self.member)
  
      def generate_result_code(self, code):
          if self.is_py_attr:
              if self.is_special_lookup:
                  code.globalstate.use_utility_code(
                      UtilityCode.load_cached("PyObjectLookupSpecial", "ObjectHandling.c"))
                  lookup_func_name = '__Pyx_PyObject_LookupSpecial'
              else:
                  code.globalstate.use_utility_code(
                      UtilityCode.load_cached("PyObjectGetAttrStr", "ObjectHandling.c"))
                  lookup_func_name = '__Pyx_PyObject_GetAttrStr'
              code.putln(
                  '%s = %s(%s, %s); %s' % (
                      self.result(),
                      lookup_func_name,
                      self.obj.py_result(),
                      code.intern_identifier(self.attribute),
                      code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.py_result())
          elif self.type.is_memoryviewslice:
              if self.is_memslice_transpose:
                  # transpose the slice
                  for access, packing in self.type.axes:
                      if access == 'ptr':
                          error(self.pos, "Transposing not supported for slices "
                                          "with indirect dimensions")
                          return
  
                  code.putln("%s = %s;" % (self.result(), self.obj.result()))
                  if self.obj.is_name or (self.obj.is_attribute and
                                          self.obj.is_memslice_transpose):
                      code.put_incref_memoryviewslice(self.result(), have_gil=True)
  
                  T = "__pyx_memslice_transpose(&%s) == 0"
                  code.putln(code.error_goto_if(T % self.result(), self.pos))
              elif self.initialized_check:
                  code.putln(
                      'if (unlikely(!%s.memview)) {'
                          'PyErr_SetString(PyExc_AttributeError,'
                                          '"Memoryview is not initialized");'
                          '%s'
                      '}' % (self.result(), code.error_goto(self.pos)))
          else:
              # result_code contains what is needed, but we may need to insert
              # a check and raise an exception
              if self.obj.type.is_extension_type:
                  pass
              elif self.entry and self.entry.is_cmethod and self.entry.utility_code:
                  # C method implemented as function call with utility code
                  code.globalstate.use_utility_code(self.entry.utility_code)
  
      def generate_disposal_code(self, code):
          if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose:
              # mirror condition for putting the memview incref here:
              if self.obj.is_name or (self.obj.is_attribute and
                                      self.obj.is_memslice_transpose):
                  code.put_xdecref_memoryviewslice(
                          self.result(), have_gil=True)
          else:
              ExprNode.generate_disposal_code(self, code)
  
      def generate_assignment_code(self, rhs, code):
          self.obj.generate_evaluation_code(code)
          if self.is_py_attr:
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("PyObjectSetAttrStr", "ObjectHandling.c"))
              code.put_error_if_neg(self.pos,
                  '__Pyx_PyObject_SetAttrStr(%s, %s, %s)' % (
                      self.obj.py_result(),
                      code.intern_identifier(self.attribute),
                      rhs.py_result()))
              rhs.generate_disposal_code(code)
              rhs.free_temps(code)
          elif self.obj.type.is_complex:
              code.putln("__Pyx_SET_C%s(%s, %s);" % (
                  self.member.upper(),
                  self.obj.result_as(self.obj.type),
                  rhs.result_as(self.ctype())))
          else:
              select_code = self.result()
              if self.type.is_pyobject and self.use_managed_ref:
                  rhs.make_owned_reference(code)
                  code.put_giveref(rhs.py_result())
                  code.put_gotref(select_code)
                  code.put_decref(select_code, self.ctype())
              elif self.type.is_memoryviewslice:
                  import MemoryView
                  MemoryView.put_assign_to_memviewslice(
                          select_code, rhs, rhs.result(), self.type, code)
  
              if not self.type.is_memoryviewslice:
                  code.putln(
                      "%s = %s;" % (
                          select_code,
                          rhs.result_as(self.ctype())))
                          #rhs.result()))
              rhs.generate_post_assignment_code(code)
              rhs.free_temps(code)
          self.obj.generate_disposal_code(code)
          self.obj.free_temps(code)
  
      def generate_deletion_code(self, code, ignore_nonexisting=False):
          self.obj.generate_evaluation_code(code)
          if self.is_py_attr or (self.entry.scope.is_property_scope
                                 and u'__del__' in self.entry.scope.entries):
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("PyObjectSetAttrStr", "ObjectHandling.c"))
              code.put_error_if_neg(self.pos,
                  '__Pyx_PyObject_DelAttrStr(%s, %s)' % (
                      self.obj.py_result(),
                      code.intern_identifier(self.attribute)))
          else:
              error(self.pos, "Cannot delete C attribute of extension type")
          self.obj.generate_disposal_code(code)
          self.obj.free_temps(code)
  
      def annotate(self, code):
          if self.is_py_attr:
              style, text = 'py_attr', 'python attribute (%s)'
          else:
              style, text = 'c_attr', 'c attribute (%s)'
          code.annotate(self.pos, AnnotationItem(style, text % self.type, size=len(self.attribute)))
  
  
  #-------------------------------------------------------------------
  #
  #  Constructor nodes
  #
  #-------------------------------------------------------------------
  
  class StarredTargetNode(ExprNode):
      #  A starred expression like "*a"
      #
      #  This is only allowed in sequence assignment targets such as
      #
      #      a, *b = (1,2,3,4)    =>     a = 1 ; b = [2,3,4]
      #
      #  and will be removed during type analysis (or generate an error
      #  if it's found at unexpected places).
      #
      #  target          ExprNode
  
      subexprs = ['target']
      is_starred = 1
      type = py_object_type
      is_temp = 1
  
      def __init__(self, pos, target):
          ExprNode.__init__(self, pos)
          self.target = target
  
      def analyse_declarations(self, env):
          error(self.pos, "can use starred expression only as assignment target")
          self.target.analyse_declarations(env)
  
      def analyse_types(self, env):
          error(self.pos, "can use starred expression only as assignment target")
          self.target = self.target.analyse_types(env)
          self.type = self.target.type
          return self
  
      def analyse_target_declaration(self, env):
          self.target.analyse_target_declaration(env)
  
      def analyse_target_types(self, env):
          self.target = self.target.analyse_target_types(env)
          self.type = self.target.type
          return self
  
      def calculate_result_code(self):
          return ""
  
      def generate_result_code(self, code):
          pass
  
  
  class SequenceNode(ExprNode):
      #  Base class for list and tuple constructor nodes.
      #  Contains common code for performing sequence unpacking.
      #
      #  args                    [ExprNode]
      #  unpacked_items          [ExprNode] or None
      #  coerced_unpacked_items  [ExprNode] or None
      # mult_factor              ExprNode     the integer number of content repetitions ([1,2]*3)
  
      subexprs = ['args', 'mult_factor']
  
      is_sequence_constructor = 1
      unpacked_items = None
      mult_factor = None
      slow = False  # trade speed for code size (e.g. use PyTuple_Pack())
  
      def compile_time_value_list(self, denv):
          return [arg.compile_time_value(denv) for arg in self.args]
  
      def replace_starred_target_node(self):
          # replace a starred node in the targets by the contained expression
          self.starred_assignment = False
          args = []
          for arg in self.args:
              if arg.is_starred:
                  if self.starred_assignment:
                      error(arg.pos, "more than 1 starred expression in assignment")
                  self.starred_assignment = True
                  arg = arg.target
                  arg.is_starred = True
              args.append(arg)
          self.args = args
  
      def analyse_target_declaration(self, env):
          self.replace_starred_target_node()
          for arg in self.args:
              arg.analyse_target_declaration(env)
  
      def analyse_types(self, env, skip_children=False):
          for i in range(len(self.args)):
              arg = self.args[i]
              if not skip_children: arg = arg.analyse_types(env)
              self.args[i] = arg.coerce_to_pyobject(env)
          if self.mult_factor:
              self.mult_factor = self.mult_factor.analyse_types(env)
              if not self.mult_factor.type.is_int:
                  self.mult_factor = self.mult_factor.coerce_to_pyobject(env)
          self.is_temp = 1
          # not setting self.type here, subtypes do this
          return self
  
      def may_be_none(self):
          return False
  
      def analyse_target_types(self, env):
          if self.mult_factor:
              error(self.pos, "can't assign to multiplied sequence")
          self.unpacked_items = []
          self.coerced_unpacked_items = []
          self.any_coerced_items = False
          for i, arg in enumerate(self.args):
              arg = self.args[i] = arg.analyse_target_types(env)
              if arg.is_starred:
                  if not arg.type.assignable_from(Builtin.list_type):
                      error(arg.pos,
                            "starred target must have Python object (list) type")
                  if arg.type is py_object_type:
                      arg.type = Builtin.list_type
              unpacked_item = PyTempNode(self.pos, env)
              coerced_unpacked_item = unpacked_item.coerce_to(arg.type, env)
              if unpacked_item is not coerced_unpacked_item:
                  self.any_coerced_items = True
              self.unpacked_items.append(unpacked_item)
              self.coerced_unpacked_items.append(coerced_unpacked_item)
          self.type = py_object_type
          return self
  
      def generate_result_code(self, code):
          self.generate_operation_code(code)
  
      def generate_sequence_packing_code(self, code, target=None, plain=False):
          if target is None:
              target = self.result()
          size_factor = c_mult = ''
          mult_factor = None
  
          if self.mult_factor and not plain:
              mult_factor = self.mult_factor
              if mult_factor.type.is_int:
                  c_mult = mult_factor.result()
                  if isinstance(mult_factor.constant_result, (int,long)) \
                         and mult_factor.constant_result > 0:
                      size_factor = ' * %s' % mult_factor.constant_result
                  else:
                      size_factor = ' * ((%s<0) ? 0:%s)' % (c_mult, c_mult)
  
          if self.type is Builtin.tuple_type and (self.is_literal or self.slow) and not c_mult:
              # use PyTuple_Pack() to avoid generating huge amounts of one-time code
              code.putln('%s = PyTuple_Pack(%d, %s); %s' % (
                  target,
                  len(self.args),
                  ', '.join([ arg.py_result() for arg in self.args ]),
                  code.error_goto_if_null(target, self.pos)))
              code.put_gotref(target)
          else:
              # build the tuple/list step by step, potentially multiplying it as we go
              if self.type is Builtin.list_type:
                  create_func, set_item_func = 'PyList_New', 'PyList_SET_ITEM'
              elif self.type is Builtin.tuple_type:
                  create_func, set_item_func = 'PyTuple_New', 'PyTuple_SET_ITEM'
              else:
                  raise InternalError("sequence packing for unexpected type %s" % self.type)
              arg_count = len(self.args)
              code.putln("%s = %s(%s%s); %s" % (
                  target, create_func, arg_count, size_factor,
                  code.error_goto_if_null(target, self.pos)))
              code.put_gotref(target)
  
              if c_mult:
                  # FIXME: can't use a temp variable here as the code may
                  # end up in the constant building function.  Temps
                  # currently don't work there.
  
                  #counter = code.funcstate.allocate_temp(mult_factor.type, manage_ref=False)
                  counter = Naming.quick_temp_cname
                  code.putln('{ Py_ssize_t %s;' % counter)
                  if arg_count == 1:
                      offset = counter
                  else:
                      offset = '%s * %s' % (counter, arg_count)
                  code.putln('for (%s=0; %s < %s; %s++) {' % (
                      counter, counter, c_mult, counter
                      ))
              else:
                  offset = ''
  
              for i in xrange(arg_count):
                  arg = self.args[i]
                  if c_mult or not arg.result_in_temp():
                      code.put_incref(arg.result(), arg.ctype())
                  code.putln("%s(%s, %s, %s);" % (
                      set_item_func,
                      target,
                      (offset and i) and ('%s + %s' % (offset, i)) or (offset or i),
                      arg.py_result()))
                  code.put_giveref(arg.py_result())
  
              if c_mult:
                  code.putln('}')
                  #code.funcstate.release_temp(counter)
                  code.putln('}')
  
          if mult_factor is not None and mult_factor.type.is_pyobject:
              code.putln('{ PyObject* %s = PyNumber_InPlaceMultiply(%s, %s); %s' % (
                  Naming.quick_temp_cname, target, mult_factor.py_result(),
                  code.error_goto_if_null(Naming.quick_temp_cname, self.pos)
                  ))
              code.put_gotref(Naming.quick_temp_cname)
              code.put_decref(target, py_object_type)
              code.putln('%s = %s;' % (target, Naming.quick_temp_cname))
              code.putln('}')
  
      def generate_subexpr_disposal_code(self, code):
          if self.mult_factor and self.mult_factor.type.is_int:
              super(SequenceNode, self).generate_subexpr_disposal_code(code)
          elif self.type is Builtin.tuple_type and (self.is_literal or self.slow):
              super(SequenceNode, self).generate_subexpr_disposal_code(code)
          else:
              # We call generate_post_assignment_code here instead
              # 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)
                  # Should NOT call free_temps -- this is invoked by the default
                  # generate_evaluation_code which will do that.
              if self.mult_factor:
                  self.mult_factor.generate_disposal_code(code)
  
      def generate_assignment_code(self, rhs, code):
          if self.starred_assignment:
              self.generate_starred_assignment_code(rhs, code)
          else:
              self.generate_parallel_assignment_code(rhs, code)
  
          for item in self.unpacked_items:
              item.release(code)
          rhs.free_temps(code)
  
      _func_iternext_type = PyrexTypes.CPtrType(PyrexTypes.CFuncType(
          PyrexTypes.py_object_type, [
              PyrexTypes.CFuncTypeArg("it", PyrexTypes.py_object_type, None),
              ]))
  
      def generate_parallel_assignment_code(self, rhs, code):
          # Need to work around the fact that generate_evaluation_code
          # allocates the temps in a rather hacky way -- the assignment
          # is evaluated twice, within each if-block.
          for item in self.unpacked_items:
              item.allocate(code)
          special_unpack = (rhs.type is py_object_type
                            or rhs.type in (tuple_type, list_type)
                            or not rhs.type.is_builtin_type)
          long_enough_for_a_loop = len(self.unpacked_items) > 3
  
          if special_unpack:
              self.generate_special_parallel_unpacking_code(
                  code, rhs, use_loop=long_enough_for_a_loop)
          else:
              code.putln("{")
              self.generate_generic_parallel_unpacking_code(
                  code, rhs, self.unpacked_items, use_loop=long_enough_for_a_loop)
              code.putln("}")
  
          for value_node in self.coerced_unpacked_items:
              value_node.generate_evaluation_code(code)
          for i in range(len(self.args)):
              self.args[i].generate_assignment_code(
                  self.coerced_unpacked_items[i], code)
  
      def generate_special_parallel_unpacking_code(self, code, rhs, use_loop):
          sequence_type_test = '1'
          none_check = "likely(%s != Py_None)" % rhs.py_result()
          if rhs.type is list_type:
              sequence_types = ['List']
              if rhs.may_be_none():
                  sequence_type_test = none_check
          elif rhs.type is tuple_type:
              sequence_types = ['Tuple']
              if rhs.may_be_none():
                  sequence_type_test = none_check
          else:
              sequence_types = ['Tuple', 'List']
              tuple_check = 'likely(PyTuple_CheckExact(%s))' % rhs.py_result()
              list_check  = 'PyList_CheckExact(%s)' % rhs.py_result()
              sequence_type_test = "(%s) || (%s)" % (tuple_check, list_check)
  
          code.putln("if (%s) {" % sequence_type_test)
          code.putln("PyObject* sequence = %s;" % rhs.py_result())
  
          # list/tuple => check size
          code.putln("#if CYTHON_COMPILING_IN_CPYTHON")
          code.putln("Py_ssize_t size = Py_SIZE(sequence);")
          code.putln("#else")
          code.putln("Py_ssize_t size = PySequence_Size(sequence);")  # < 0 => exception
          code.putln("#endif")
          code.putln("if (unlikely(size != %d)) {" % len(self.args))
          code.globalstate.use_utility_code(raise_too_many_values_to_unpack)
          code.putln("if (size > %d) __Pyx_RaiseTooManyValuesError(%d);" % (
              len(self.args), len(self.args)))
          code.globalstate.use_utility_code(raise_need_more_values_to_unpack)
          code.putln("else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);")
          code.putln(code.error_goto(self.pos))
          code.putln("}")
  
          code.putln("#if CYTHON_COMPILING_IN_CPYTHON")
          # unpack items from list/tuple in unrolled loop (can't fail)
          if len(sequence_types) == 2:
              code.putln("if (likely(Py%s_CheckExact(sequence))) {" % sequence_types[0])
          for i, item in enumerate(self.unpacked_items):
              code.putln("%s = Py%s_GET_ITEM(sequence, %d); " % (
                  item.result(), sequence_types[0], i))
          if len(sequence_types) == 2:
              code.putln("} else {")
              for i, item in enumerate(self.unpacked_items):
                  code.putln("%s = Py%s_GET_ITEM(sequence, %d); " % (
                      item.result(), sequence_types[1], i))
              code.putln("}")
          for item in self.unpacked_items:
              code.put_incref(item.result(), item.ctype())
  
          code.putln("#else")
          # in non-CPython, use the PySequence protocol (which can fail)
          if not use_loop:
              for i, item in enumerate(self.unpacked_items):
                  code.putln("%s = PySequence_ITEM(sequence, %d); %s" % (
                      item.result(), i,
                      code.error_goto_if_null(item.result(), self.pos)))
                  code.put_gotref(item.result())
          else:
              code.putln("{")
              code.putln("Py_ssize_t i;")
              code.putln("PyObject** temps[%s] = {%s};" % (
                  len(self.unpacked_items),
                  ','.join(['&%s' % item.result() for item in self.unpacked_items])))
              code.putln("for (i=0; i < %s; i++) {" % len(self.unpacked_items))
              code.putln("PyObject* item = PySequence_ITEM(sequence, i); %s" % (
                  code.error_goto_if_null('item', self.pos)))
              code.put_gotref('item')
              code.putln("*(temps[i]) = item;")
              code.putln("}")
              code.putln("}")
  
          code.putln("#endif")
          rhs.generate_disposal_code(code)
  
          if sequence_type_test == '1':
              code.putln("}")  # all done
          elif sequence_type_test == none_check:
              # either tuple/list or None => save some code by generating the error directly
              code.putln("} else {")
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("RaiseNoneIterError", "ObjectHandling.c"))
              code.putln("__Pyx_RaiseNoneNotIterableError(); %s" % code.error_goto(self.pos))
              code.putln("}")  # all done
          else:
              code.putln("} else {")  # needs iteration fallback code
              self.generate_generic_parallel_unpacking_code(
                  code, rhs, self.unpacked_items, use_loop=use_loop)
              code.putln("}")
  
      def generate_generic_parallel_unpacking_code(self, code, rhs, unpacked_items, use_loop, terminate=True):
          code.globalstate.use_utility_code(raise_need_more_values_to_unpack)
          code.globalstate.use_utility_code(UtilityCode.load_cached("IterFinish", "ObjectHandling.c"))
          code.putln("Py_ssize_t index = -1;") # must be at the start of a C block!
  
          if use_loop:
              code.putln("PyObject** temps[%s] = {%s};" % (
                  len(self.unpacked_items),
                  ','.join(['&%s' % item.result() for item in unpacked_items])))
  
          iterator_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
          code.putln(
              "%s = PyObject_GetIter(%s); %s" % (
                  iterator_temp,
                  rhs.py_result(),
                  code.error_goto_if_null(iterator_temp, self.pos)))
          code.put_gotref(iterator_temp)
          rhs.generate_disposal_code(code)
  
          iternext_func = code.funcstate.allocate_temp(self._func_iternext_type, manage_ref=False)
          code.putln("%s = Py_TYPE(%s)->tp_iternext;" % (
              iternext_func, iterator_temp))
  
          unpacking_error_label = code.new_label('unpacking_failed')
          unpack_code = "%s(%s)" % (iternext_func, iterator_temp)
          if use_loop:
              code.putln("for (index=0; index < %s; index++) {" % len(unpacked_items))
              code.put("PyObject* item = %s; if (unlikely(!item)) " % unpack_code)
              code.put_goto(unpacking_error_label)
              code.put_gotref("item")
              code.putln("*(temps[index]) = item;")
              code.putln("}")
          else:
              for i, item in enumerate(unpacked_items):
                  code.put(
                      "index = %d; %s = %s; if (unlikely(!%s)) " % (
                          i,
                          item.result(),
                          unpack_code,
                          item.result()))
                  code.put_goto(unpacking_error_label)
                  code.put_gotref(item.py_result())
  
          if terminate:
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("UnpackItemEndCheck", "ObjectHandling.c"))
              code.put_error_if_neg(self.pos, "__Pyx_IternextUnpackEndCheck(%s, %d)" % (
                  unpack_code,
                  len(unpacked_items)))
              code.putln("%s = NULL;" % iternext_func)
              code.put_decref_clear(iterator_temp, py_object_type)
  
          unpacking_done_label = code.new_label('unpacking_done')
          code.put_goto(unpacking_done_label)
  
          code.put_label(unpacking_error_label)
          code.put_decref_clear(iterator_temp, py_object_type)
          code.putln("%s = NULL;" % iternext_func)
          code.putln("if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);")
          code.putln(code.error_goto(self.pos))
          code.put_label(unpacking_done_label)
  
          code.funcstate.release_temp(iternext_func)
          if terminate:
              code.funcstate.release_temp(iterator_temp)
              iterator_temp = None
  
          return iterator_temp
  
      def generate_starred_assignment_code(self, rhs, code):
          for i, arg in enumerate(self.args):
              if arg.is_starred:
                  starred_target = self.unpacked_items[i]
                  unpacked_fixed_items_left  = self.unpacked_items[:i]
                  unpacked_fixed_items_right = self.unpacked_items[i+1:]
                  break
          else:
              assert False
  
          iterator_temp = None
          if unpacked_fixed_items_left:
              for item in unpacked_fixed_items_left:
                  item.allocate(code)
              code.putln('{')
              iterator_temp = self.generate_generic_parallel_unpacking_code(
                  code, rhs, unpacked_fixed_items_left,
                  use_loop=True, terminate=False)
              for i, item in enumerate(unpacked_fixed_items_left):
                  value_node = self.coerced_unpacked_items[i]
                  value_node.generate_evaluation_code(code)
              code.putln('}')
  
          starred_target.allocate(code)
          target_list = starred_target.result()
          code.putln("%s = PySequence_List(%s); %s" % (
              target_list,
              iterator_temp or rhs.py_result(),
              code.error_goto_if_null(target_list, self.pos)))
          code.put_gotref(target_list)
  
          if iterator_temp:
              code.put_decref_clear(iterator_temp, py_object_type)
              code.funcstate.release_temp(iterator_temp)
          else:
              rhs.generate_disposal_code(code)
  
          if unpacked_fixed_items_right:
              code.globalstate.use_utility_code(raise_need_more_values_to_unpack)
              length_temp = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False)
              code.putln('%s = PyList_GET_SIZE(%s);' % (length_temp, target_list))
              code.putln("if (unlikely(%s < %d)) {" % (length_temp, len(unpacked_fixed_items_right)))
              code.putln("__Pyx_RaiseNeedMoreValuesError(%d+%s); %s" % (
                   len(unpacked_fixed_items_left), length_temp,
                   code.error_goto(self.pos)))
              code.putln('}')
  
              for item in unpacked_fixed_items_right[::-1]:
                  item.allocate(code)
              for i, (item, coerced_arg) in enumerate(zip(unpacked_fixed_items_right[::-1],
                                                          self.coerced_unpacked_items[::-1])):
                  code.putln('#if CYTHON_COMPILING_IN_CPYTHON')
                  code.putln("%s = PyList_GET_ITEM(%s, %s-%d); " % (
                      item.py_result(), target_list, length_temp, i+1))
                  # resize the list the hard way
                  code.putln("((PyVarObject*)%s)->ob_size--;" % target_list)
                  code.putln('#else')
                  code.putln("%s = PySequence_ITEM(%s, %s-%d); " % (
                      item.py_result(), target_list, length_temp, i+1))
                  code.putln('#endif')
                  code.put_gotref(item.py_result())
                  coerced_arg.generate_evaluation_code(code)
  
              code.putln('#if !CYTHON_COMPILING_IN_CPYTHON')
              sublist_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
              code.putln('%s = PySequence_GetSlice(%s, 0, %s-%d); %s' % (
                  sublist_temp, target_list, length_temp, len(unpacked_fixed_items_right),
                  code.error_goto_if_null(sublist_temp, self.pos)))
              code.put_gotref(sublist_temp)
              code.funcstate.release_temp(length_temp)
              code.put_decref(target_list, py_object_type)
              code.putln('%s = %s; %s = NULL;' % (target_list, sublist_temp, sublist_temp))
              code.putln('#else')
              code.putln('%s = %s;' % (sublist_temp, sublist_temp)) # avoid warning about unused variable
              code.funcstate.release_temp(sublist_temp)
              code.putln('#endif')
  
          for i, arg in enumerate(self.args):
              arg.generate_assignment_code(self.coerced_unpacked_items[i], code)
  
      def annotate(self, code):
          for arg in self.args:
              arg.annotate(code)
          if self.unpacked_items:
              for arg in self.unpacked_items:
                  arg.annotate(code)
              for arg in self.coerced_unpacked_items:
                  arg.annotate(code)
  
  
  class TupleNode(SequenceNode):
      #  Tuple constructor.
  
      type = tuple_type
      is_partly_literal = False
  
      gil_message = "Constructing Python tuple"
  
      def analyse_types(self, env, skip_children=False):
          if len(self.args) == 0:
              node = self
              node.is_temp = False
              node.is_literal = True
          else:
              node = SequenceNode.analyse_types(self, env, skip_children)
              for child in node.args:
                  if not child.is_literal:
                      break
              else:
                  if not node.mult_factor or node.mult_factor.is_literal and \
                         isinstance(node.mult_factor.constant_result, (int, long)):
                      node.is_temp = False
                      node.is_literal = True
                  else:
                      if not node.mult_factor.type.is_pyobject:
                          node.mult_factor = node.mult_factor.coerce_to_pyobject(env)
                      node.is_temp = True
                      node.is_partly_literal = True
          return node
  
      def is_simple(self):
          # either temp or constant => always simple
          return True
  
      def nonlocally_immutable(self):
          # either temp or constant => always safe
          return True
  
      def calculate_result_code(self):
          if len(self.args) > 0:
              return self.result_code
          else:
              return Naming.empty_tuple
  
      def calculate_constant_result(self):
          self.constant_result = tuple([
                  arg.constant_result for arg in self.args])
  
      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):
          if len(self.args) == 0:
              # result_code is Naming.empty_tuple
              return
          if self.is_partly_literal:
              # underlying tuple is const, but factor is not
              tuple_target = code.get_py_const(py_object_type, 'tuple', cleanup_level=2)
              const_code = code.get_cached_constants_writer()
              const_code.mark_pos(self.pos)
              self.generate_sequence_packing_code(const_code, tuple_target, plain=True)
              const_code.put_giveref(tuple_target)
              code.putln('%s = PyNumber_Multiply(%s, %s); %s' % (
                  self.result(), tuple_target, self.mult_factor.py_result(),
                  code.error_goto_if_null(self.result(), self.pos)
                  ))
              code.put_gotref(self.py_result())
          elif self.is_literal:
              # non-empty cached tuple => result is global constant,
              # creation code goes into separate code writer
              self.result_code = code.get_py_const(py_object_type, 'tuple', cleanup_level=2)
              code = code.get_cached_constants_writer()
              code.mark_pos(self.pos)
              self.generate_sequence_packing_code(code)
              code.put_giveref(self.py_result())
          else:
              self.generate_sequence_packing_code(code)
  
  
  class ListNode(SequenceNode):
      #  List constructor.
  
      # obj_conversion_errors    [PyrexError]   used internally
      # orignial_args            [ExprNode]     used internally
  
      obj_conversion_errors = []
      type = list_type
      in_module_scope = False
  
      gil_message = "Constructing Python list"
  
      def type_dependencies(self, env):
          return ()
  
      def infer_type(self, env):
          # TOOD: Infer non-object list arrays.
          return list_type
  
      def analyse_expressions(self, env):
          node = SequenceNode.analyse_expressions(self, env)
          return node.coerce_to_pyobject(env)
  
      def analyse_types(self, env):
          hold_errors()
          self.original_args = list(self.args)
          node = SequenceNode.analyse_types(self, env)
          node.obj_conversion_errors = held_errors()
          release_errors(ignore=True)
          if env.is_module_scope:
              self.in_module_scope = True
          return node
  
      def coerce_to(self, dst_type, env):
          if dst_type.is_pyobject:
              for err in self.obj_conversion_errors:
                  report_error(err)
              self.obj_conversion_errors = []
              if not self.type.subtype_of(dst_type):
                  error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
          elif self.mult_factor:
              error(self.pos, "Cannot coerce multiplied list to '%s'" % dst_type)
          elif dst_type.is_ptr and dst_type.base_type is not PyrexTypes.c_void_type:
              base_type = dst_type.base_type
              self.type = PyrexTypes.CArrayType(base_type, len(self.args))
              for i in range(len(self.original_args)):
                  arg = self.args[i]
                  if isinstance(arg, CoerceToPyTypeNode):
                      arg = arg.arg
                  self.args[i] = arg.coerce_to(base_type, env)
          elif dst_type.is_struct:
              if len(self.args) > len(dst_type.scope.var_entries):
                  error(self.pos, "Too may members for '%s'" % dst_type)
              else:
                  if len(self.args) < len(dst_type.scope.var_entries):
                      warning(self.pos, "Too few members for '%s'" % dst_type, 1)
                  for i, (arg, member) in enumerate(zip(self.original_args, dst_type.scope.var_entries)):
                      if isinstance(arg, CoerceToPyTypeNode):
                          arg = arg.arg
                      self.args[i] = arg.coerce_to(member.type, env)
              self.type = dst_type
          else:
              self.type = error_type
              error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
          return self
  
      def as_tuple(self):
          t = TupleNode(self.pos, args=self.args, mult_factor=self.mult_factor)
          if isinstance(self.constant_result, list):
              t.constant_result = tuple(self.constant_result)
          return t
  
      def allocate_temp_result(self, code):
          if self.type.is_array and self.in_module_scope:
              self.temp_code = code.funcstate.allocate_temp(
                  self.type, manage_ref=False, static=True)
          else:
              SequenceNode.allocate_temp_result(self, code)
  
      def release_temp_result(self, env):
          if self.type.is_array:
              # To be valid C++, we must allocate the memory on the stack
              # manually and be sure not to reuse it for something else.
              pass
          else:
              SequenceNode.release_temp_result(self, env)
  
      def calculate_constant_result(self):
          if self.mult_factor:
              raise ValueError() # may exceed the compile time memory
          self.constant_result = [
              arg.constant_result for arg in self.args]
  
      def compile_time_value(self, denv):
          l = self.compile_time_value_list(denv)
          if self.mult_factor:
              l *= self.mult_factor.compile_time_value(denv)
          return l
  
      def generate_operation_code(self, code):
          if self.type.is_pyobject:
              for err in self.obj_conversion_errors:
                  report_error(err)
              self.generate_sequence_packing_code(code)
          elif self.type.is_array:
              for i, arg in enumerate(self.args):
                  code.putln("%s[%s] = %s;" % (
                                  self.result(),
                                  i,
                                  arg.result()))
          elif self.type.is_struct:
              for arg, member in zip(self.args, self.type.scope.var_entries):
                  code.putln("%s.%s = %s;" % (
                          self.result(),
                          member.cname,
                          arg.result()))
          else:
              raise InternalError("List type never specified")
  
  
  class ScopedExprNode(ExprNode):
      # Abstract base class for ExprNodes that have their own local
      # scope, such as generator expressions.
      #
      # expr_scope    Scope  the inner scope of the expression
  
      subexprs = []
      expr_scope = None
  
      # does this node really have a local scope, e.g. does it leak loop
      # variables or not?  non-leaking Py3 behaviour is default, except
      # for list comprehensions where the behaviour differs in Py2 and
      # Py3 (set in Parsing.py based on parser context)
      has_local_scope = True
  
      def init_scope(self, outer_scope, expr_scope=None):
          if expr_scope is not None:
              self.expr_scope = expr_scope
          elif self.has_local_scope:
              self.expr_scope = Symtab.GeneratorExpressionScope(outer_scope)
          else:
              self.expr_scope = None
  
      def analyse_declarations(self, env):
          self.init_scope(env)
  
      def analyse_scoped_declarations(self, env):
          # this is called with the expr_scope as env
          pass
  
      def analyse_types(self, env):
          # no recursion here, the children will be analysed separately below
          return self
  
      def analyse_scoped_expressions(self, env):
          # this is called with the expr_scope as env
          return self
  
      def generate_evaluation_code(self, code):
          # set up local variables and free their references on exit
          generate_inner_evaluation_code = super(ScopedExprNode, self).generate_evaluation_code
          if not self.has_local_scope or not self.expr_scope.var_entries:
              # no local variables => delegate, done
              generate_inner_evaluation_code(code)
              return
  
          code.putln('{ /* enter inner scope */')
          py_entries = []
          for entry in self.expr_scope.var_entries:
              if not entry.in_closure:
                  code.put_var_declaration(entry)
                  if entry.type.is_pyobject and entry.used:
                      py_entries.append(entry)
          if not py_entries:
              # no local Python references => no cleanup required
              generate_inner_evaluation_code(code)
              code.putln('} /* exit inner scope */')
              return
  
          # must free all local Python references at each exit point
          old_loop_labels = tuple(code.new_loop_labels())
          old_error_label = code.new_error_label()
  
          generate_inner_evaluation_code(code)
  
          # normal (non-error) exit
          for entry in py_entries:
              code.put_var_decref(entry)
  
          # error/loop body exit points
          exit_scope = code.new_label('exit_scope')
          code.put_goto(exit_scope)
          for label, old_label in ([(code.error_label, old_error_label)] +
                                   list(zip(code.get_loop_labels(), old_loop_labels))):
              if code.label_used(label):
                  code.put_label(label)
                  for entry in py_entries:
                      code.put_var_decref(entry)
                  code.put_goto(old_label)
          code.put_label(exit_scope)
          code.putln('} /* exit inner scope */')
  
          code.set_loop_labels(old_loop_labels)
          code.error_label = old_error_label
  
  
  class ComprehensionNode(ScopedExprNode):
      # A list/set/dict comprehension
  
      child_attrs = ["loop"]
  
      is_temp = True
  
      def infer_type(self, env):
          return self.type
  
      def analyse_declarations(self, env):
          self.append.target = self # this is used in the PyList_Append of the inner loop
          self.init_scope(env)
  
      def analyse_scoped_declarations(self, env):
          self.loop.analyse_declarations(env)
  
      def analyse_types(self, env):
          if not self.has_local_scope:
              self.loop = self.loop.analyse_expressions(env)
          return self
  
      def analyse_scoped_expressions(self, env):
          if self.has_local_scope:
              self.loop = self.loop.analyse_expressions(env)
          return self
  
      def may_be_none(self):
          return False
  
      def generate_result_code(self, code):
          self.generate_operation_code(code)
  
      def generate_operation_code(self, code):
          if self.type is Builtin.list_type:
              create_code = 'PyList_New(0)'
          elif self.type is Builtin.set_type:
              create_code = 'PySet_New(NULL)'
          elif self.type is Builtin.dict_type:
              create_code = 'PyDict_New()'
          else:
              raise InternalError("illegal type for comprehension: %s" % self.type)
          code.putln('%s = %s; %s' % (
              self.result(), create_code,
              code.error_goto_if_null(self.result(), self.pos)))
  
          code.put_gotref(self.result())
          self.loop.generate_execution_code(code)
  
      def annotate(self, code):
          self.loop.annotate(code)
  
  
  class ComprehensionAppendNode(Node):
      # Need to be careful to avoid infinite recursion:
      # target must not be in child_attrs/subexprs
  
      child_attrs = ['expr']
      target = None
  
      type = PyrexTypes.c_int_type
  
      def analyse_expressions(self, env):
          self.expr = self.expr.analyse_expressions(env)
          if not self.expr.type.is_pyobject:
              self.expr = self.expr.coerce_to_pyobject(env)
          return self
  
      def generate_execution_code(self, code):
          if self.target.type is list_type:
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("ListCompAppend", "Optimize.c"))
              function = "__Pyx_ListComp_Append"
          elif self.target.type is set_type:
              function = "PySet_Add"
          else:
              raise InternalError(
                  "Invalid type for comprehension node: %s" % self.target.type)
  
          self.expr.generate_evaluation_code(code)
          code.putln(code.error_goto_if("%s(%s, (PyObject*)%s)" % (
              function,
              self.target.result(),
              self.expr.result()
              ), self.pos))
          self.expr.generate_disposal_code(code)
          self.expr.free_temps(code)
  
      def generate_function_definitions(self, env, code):
          self.expr.generate_function_definitions(env, code)
  
      def annotate(self, code):
          self.expr.annotate(code)
  
  class DictComprehensionAppendNode(ComprehensionAppendNode):
      child_attrs = ['key_expr', 'value_expr']
  
      def analyse_expressions(self, env):
          self.key_expr = self.key_expr.analyse_expressions(env)
          if not self.key_expr.type.is_pyobject:
              self.key_expr = self.key_expr.coerce_to_pyobject(env)
          self.value_expr = self.value_expr.analyse_expressions(env)
          if not self.value_expr.type.is_pyobject:
              self.value_expr = self.value_expr.coerce_to_pyobject(env)
          return self
  
      def generate_execution_code(self, code):
          self.key_expr.generate_evaluation_code(code)
          self.value_expr.generate_evaluation_code(code)
          code.putln(code.error_goto_if("PyDict_SetItem(%s, (PyObject*)%s, (PyObject*)%s)" % (
              self.target.result(),
              self.key_expr.result(),
              self.value_expr.result()
              ), self.pos))
          self.key_expr.generate_disposal_code(code)
          self.key_expr.free_temps(code)
          self.value_expr.generate_disposal_code(code)
          self.value_expr.free_temps(code)
  
      def generate_function_definitions(self, env, code):
          self.key_expr.generate_function_definitions(env, code)
          self.value_expr.generate_function_definitions(env, code)
  
      def annotate(self, code):
          self.key_expr.annotate(code)
          self.value_expr.annotate(code)
  
  
  class InlinedGeneratorExpressionNode(ScopedExprNode):
      # An inlined generator expression for which the result is
      # calculated inside of the loop.  This will only be created by
      # transforms when replacing builtin calls on generator
      # expressions.
      #
      # loop           ForStatNode      the for-loop, not containing any YieldExprNodes
      # result_node    ResultRefNode    the reference to the result value temp
      # orig_func      String           the name of the builtin function this node replaces
  
      child_attrs = ["loop"]
      loop_analysed = False
      type = py_object_type
  
      def analyse_scoped_declarations(self, env):
          self.loop.analyse_declarations(env)
  
      def may_be_none(self):
          return False
  
      def annotate(self, code):
          self.loop.annotate(code)
  
      def infer_type(self, env):
          return self.result_node.infer_type(env)
  
      def analyse_types(self, env):
          if not self.has_local_scope:
              self.loop_analysed = True
              self.loop = self.loop.analyse_expressions(env)
          self.type = self.result_node.type
          self.is_temp = True
          return self
  
      def analyse_scoped_expressions(self, env):
          self.loop_analysed = True
          if self.has_local_scope:
              self.loop = self.loop.analyse_expressions(env)
          return self
  
      def coerce_to(self, dst_type, env):
          if self.orig_func == 'sum' and dst_type.is_numeric and not self.loop_analysed:
              # We can optimise by dropping the aggregation variable and
              # the add operations into C.  This can only be done safely
              # before analysing the loop body, after that, the result
              # reference type will have infected expressions and
              # assignments.
              self.result_node.type = self.type = dst_type
              return self
          return super(InlinedGeneratorExpressionNode, self).coerce_to(dst_type, env)
  
      def generate_result_code(self, code):
          self.result_node.result_code = self.result()
          self.loop.generate_execution_code(code)
  
  
  class SetNode(ExprNode):
      #  Set constructor.
  
      type = set_type
  
      subexprs = ['args']
  
      gil_message = "Constructing Python set"
  
      def analyse_types(self, env):
          for i in range(len(self.args)):
              arg = self.args[i]
              arg = arg.analyse_types(env)
              self.args[i] = arg.coerce_to_pyobject(env)
          self.type = set_type
          self.is_temp = 1
          return self
  
      def may_be_none(self):
          return False
  
      def calculate_constant_result(self):
          self.constant_result = set([
                  arg.constant_result for arg in self.args])
  
      def compile_time_value(self, denv):
          values = [arg.compile_time_value(denv) for arg in self.args]
          try:
              return set(values)
          except Exception, e:
              self.compile_time_value_error(e)
  
      def generate_evaluation_code(self, code):
          code.globalstate.use_utility_code(Builtin.py_set_utility_code)
          self.allocate_temp_result(code)
          code.putln(
              "%s = PySet_New(0); %s" % (
                  self.result(),
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
          for arg in self.args:
              arg.generate_evaluation_code(code)
              code.put_error_if_neg(
                  self.pos,
                  "PySet_Add(%s, %s)" % (self.result(), arg.py_result()))
              arg.generate_disposal_code(code)
              arg.free_temps(code)
  
  
  class DictNode(ExprNode):
      #  Dictionary constructor.
      #
      #  key_value_pairs     [DictItemNode]
      #  exclude_null_values [boolean]          Do not add NULL values to dict
      #
      # obj_conversion_errors    [PyrexError]   used internally
  
      subexprs = ['key_value_pairs']
      is_temp = 1
      exclude_null_values = False
      type = dict_type
  
      obj_conversion_errors = []
  
      @classmethod
      def from_pairs(cls, pos, pairs):
          return cls(pos, key_value_pairs=[
                  DictItemNode(pos, key=k, value=v) for k, v in pairs])
  
      def calculate_constant_result(self):
          self.constant_result = dict([
                  item.constant_result for item in self.key_value_pairs])
  
      def compile_time_value(self, denv):
          pairs = [(item.key.compile_time_value(denv), item.value.compile_time_value(denv))
              for item in self.key_value_pairs]
          try:
              return dict(pairs)
          except Exception, e:
              self.compile_time_value_error(e)
  
      def type_dependencies(self, env):
          return ()
  
      def infer_type(self, env):
          # TOOD: Infer struct constructors.
          return dict_type
  
      def analyse_types(self, env):
          hold_errors()
          self.key_value_pairs = [ item.analyse_types(env)
                                   for item in self.key_value_pairs ]
          self.obj_conversion_errors = held_errors()
          release_errors(ignore=True)
          return self
  
      def may_be_none(self):
          return False
  
      def coerce_to(self, dst_type, env):
          if dst_type.is_pyobject:
              self.release_errors()
              if not self.type.subtype_of(dst_type):
                  error(self.pos, "Cannot interpret dict as type '%s'" % dst_type)
          elif dst_type.is_struct_or_union:
              self.type = dst_type
              if not dst_type.is_struct and len(self.key_value_pairs) != 1:
                  error(self.pos, "Exactly one field must be specified to convert to union '%s'" % dst_type)
              elif dst_type.is_struct and len(self.key_value_pairs) < len(dst_type.scope.var_entries):
                  warning(self.pos, "Not all members given for struct '%s'" % dst_type, 1)
              for item in self.key_value_pairs:
                  if isinstance(item.key, CoerceToPyTypeNode):
                      item.key = item.key.arg
                  if not item.key.is_string_literal:
                      error(item.key.pos, "Invalid struct field identifier")
                      item.key = StringNode(item.key.pos, value="<error>")
                  else:
                      key = str(item.key.value) # converts string literals to unicode in Py3
                      member = dst_type.scope.lookup_here(key)
                      if not member:
                          error(item.key.pos, "struct '%s' has no field '%s'" % (dst_type, key))
                      else:
                          value = item.value
                          if isinstance(value, CoerceToPyTypeNode):
                              value = value.arg
                          item.value = value.coerce_to(member.type, env)
          else:
              self.type = error_type
              error(self.pos, "Cannot interpret dict as type '%s'" % dst_type)
          return self
  
      def release_errors(self):
          for err in self.obj_conversion_errors:
              report_error(err)
          self.obj_conversion_errors = []
  
      gil_message = "Constructing Python dict"
  
      def generate_evaluation_code(self, code):
          #  Custom method used here because key-value
          #  pairs are evaluated and used one at a time.
          code.mark_pos(self.pos)
          self.allocate_temp_result(code)
          if self.type.is_pyobject:
              self.release_errors()
              code.putln(
                  "%s = PyDict_New(); %s" % (
                      self.result(),
                      code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.py_result())
          for item in self.key_value_pairs:
              item.generate_evaluation_code(code)
              if self.type.is_pyobject:
                  if self.exclude_null_values:
                      code.putln('if (%s) {' % item.value.py_result())
                  code.put_error_if_neg(self.pos,
                      "PyDict_SetItem(%s, %s, %s)" % (
                          self.result(),
                          item.key.py_result(),
                          item.value.py_result()))
                  if self.exclude_null_values:
                      code.putln('}')
              else:
                  code.putln("%s.%s = %s;" % (
                          self.result(),
                          item.key.value,
                          item.value.result()))
              item.generate_disposal_code(code)
              item.free_temps(code)
  
      def annotate(self, code):
          for item in self.key_value_pairs:
              item.annotate(code)
  
  class DictItemNode(ExprNode):
      # Represents a single item in a DictNode
      #
      # key          ExprNode
      # value        ExprNode
      subexprs = ['key', 'value']
  
      nogil_check = None # Parent DictNode takes care of it
  
      def calculate_constant_result(self):
          self.constant_result = (
              self.key.constant_result, self.value.constant_result)
  
      def analyse_types(self, env):
          self.key = self.key.analyse_types(env)
          self.value = self.value.analyse_types(env)
          self.key = self.key.coerce_to_pyobject(env)
          self.value = self.value.coerce_to_pyobject(env)
          return self
  
      def generate_evaluation_code(self, code):
          self.key.generate_evaluation_code(code)
          self.value.generate_evaluation_code(code)
  
      def generate_disposal_code(self, code):
          self.key.generate_disposal_code(code)
          self.value.generate_disposal_code(code)
  
      def free_temps(self, code):
          self.key.free_temps(code)
          self.value.free_temps(code)
  
      def __iter__(self):
          return iter([self.key, self.value])
  
  
  class SortedDictKeysNode(ExprNode):
      # build sorted list of dict keys, e.g. for dir()
      subexprs = ['arg']
  
      is_temp = True
  
      def __init__(self, arg):
          ExprNode.__init__(self, arg.pos, arg=arg)
          self.type = Builtin.list_type
  
      def analyse_types(self, env):
          arg = self.arg.analyse_types(env)
          if arg.type is Builtin.dict_type:
              arg = arg.as_none_safe_node(
                  "'NoneType' object is not iterable")
          self.arg = arg
          return self
  
      def may_be_none(self):
          return False
  
      def generate_result_code(self, code):
          dict_result = self.arg.py_result()
          if self.arg.type is Builtin.dict_type:
              function = 'PyDict_Keys'
          else:
              function = 'PyMapping_Keys'
          code.putln('%s = %s(%s); %s' % (
              self.result(), function, dict_result,
              code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
          code.put_error_if_neg(
              self.pos, 'PyList_Sort(%s)' % self.py_result())
  
  
  class ModuleNameMixin(object):
      def get_py_mod_name(self, code):
          return code.get_py_string_const(
              self.module_name, identifier=True)
  
      def get_py_qualified_name(self, code):
          return code.get_py_string_const(
              self.qualname, identifier=True)
  
  
  class ClassNode(ExprNode, ModuleNameMixin):
      #  Helper class used in the implementation of Python
      #  class definitions. Constructs a class object given
      #  a name, tuple of bases and class dictionary.
      #
      #  name         EncodedString      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  EncodedString      Name of defining module
  
      subexprs = ['bases', 'doc']
  
      def analyse_types(self, env):
          self.bases = self.bases.analyse_types(env)
          if self.doc:
              self.doc = self.doc.analyse_types(env)
              self.doc = self.doc.coerce_to_pyobject(env)
          self.type = py_object_type
          self.is_temp = 1
          env.use_utility_code(UtilityCode.load_cached("CreateClass", "ObjectHandling.c"))
          return self
  
      def may_be_none(self):
          return True
  
      gil_message = "Constructing Python class"
  
      def generate_result_code(self, code):
          cname = code.intern_identifier(self.name)
  
          if self.doc:
              code.put_error_if_neg(self.pos,
                  'PyDict_SetItem(%s, %s, %s)' % (
                      self.dict.py_result(),
                      code.intern_identifier(
                          StringEncoding.EncodedString("__doc__")),
                      self.doc.py_result()))
          py_mod_name = self.get_py_mod_name(code)
          qualname = self.get_py_qualified_name(code)
          code.putln(
              '%s = __Pyx_CreateClass(%s, %s, %s, %s, %s); %s' % (
                  self.result(),
                  self.bases.py_result(),
                  self.dict.py_result(),
                  cname,
                  qualname,
                  py_mod_name,
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  
  class Py3ClassNode(ExprNode):
      #  Helper class used in the implementation of Python3+
      #  class definitions. Constructs a class object given
      #  a name, tuple of bases and class dictionary.
      #
      #  name         EncodedString      Name of the class
      #  dict         ExprNode           Class dict (not owned by this node)
      #  module_name  EncodedString      Name of defining module
      #  calculate_metaclass  bool       should call CalculateMetaclass()
      #  allow_py2_metaclass  bool       should look for Py2 metaclass
  
      subexprs = []
  
      def analyse_types(self, env):
          self.type = py_object_type
          self.is_temp = 1
          return self
  
      def may_be_none(self):
          return True
  
      gil_message = "Constructing Python class"
  
      def generate_result_code(self, code):
          code.globalstate.use_utility_code(UtilityCode.load_cached("Py3ClassCreate", "ObjectHandling.c"))
          cname = code.intern_identifier(self.name)
          if self.mkw:
              mkw = self.mkw.py_result()
          else:
              mkw = 'NULL'
          if self.metaclass:
              metaclass = self.metaclass.result()
          else:
              metaclass = "((PyObject*)&__Pyx_DefaultClassType)"
          code.putln(
              '%s = __Pyx_Py3ClassCreate(%s, %s, %s, %s, %s, %d, %d); %s' % (
                  self.result(),
                  metaclass,
                  cname,
                  self.bases.py_result(),
                  self.dict.py_result(),
                  mkw,
                  self.calculate_metaclass,
                  self.allow_py2_metaclass,
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  class KeywordArgsNode(ExprNode):
      #  Helper class for keyword arguments.
      #
      #  starstar_arg      DictNode
      #  keyword_args      [DictItemNode]
  
      subexprs = ['starstar_arg', 'keyword_args']
      is_temp = 1
      type = dict_type
  
      def calculate_constant_result(self):
          result = dict(self.starstar_arg.constant_result)
          for item in self.keyword_args:
              key, value = item.constant_result
              if key in result:
                  raise ValueError("duplicate keyword argument found: %s" % key)
              result[key] = value
          self.constant_result = result
  
      def compile_time_value(self, denv):
          result = self.starstar_arg.compile_time_value(denv)
          pairs = [ (item.key.compile_time_value(denv), item.value.compile_time_value(denv))
                    for item in self.keyword_args ]
          try:
              result = dict(result)
              for key, value in pairs:
                  if key in result:
                      raise ValueError("duplicate keyword argument found: %s" % key)
                  result[key] = value
          except Exception, e:
              self.compile_time_value_error(e)
          return result
  
      def type_dependencies(self, env):
          return ()
  
      def infer_type(self, env):
          return dict_type
  
      def analyse_types(self, env):
          arg = self.starstar_arg.analyse_types(env)
          arg = arg.coerce_to_pyobject(env)
          self.starstar_arg = arg.as_none_safe_node(
              # FIXME: CPython's error message starts with the runtime function name
              'argument after ** must be a mapping, not NoneType')
          self.keyword_args = [ item.analyse_types(env)
                                for item in self.keyword_args ]
          return self
  
      def may_be_none(self):
          return False
  
      gil_message = "Constructing Python dict"
  
      def generate_evaluation_code(self, code):
          code.mark_pos(self.pos)
          self.allocate_temp_result(code)
          self.starstar_arg.generate_evaluation_code(code)
          if self.starstar_arg.type is not Builtin.dict_type:
              # CPython supports calling functions with non-dicts, so do we
              code.putln('if (likely(PyDict_Check(%s))) {' %
                         self.starstar_arg.py_result())
          if self.keyword_args:
              code.putln(
                  "%s = PyDict_Copy(%s); %s" % (
                      self.result(),
                      self.starstar_arg.py_result(),
                      code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.py_result())
          else:
              code.putln("%s = %s;" % (
                  self.result(),
                  self.starstar_arg.py_result()))
              code.put_incref(self.result(), py_object_type)
          if self.starstar_arg.type is not Builtin.dict_type:
              code.putln('} else {')
              code.putln(
                  "%s = PyObject_CallFunctionObjArgs("
                  "(PyObject*)&PyDict_Type, %s, NULL); %s" % (
                      self.result(),
                      self.starstar_arg.py_result(),
                      code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.py_result())
              code.putln('}')
          self.starstar_arg.generate_disposal_code(code)
          self.starstar_arg.free_temps(code)
  
          if not self.keyword_args:
              return
  
          code.globalstate.use_utility_code(
              UtilityCode.load_cached("RaiseDoubleKeywords", "FunctionArguments.c"))
          for item in self.keyword_args:
              item.generate_evaluation_code(code)
              code.putln("if (unlikely(PyDict_GetItem(%s, %s))) {" % (
                      self.result(),
                      item.key.py_result()))
              # FIXME: find out function name at runtime!
              code.putln('__Pyx_RaiseDoubleKeywordsError("function", %s); %s' % (
                  item.key.py_result(),
                  code.error_goto(self.pos)))
              code.putln("}")
              code.put_error_if_neg(self.pos,
                  "PyDict_SetItem(%s, %s, %s)" % (
                      self.result(),
                      item.key.py_result(),
                      item.value.py_result()))
              item.generate_disposal_code(code)
              item.free_temps(code)
  
      def annotate(self, code):
          self.starstar_arg.annotate(code)
          for item in self.keyword_args:
              item.annotate(code)
  
  class PyClassMetaclassNode(ExprNode):
      # Helper class holds Python3 metaclass object
      #
      #  bases        ExprNode           Base class tuple (not owned by this node)
      #  mkw          ExprNode           Class keyword arguments (not owned by this node)
  
      subexprs = []
  
      def analyse_types(self, env):
          self.type = py_object_type
          self.is_temp = True
          return self
  
      def may_be_none(self):
          return True
  
      def generate_result_code(self, code):
          if self.mkw:
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("Py3MetaclassGet", "ObjectHandling.c"))
              call = "__Pyx_Py3MetaclassGet(%s, %s)" % (
                  self.bases.result(),
                  self.mkw.result())
          else:
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("CalculateMetaclass", "ObjectHandling.c"))
              call = "__Pyx_CalculateMetaclass(NULL, %s)" % (
                  self.bases.result())
          code.putln(
              "%s = %s; %s" % (
                  self.result(), call,
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  class PyClassNamespaceNode(ExprNode, ModuleNameMixin):
      # Helper class holds Python3 namespace object
      #
      # All this are not owned by this node
      #  metaclass    ExprNode           Metaclass object
      #  bases        ExprNode           Base class tuple
      #  mkw          ExprNode           Class keyword arguments
      #  doc          ExprNode or None   Doc string (owned)
  
      subexprs = ['doc']
  
      def analyse_types(self, env):
          if self.doc:
              self.doc = self.doc.analyse_types(env)
              self.doc = self.doc.coerce_to_pyobject(env)
          self.type = py_object_type
          self.is_temp = 1
          return self
  
      def may_be_none(self):
          return True
  
      def generate_result_code(self, code):
          cname = code.intern_identifier(self.name)
          py_mod_name = self.get_py_mod_name(code)
          qualname = self.get_py_qualified_name(code)
          if self.doc:
              doc_code = self.doc.result()
          else:
              doc_code = '(PyObject *) NULL'
          if self.mkw:
              mkw = self.mkw.py_result()
          else:
              mkw = '(PyObject *) NULL'
          if self.metaclass:
              metaclass = self.metaclass.result()
          else:
              metaclass = "(PyObject *) NULL"
          code.putln(
              "%s = __Pyx_Py3MetaclassPrepare(%s, %s, %s, %s, %s, %s, %s); %s" % (
                  self.result(),
                  metaclass,
                  self.bases.result(),
                  cname,
                  qualname,
                  mkw,
                  py_mod_name,
                  doc_code,
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  
  class ClassCellInjectorNode(ExprNode):
      # Initialize CyFunction.func_classobj
      is_temp = True
      type = py_object_type
      subexprs = []
      is_active = False
  
      def analyse_expressions(self, env):
          if self.is_active:
              env.use_utility_code(
                  UtilityCode.load_cached("CyFunctionClassCell", "CythonFunction.c"))
          return self
  
      def generate_evaluation_code(self, code):
          if self.is_active:
              self.allocate_temp_result(code)
              code.putln(
                  '%s = PyList_New(0); %s' % (
                      self.result(),
                      code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.result())
  
      def generate_injection_code(self, code, classobj_cname):
          if self.is_active:
              code.putln('__Pyx_CyFunction_InitClassCell(%s, %s);' % (
                  self.result(), classobj_cname))
  
  
  class ClassCellNode(ExprNode):
      # Class Cell for noargs super()
      subexprs = []
      is_temp = True
      is_generator = False
      type = py_object_type
  
      def analyse_types(self, env):
          return self
  
      def generate_result_code(self, code):
          if not self.is_generator:
              code.putln('%s = __Pyx_CyFunction_GetClassObj(%s);' % (
                  self.result(),
                  Naming.self_cname))
          else:
              code.putln('%s =  %s->classobj;' % (
                  self.result(), Naming.generator_cname))
          code.putln(
              'if (!%s) { PyErr_SetString(PyExc_SystemError, '
              '"super(): empty __class__ cell"); %s }' % (
                  self.result(),
                  code.error_goto(self.pos)))
          code.put_incref(self.result(), py_object_type)
  
  
  class BoundMethodNode(ExprNode):
      #  Helper class used in the implementation of Python
      #  class definitions. Constructs an bound method
      #  object from a class and a function.
      #
      #  function      ExprNode   Function object
      #  self_object   ExprNode   self object
  
      subexprs = ['function']
  
      def analyse_types(self, env):
          self.function = self.function.analyse_types(env)
          self.type = py_object_type
          self.is_temp = 1
          return self
  
      gil_message = "Constructing a bound method"
  
      def generate_result_code(self, code):
          code.putln(
              "%s = PyMethod_New(%s, %s, (PyObject*)%s->ob_type); %s" % (
                  self.result(),
                  self.function.py_result(),
                  self.self_object.py_result(),
                  self.self_object.py_result(),
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  class UnboundMethodNode(ExprNode):
      #  Helper class used in the implementation of Python
      #  class definitions. Constructs an unbound method
      #  object from a class and a function.
      #
      #  function      ExprNode   Function object
  
      type = py_object_type
      is_temp = 1
  
      subexprs = ['function']
  
      def analyse_types(self, env):
          self.function = self.function.analyse_types(env)
          return self
  
      def may_be_none(self):
          return False
  
      gil_message = "Constructing an unbound method"
  
      def generate_result_code(self, code):
          class_cname = code.pyclass_stack[-1].classobj.result()
          code.putln(
              "%s = PyMethod_New(%s, 0, %s); %s" % (
                  self.result(),
                  self.function.py_result(),
                  class_cname,
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  
  class PyCFunctionNode(ExprNode, ModuleNameMixin):
      #  Helper class used in the implementation of Python
      #  functions.  Constructs a PyCFunction object
      #  from a PyMethodDef struct.
      #
      #  pymethdef_cname   string             PyMethodDef structure
      #  self_object       ExprNode or None
      #  binding           bool
      #  def_node          DefNode            the Python function node
      #  module_name       EncodedString      Name of defining module
      #  code_object       CodeObjectNode     the PyCodeObject creator node
  
      subexprs = ['code_object', 'defaults_tuple', 'defaults_kwdict',
                  'annotations_dict']
  
      self_object = None
      code_object = None
      binding = False
      def_node = None
      defaults = None
      defaults_struct = None
      defaults_pyobjects = 0
      defaults_tuple = None
      defaults_kwdict = None
      annotations_dict = None
  
      type = py_object_type
      is_temp = 1
  
      specialized_cpdefs = None
      is_specialization = False
  
      @classmethod
      def from_defnode(cls, node, binding):
          return cls(node.pos,
                     def_node=node,
                     pymethdef_cname=node.entry.pymethdef_cname,
                     binding=binding or node.specialized_cpdefs,
                     specialized_cpdefs=node.specialized_cpdefs,
                     code_object=CodeObjectNode(node))
  
      def analyse_types(self, env):
          if self.binding:
              self.analyse_default_args(env)
          return self
  
      def analyse_default_args(self, env):
          """
          Handle non-literal function's default arguments.
          """
          nonliteral_objects = []
          nonliteral_other = []
          default_args = []
          default_kwargs = []
          annotations = []
          for arg in self.def_node.args:
              if arg.default:
                  if not arg.default.is_literal:
                      arg.is_dynamic = True
                      if arg.type.is_pyobject:
                          nonliteral_objects.append(arg)
                      else:
                          nonliteral_other.append(arg)
                  else:
                      arg.default = DefaultLiteralArgNode(arg.pos, arg.default)
                  if arg.kw_only:
                      default_kwargs.append(arg)
                  else:
                      default_args.append(arg)
              if arg.annotation:
                  arg.annotation = arg.annotation.analyse_types(env)
                  if not arg.annotation.type.is_pyobject:
                      arg.annotation = arg.annotation.coerce_to_pyobject(env)
                  annotations.append((arg.pos, arg.name, arg.annotation))
          if self.def_node.return_type_annotation:
              annotations.append((self.def_node.return_type_annotation.pos,
                                  StringEncoding.EncodedString("return"),
                                  self.def_node.return_type_annotation))
  
          if nonliteral_objects or nonliteral_other:
              module_scope = env.global_scope()
              cname = module_scope.next_id(Naming.defaults_struct_prefix)
              scope = Symtab.StructOrUnionScope(cname)
              self.defaults = []
              for arg in nonliteral_objects:
                  entry = scope.declare_var(arg.name, arg.type, None,
                                            Naming.arg_prefix + arg.name,
                                            allow_pyobject=True)
                  self.defaults.append((arg, entry))
              for arg in nonliteral_other:
                  entry = scope.declare_var(arg.name, arg.type, None,
                                            Naming.arg_prefix + arg.name,
                                            allow_pyobject=False)
                  self.defaults.append((arg, entry))
              entry = module_scope.declare_struct_or_union(
                  None, 'struct', scope, 1, None, cname=cname)
              self.defaults_struct = scope
              self.defaults_pyobjects = len(nonliteral_objects)
              for arg, entry in self.defaults:
                  arg.default_value = '%s->%s' % (
                      Naming.dynamic_args_cname, entry.cname)
              self.def_node.defaults_struct = self.defaults_struct.name
  
          if default_args or default_kwargs:
              if self.defaults_struct is None:
                  if default_args:
                      defaults_tuple = TupleNode(self.pos, args=[
                          arg.default for arg in default_args])
                      self.defaults_tuple = defaults_tuple.analyse_types(env)
                  if default_kwargs:
                      defaults_kwdict = DictNode(self.pos, key_value_pairs=[
                          DictItemNode(
                              arg.pos,
                              key=IdentifierStringNode(arg.pos, value=arg.name),
                              value=arg.default)
                          for arg in default_kwargs])
                      self.defaults_kwdict = defaults_kwdict.analyse_types(env)
              else:
                  if default_args:
                      defaults_tuple = DefaultsTupleNode(
                          self.pos, default_args, self.defaults_struct)
                  else:
                      defaults_tuple = NoneNode(self.pos)
                  if default_kwargs:
                      defaults_kwdict = DefaultsKwDictNode(
                          self.pos, default_kwargs, self.defaults_struct)
                  else:
                      defaults_kwdict = NoneNode(self.pos)
  
                  defaults_getter = Nodes.DefNode(
                      self.pos, args=[], star_arg=None, starstar_arg=None,
                      body=Nodes.ReturnStatNode(
                          self.pos, return_type=py_object_type,
                          value=TupleNode(
                              self.pos, args=[defaults_tuple, defaults_kwdict])),
                      decorators=None,
                      name=StringEncoding.EncodedString("__defaults__"))
                  defaults_getter.analyse_declarations(env)
                  defaults_getter = defaults_getter.analyse_expressions(env)
                  defaults_getter.body = defaults_getter.body.analyse_expressions(
                      defaults_getter.local_scope)
                  defaults_getter.py_wrapper_required = False
                  defaults_getter.pymethdef_required = False
                  self.def_node.defaults_getter = defaults_getter
          if annotations:
              annotations_dict = DictNode(self.pos, key_value_pairs=[
                  DictItemNode(
                      pos, key=IdentifierStringNode(pos, value=name),
                      value=value)
                  for pos, name, value in annotations])
              self.annotations_dict = annotations_dict.analyse_types(env)
  
      def may_be_none(self):
          return False
  
      gil_message = "Constructing Python function"
  
      def self_result_code(self):
          if self.self_object is None:
              self_result = "NULL"
          else:
              self_result = self.self_object.py_result()
          return self_result
  
      def generate_result_code(self, code):
          if self.binding:
              self.generate_cyfunction_code(code)
          else:
              self.generate_pycfunction_code(code)
  
      def generate_pycfunction_code(self, code):
          py_mod_name = self.get_py_mod_name(code)
          code.putln(
              '%s = PyCFunction_NewEx(&%s, %s, %s); %s' % (
                  self.result(),
                  self.pymethdef_cname,
                  self.self_result_code(),
                  py_mod_name,
                  code.error_goto_if_null(self.result(), self.pos)))
  
          code.put_gotref(self.py_result())
  
      def generate_cyfunction_code(self, code):
          if self.specialized_cpdefs:
              def_node = self.specialized_cpdefs[0]
          else:
              def_node = self.def_node
  
          if self.specialized_cpdefs or self.is_specialization:
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("FusedFunction", "CythonFunction.c"))
              constructor = "__pyx_FusedFunction_NewEx"
          else:
              code.globalstate.use_utility_code(
                  UtilityCode.load_cached("CythonFunction", "CythonFunction.c"))
              constructor = "__Pyx_CyFunction_NewEx"
  
          if self.code_object:
              code_object_result = self.code_object.py_result()
          else:
              code_object_result = 'NULL'
  
          flags = []
          if def_node.is_staticmethod:
              flags.append('__Pyx_CYFUNCTION_STATICMETHOD')
          elif def_node.is_classmethod:
              flags.append('__Pyx_CYFUNCTION_CLASSMETHOD')
  
          if def_node.local_scope.parent_scope.is_c_class_scope:
              flags.append('__Pyx_CYFUNCTION_CCLASS')
  
          if flags:
              flags = ' | '.join(flags)
          else:
              flags = '0'
  
          code.putln(
              '%s = %s(&%s, %s, %s, %s, %s, %s, %s); %s' % (
                  self.result(),
                  constructor,
                  self.pymethdef_cname,
                  flags,
                  self.get_py_qualified_name(code),
                  self.self_result_code(),
                  self.get_py_mod_name(code),
                  "PyModule_GetDict(%s)" % Naming.module_cname,
                  code_object_result,
                  code.error_goto_if_null(self.result(), self.pos)))
  
          code.put_gotref(self.py_result())
  
          if def_node.requires_classobj:
              assert code.pyclass_stack, "pyclass_stack is empty"
              class_node = code.pyclass_stack[-1]
              code.put_incref(self.py_result(), py_object_type)
              code.putln(
                  'PyList_Append(%s, %s);' % (
                      class_node.class_cell.result(),
                      self.result()))
              code.put_giveref(self.py_result())
  
          if self.defaults:
              code.putln(
                  'if (!__Pyx_CyFunction_InitDefaults(%s, sizeof(%s), %d)) %s' % (
                      self.result(), self.defaults_struct.name,
                      self.defaults_pyobjects, code.error_goto(self.pos)))
              defaults = '__Pyx_CyFunction_Defaults(%s, %s)' % (
                  self.defaults_struct.name, self.result())
              for arg, entry in self.defaults:
                  arg.generate_assignment_code(code, target='%s->%s' % (
                      defaults, entry.cname))
  
          if self.defaults_tuple:
              code.putln('__Pyx_CyFunction_SetDefaultsTuple(%s, %s);' % (
                  self.result(), self.defaults_tuple.py_result()))
          if self.defaults_kwdict:
              code.putln('__Pyx_CyFunction_SetDefaultsKwDict(%s, %s);' % (
                  self.result(), self.defaults_kwdict.py_result()))
          if def_node.defaults_getter:
              code.putln('__Pyx_CyFunction_SetDefaultsGetter(%s, %s);' % (
                  self.result(), def_node.defaults_getter.entry.pyfunc_cname))
          if self.annotations_dict:
              code.putln('__Pyx_CyFunction_SetAnnotationsDict(%s, %s);' % (
                  self.result(), self.annotations_dict.py_result()))
  
  
  class InnerFunctionNode(PyCFunctionNode):
      # Special PyCFunctionNode that depends on a closure class
      #
  
      binding = True
      needs_self_code = True
  
      def self_result_code(self):
          if self.needs_self_code:
              return "((PyObject*)%s)" % Naming.cur_scope_cname
          return "NULL"
  
  
  class CodeObjectNode(ExprNode):
      # Create a PyCodeObject for a CyFunction instance.
      #
      # def_node   DefNode    the Python function node
      # varnames   TupleNode  a tuple with all local variable names
  
      subexprs = ['varnames']
      is_temp = False
  
      def __init__(self, def_node):
          ExprNode.__init__(self, def_node.pos, def_node=def_node)
          args = list(def_node.args)
          # if we have args/kwargs, then the first two in var_entries are those
          local_vars = [arg for arg in def_node.local_scope.var_entries if arg.name]
          self.varnames = TupleNode(
              def_node.pos,
              args=[IdentifierStringNode(arg.pos, value=arg.name)
                    for arg in args + local_vars],
              is_temp=0,
              is_literal=1)
  
      def may_be_none(self):
          return False
  
      def calculate_result_code(self):
          return self.result_code
  
      def generate_result_code(self, code):
          self.result_code = code.get_py_const(py_object_type, 'codeobj', cleanup_level=2)
  
          code = code.get_cached_constants_writer()
          code.mark_pos(self.pos)
          func = self.def_node
          func_name = code.get_py_string_const(
              func.name, identifier=True, is_str=False, unicode_value=func.name)
          # FIXME: better way to get the module file path at module init time? Encoding to use?
          file_path = StringEncoding.BytesLiteral(func.pos[0].get_filenametable_entry().encode('utf8'))
          file_path_const = code.get_py_string_const(file_path, identifier=False, is_str=True)
  
          flags = []
          if self.def_node.star_arg:
              flags.append('CO_VARARGS')
          if self.def_node.starstar_arg:
              flags.append('CO_VARKEYWORDS')
  
          code.putln("%s = (PyObject*)__Pyx_PyCode_New(%d, %d, %d, 0, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s); %s" % (
              self.result_code,
              len(func.args) - func.num_kwonly_args,  # argcount
              func.num_kwonly_args,      # kwonlyargcount (Py3 only)
              len(self.varnames.args),   # nlocals
              '|'.join(flags) or '0',    # flags
              Naming.empty_bytes,        # code
              Naming.empty_tuple,        # consts
              Naming.empty_tuple,        # names (FIXME)
              self.varnames.result(),    # varnames
              Naming.empty_tuple,        # freevars (FIXME)
              Naming.empty_tuple,        # cellvars (FIXME)
              file_path_const,           # filename
              func_name,                 # name
              self.pos[1],               # firstlineno
              Naming.empty_bytes,        # lnotab
              code.error_goto_if_null(self.result_code, self.pos),
              ))
  
  
  class DefaultLiteralArgNode(ExprNode):
      # CyFunction's literal argument default value
      #
      # Evaluate literal only once.
  
      subexprs = []
      is_literal = True
      is_temp = False
  
      def __init__(self, pos, arg):
          super(DefaultLiteralArgNode, self).__init__(pos)
          self.arg = arg
          self.type = self.arg.type
          self.evaluated = False
  
      def analyse_types(self, env):
          return self
  
      def generate_result_code(self, code):
          pass
  
      def generate_evaluation_code(self, code):
          if not self.evaluated:
              self.arg.generate_evaluation_code(code)
              self.evaluated = True
  
      def result(self):
          return self.type.cast_code(self.arg.result())
  
  
  class DefaultNonLiteralArgNode(ExprNode):
      # CyFunction's non-literal argument default value
  
      subexprs = []
  
      def __init__(self, pos, arg, defaults_struct):
          super(DefaultNonLiteralArgNode, self).__init__(pos)
          self.arg = arg
          self.defaults_struct = defaults_struct
  
      def analyse_types(self, env):
          self.type = self.arg.type
          self.is_temp = False
          return self
  
      def generate_result_code(self, code):
          pass
  
      def result(self):
          return '__Pyx_CyFunction_Defaults(%s, %s)->%s' % (
              self.defaults_struct.name, Naming.self_cname,
              self.defaults_struct.lookup(self.arg.name).cname)
  
  
  class DefaultsTupleNode(TupleNode):
      # CyFunction's __defaults__ tuple
  
      def __init__(self, pos, defaults, defaults_struct):
          args = []
          for arg in defaults:
              if not arg.default.is_literal:
                  arg = DefaultNonLiteralArgNode(pos, arg, defaults_struct)
              else:
                  arg = arg.default
              args.append(arg)
          super(DefaultsTupleNode, self).__init__(pos, args=args)
  
  
  class DefaultsKwDictNode(DictNode):
      # CyFunction's __kwdefaults__ dict
  
      def __init__(self, pos, defaults, defaults_struct):
          items = []
          for arg in defaults:
              name = IdentifierStringNode(arg.pos, value=arg.name)
              if not arg.default.is_literal:
                  arg = DefaultNonLiteralArgNode(pos, arg, defaults_struct)
              else:
                  arg = arg.default
              items.append(DictItemNode(arg.pos, key=name, value=arg))
          super(DefaultsKwDictNode, self).__init__(pos, key_value_pairs=items)
  
  
  class LambdaNode(InnerFunctionNode):
      # Lambda expression node (only used as a function reference)
      #
      # args          [CArgDeclNode]         formal arguments
      # star_arg      PyArgDeclNode or None  * argument
      # starstar_arg  PyArgDeclNode or None  ** argument
      # lambda_name   string                 a module-globally unique lambda name
      # result_expr   ExprNode
      # def_node      DefNode                the underlying function 'def' node
  
      child_attrs = ['def_node']
  
      name = StringEncoding.EncodedString('<lambda>')
  
      def analyse_declarations(self, env):
          self.def_node.no_assignment_synthesis = True
          self.def_node.pymethdef_required = True
          self.def_node.analyse_declarations(env)
          self.def_node.is_cyfunction = True
          self.pymethdef_cname = self.def_node.entry.pymethdef_cname
          env.add_lambda_def(self.def_node)
  
      def analyse_types(self, env):
          self.def_node = self.def_node.analyse_expressions(env)
          return super(LambdaNode, self).analyse_types(env)
  
      def generate_result_code(self, code):
          self.def_node.generate_execution_code(code)
          super(LambdaNode, self).generate_result_code(code)
  
  
  class GeneratorExpressionNode(LambdaNode):
      # A generator expression, e.g.  (i for i in range(10))
      #
      # Result is a generator.
      #
      # loop      ForStatNode   the for-loop, containing a YieldExprNode
      # def_node  DefNode       the underlying generator 'def' node
  
      name = StringEncoding.EncodedString('genexpr')
      binding = False
  
      def analyse_declarations(self, env):
          super(GeneratorExpressionNode, self).analyse_declarations(env)
          # No pymethdef required
          self.def_node.pymethdef_required = False
          self.def_node.py_wrapper_required = False
          self.def_node.is_cyfunction = False
          # Force genexpr signature
          self.def_node.entry.signature = TypeSlots.pyfunction_noargs
  
      def generate_result_code(self, code):
          code.putln(
              '%s = %s(%s); %s' % (
                  self.result(),
                  self.def_node.entry.pyfunc_cname,
                  self.self_result_code(),
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
  
  class YieldExprNode(ExprNode):
      # Yield expression node
      #
      # arg         ExprNode   the value to return from the generator
      # label_num   integer    yield label number
      # is_yield_from  boolean is a YieldFromExprNode to delegate to another generator
  
      subexprs = ['arg']
      type = py_object_type
      label_num = 0
      is_yield_from = False
  
      def analyse_types(self, env):
          if not self.label_num:
              error(self.pos, "'yield' not supported here")
          self.is_temp = 1
          if self.arg is not None:
              self.arg = self.arg.analyse_types(env)
              if not self.arg.type.is_pyobject:
                  self.coerce_yield_argument(env)
          return self
  
      def coerce_yield_argument(self, env):
          self.arg = self.arg.coerce_to_pyobject(env)
  
      def generate_evaluation_code(self, code):
          if self.arg:
              self.arg.generate_evaluation_code(code)
              self.arg.make_owned_reference(code)
              code.putln(
                  "%s = %s;" % (
                      Naming.retval_cname,
                      self.arg.result_as(py_object_type)))
              self.arg.generate_post_assignment_code(code)
              self.arg.free_temps(code)
          else:
              code.put_init_to_py_none(Naming.retval_cname, py_object_type)
          self.generate_yield_code(code)
  
      def generate_yield_code(self, code):
          """
          Generate the code to return the argument in 'Naming.retval_cname'
          and to continue at the yield label.
          """
          label_num, label_name = code.new_yield_label()
          code.use_label(label_name)
  
          saved = []
          code.funcstate.closure_temps.reset()
          for cname, type, manage_ref in code.funcstate.temps_in_use():
              save_cname = code.funcstate.closure_temps.allocate_temp(type)
              saved.append((cname, save_cname, type))
              if type.is_pyobject:
                  code.put_xgiveref(cname)
              code.putln('%s->%s = %s;' % (Naming.cur_scope_cname, save_cname, cname))
  
          code.put_xgiveref(Naming.retval_cname)
          code.put_finish_refcount_context()
          code.putln("/* return from generator, yielding value */")
          code.putln("%s->resume_label = %d;" % (
              Naming.generator_cname, label_num))
          code.putln("return %s;" % Naming.retval_cname)
  
          code.put_label(label_name)
          for cname, save_cname, type in saved:
              code.putln('%s = %s->%s;' % (cname, Naming.cur_scope_cname, save_cname))
              if type.is_pyobject:
                  code.putln('%s->%s = 0;' % (Naming.cur_scope_cname, save_cname))
                  code.put_xgotref(cname)
          code.putln(code.error_goto_if_null(Naming.sent_value_cname, self.pos))
          if self.result_is_used:
              self.allocate_temp_result(code)
              code.put('%s = %s; ' % (self.result(), Naming.sent_value_cname))
              code.put_incref(self.result(), py_object_type)
  
  
  class YieldFromExprNode(YieldExprNode):
      # "yield from GEN" expression
      is_yield_from = True
  
      def coerce_yield_argument(self, env):
          if not self.arg.type.is_string:
              # FIXME: support C arrays and C++ iterators?
              error(self.pos, "yielding from non-Python object not supported")
          self.arg = self.arg.coerce_to_pyobject(env)
  
      def generate_evaluation_code(self, code):
          code.globalstate.use_utility_code(UtilityCode.load_cached("YieldFrom", "Generator.c"))
  
          self.arg.generate_evaluation_code(code)
          code.putln("%s = __Pyx_Generator_Yield_From(%s, %s);" % (
              Naming.retval_cname,
              Naming.generator_cname,
              self.arg.result_as(py_object_type)))
          self.arg.generate_disposal_code(code)
          self.arg.free_temps(code)
          code.put_xgotref(Naming.retval_cname)
  
          code.putln("if (likely(%s)) {" % Naming.retval_cname)
          self.generate_yield_code(code)
          code.putln("} else {")
          # either error or sub-generator has normally terminated: return value => node result
          if self.result_is_used:
              # YieldExprNode has allocated the result temp for us
              code.putln("%s = NULL;" % self.result())
              code.putln("if (unlikely(__Pyx_PyGen_FetchStopIterationValue(&%s) < 0)) %s" % (
                  self.result(),
                  code.error_goto(self.pos)))
              code.put_gotref(self.result())
          else:
              code.putln("PyObject* exc_type = PyErr_Occurred();")
              code.putln("if (exc_type) {")
              code.putln("if (likely(exc_type == PyExc_StopIteration ||"
                         " PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();")
              code.putln("else %s" % code.error_goto(self.pos))
              code.putln("}")
          code.putln("}")
  
  class GlobalsExprNode(AtomicExprNode):
      type = dict_type
      is_temp = 1
  
      def analyse_types(self, env):
          env.use_utility_code(Builtin.globals_utility_code)
          return self
  
      gil_message = "Constructing globals dict"
  
      def may_be_none(self):
          return False
  
      def generate_result_code(self, code):
          code.putln('%s = __Pyx_Globals(); %s' % (
              self.result(),
              code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.result())
  
  
  class LocalsDictItemNode(DictItemNode):
      def analyse_types(self, env):
          self.key = self.key.analyse_types(env)
          self.value = self.value.analyse_types(env)
          self.key = self.key.coerce_to_pyobject(env)
          if self.value.type.can_coerce_to_pyobject(env):
              self.value = self.value.coerce_to_pyobject(env)
          else:
              self.value = None
          return self
  
  
  class FuncLocalsExprNode(DictNode):
      def __init__(self, pos, env):
          local_vars = sorted([
              entry.name for entry in env.entries.values() if entry.name])
          items = [LocalsDictItemNode(
              pos, key=IdentifierStringNode(pos, value=var),
              value=NameNode(pos, name=var, allow_null=True))
                   for var in local_vars]
          DictNode.__init__(self, pos, key_value_pairs=items,
                            exclude_null_values=True)
  
      def analyse_types(self, env):
          node = super(FuncLocalsExprNode, self).analyse_types(env)
          node.key_value_pairs = [ i for i in node.key_value_pairs
                                   if i.value is not None ]
          return node
  
  
  class PyClassLocalsExprNode(AtomicExprNode):
      def __init__(self, pos, pyclass_dict):
          AtomicExprNode.__init__(self, pos)
          self.pyclass_dict = pyclass_dict
  
      def analyse_types(self, env):
          self.type = self.pyclass_dict.type
          self.is_temp = False
          return self
  
      def may_be_none(self):
          return False
  
      def result(self):
          return self.pyclass_dict.result()
  
      def generate_result_code(self, code):
          pass
  
  
  def LocalsExprNode(pos, scope_node, env):
      if env.is_module_scope:
          return GlobalsExprNode(pos)
      if env.is_py_class_scope:
          return PyClassLocalsExprNode(pos, scope_node.dict)
      return FuncLocalsExprNode(pos, env)
  
  
  #-------------------------------------------------------------------
  #
  #  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']
      infix = True
  
      def calculate_constant_result(self):
          func = compile_time_unary_operators[self.operator]
          self.constant_result = func(self.operand.constant_result)
  
      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 infer_type(self, env):
          operand_type = self.operand.infer_type(env)
          if operand_type.is_cpp_class or operand_type.is_ptr:
              cpp_type = operand_type.find_cpp_operation_type(self.operator)
              if cpp_type is not None:
                  return cpp_type
          return self.infer_unop_type(env, operand_type)
  
      def infer_unop_type(self, env, operand_type):
          if operand_type.is_pyobject:
              return py_object_type
          else:
              return operand_type
  
      def may_be_none(self):
          if self.operand.type and self.operand.type.is_builtin_type:
              if self.operand.type is not type_type:
                  return False
          return ExprNode.may_be_none(self)
  
      def analyse_types(self, env):
          self.operand = self.operand.analyse_types(env)
          if self.is_py_operation():
              self.coerce_operand_to_pyobject(env)
              self.type = py_object_type
              self.is_temp = 1
          elif self.is_cpp_operation():
              self.analyse_cpp_operation(env)
          else:
              self.analyse_c_operation(env)
          return self
  
      def check_const(self):
          return self.operand.check_const()
  
      def is_py_operation(self):
          return self.operand.type.is_pyobject
  
      def nogil_check(self, env):
          if self.is_py_operation():
              self.gil_error()
  
      def is_cpp_operation(self):
          type = self.operand.type
          return type.is_cpp_class
  
      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)
  
      def generate_py_operation_code(self, code):
          function = self.py_operation_function()
          code.putln(
              "%s = %s(%s); %s" % (
                  self.result(),
                  function,
                  self.operand.py_result(),
                  code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.py_result())
  
      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
  
      def analyse_cpp_operation(self, env):
          cpp_type = self.operand.type.find_cpp_operation_type(self.operator)
          if cpp_type is None:
              error(self.pos, "'%s' operator not defined for %s" % (
                  self.operator, type))
              self.type_error()
              return
          self.type = cpp_type
  
  
  class NotNode(UnopNode):
      #  'not' operator
      #
      #  operand   ExprNode
      operator = '!'
  
      type = PyrexTypes.c_bint_type
  
      def calculate_constant_result(self):
          self.constant_result = not self.operand.constant_result
  
      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)
  
      def infer_unop_type(self, env, operand_type):
          return PyrexTypes.c_bint_type
  
      def analyse_types(self, env):
          self.operand = self.operand.analyse_types(env)
          operand_type = self.operand.type
          if operand_type.is_cpp_class:
              cpp_type = operand_type.find_cpp_operation_type(self.operator)
              if not cpp_type:
                  error(self.pos, "'!' operator not defined for %s" % operand_type)
                  self.type = PyrexTypes.error_type
                  return
              self.type = cpp_type
          else:
              self.operand = self.operand.coerce_to_boolean(env)
          return self
  
      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 = PyrexTypes.widest_numeric_type(
              self.operand.type, PyrexTypes.c_int_type)
  
      def py_operation_function(self):
          return "PyNumber_Positive"
  
      def calculate_result_code(self):
          if self.is_cpp_operation():
              return "(+%s)" % self.operand.result()
          else:
              return self.operand.result()
  
  
  class UnaryMinusNode(UnopNode):
      #  unary '-' operator
  
      operator = '-'
  
      def analyse_c_operation(self, env):
          if self.operand.type.is_numeric:
              self.type = PyrexTypes.widest_numeric_type(
                  self.operand.type, PyrexTypes.c_int_type)
          elif self.operand.type.is_enum:
              self.type = PyrexTypes.c_int_type
          else:
              self.type_error()
          if self.type.is_complex:
              self.infix = False
  
      def py_operation_function(self):
          return "PyNumber_Negative"
  
      def calculate_result_code(self):
          if self.infix:
              return "(-%s)" % self.operand.result()
          else:
              return "%s(%s)" % (self.operand.type.unary_op('-'), self.operand.result())
  
      def get_constant_c_result_code(self):
          value = self.operand.get_constant_c_result_code()
          if value:
              return "(-%s)" % value
  
  class TildeNode(UnopNode):
      #  unary '~' operator
  
      def analyse_c_operation(self, env):
          if self.operand.type.is_int:
              self.type = PyrexTypes.widest_numeric_type(
                  self.operand.type, PyrexTypes.c_int_type)
          elif self.operand.type.is_enum:
              self.type = PyrexTypes.c_int_type
          else:
              self.type_error()
  
      def py_operation_function(self):
          return "PyNumber_Invert"
  
      def calculate_result_code(self):
          return "(~%s)" % self.operand.result()
  
  
  class CUnopNode(UnopNode):
  
      def is_py_operation(self):
          return False
  
  class DereferenceNode(CUnopNode):
      #  unary * operator
  
      operator = '*'
  
      def infer_unop_type(self, env, operand_type):
          if operand_type.is_ptr:
              return operand_type.base_type
          else:
              return PyrexTypes.error_type
  
      def analyse_c_operation(self, env):
          if self.operand.type.is_ptr:
              self.type = self.operand.type.base_type
          else:
              self.type_error()
  
      def calculate_result_code(self):
          return "(*%s)" % self.operand.result()
  
  
  class DecrementIncrementNode(CUnopNode):
      #  unary ++/-- operator
  
      def analyse_c_operation(self, env):
          if self.operand.type.is_numeric:
              self.type = PyrexTypes.widest_numeric_type(
                  self.operand.type, PyrexTypes.c_int_type)
          elif self.operand.type.is_ptr:
              self.type = self.operand.type
          else:
              self.type_error()
  
      def calculate_result_code(self):
          if self.is_prefix:
              return "(%s%s)" % (self.operator, self.operand.result())
          else:
              return "(%s%s)" % (self.operand.result(), self.operator)
  
  def inc_dec_constructor(is_prefix, operator):
      return lambda pos, **kwds: DecrementIncrementNode(pos, is_prefix=is_prefix, operator=operator, **kwds)
  
  
  class AmpersandNode(CUnopNode):
      #  The C address-of operator.
      #
      #  operand  ExprNode
      operator = '&'
  
      def infer_unop_type(self, env, operand_type):
          return PyrexTypes.c_ptr_type(operand_type)
  
      def analyse_types(self, env):
          self.operand = self.operand.analyse_types(env)
          argtype = self.operand.type
          if argtype.is_cpp_class:
              cpp_type = argtype.find_cpp_operation_type(self.operator)
              if cpp_type is not None:
                  self.type = cpp_type
                  return self
          if not (argtype.is_cfunction or argtype.is_reference or self.operand.is_addressable()):
              if argtype.is_memoryviewslice:
                  self.error("Cannot take address of memoryview slice")
              else:
                  self.error("Taking address of non-lvalue")
              return self
          if argtype.is_pyobject:
              self.error("Cannot take address of Python variable")
              return self
          self.type = PyrexTypes.c_ptr_type(argtype)
          return self
  
      def check_const(self):
          return 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.
      if isinstance(operand, IntNode) and operator == '-':
          return IntNode(pos = operand.pos, value = str(-Utils.str_to_number(operand.value)),
                         longness=operand.longness, unsigned=operand.unsigned)
      elif isinstance(operand, UnopNode) and operand.operator == operator in '+-':
          warning(pos, "Python has no increment/decrement operator: %s%sx == %s(%sx) == x" % ((operator,)*4), 5)
      return unop_node_classes[operator](pos,
          operator = operator,
          operand = operand)
  
  
  class TypecastNode(ExprNode):
      #  C type cast
      #
      #  operand      ExprNode
      #  base_type    CBaseTypeNode
      #  declarator   CDeclaratorNode
      #  typecheck    boolean
      #
      #  If used from a transform, one can if wanted specify the attribute
      #  "type" directly and leave base_type and declarator to None
  
      subexprs = ['operand']
      base_type = declarator = type = None
  
      def type_dependencies(self, env):
          return ()
  
      def infer_type(self, env):
          if self.type is None:
              base_type = self.base_type.analyse(env)
              _, self.type = self.declarator.analyse(base_type, env)
          return self.type
  
      def analyse_types(self, env):
          if self.type is None:
              base_type = self.base_type.analyse(env)
              _, self.type = self.declarator.analyse(base_type, env)
          if self.operand.has_constant_result():
              # Must be done after self.type is resolved.
              self.calculate_constant_result()
          if self.type.is_cfunction:
              error(self.pos,
                  "Cannot cast to a function type")
              self.type = PyrexTypes.error_type
          self.operand = self.operand.analyse_types(env)
          if self.type is PyrexTypes.c_bint_type:
              # short circuit this to a coercion
              return self.operand.coerce_to_boolean(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():
              if not self.type.is_numeric and not self.type.is_cpp_class:
                  error(self.pos, "Casting temporary Python object to non-numeric non-Python type")
          if to_py and not from_py:
              if self.type is bytes_type and self.operand.type.is_int:
                  return CoerceIntToBytesNode(self.operand, env)
              elif self.operand.type.can_coerce_to_pyobject(env):
                  self.result_ctype = py_object_type
                  base_type = self.base_type.analyse(env)
                  self.operand = self.operand.coerce_to(base_type, env)
              else:
                  if self.operand.type.is_ptr:
                      if not (self.operand.type.base_type.is_void or self.operand.type.base_type.is_struct):
                          error(self.pos, "Python objects cannot be cast from pointers of primitive types")
                  else:
                      # Should this be an error?
                      warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type))
                  self.operand = self.operand.coerce_to_simple(env)
          elif from_py and not to_py:
              if self.type.create_from_py_utility_code(env):
                  self.operand = self.operand.coerce_to(self.type, env)
              elif self.type.is_ptr:
                  if not (self.type.base_type.is_void or self.type.base_type.is_struct):
                      error(self.pos, "Python objects cannot be cast to pointers of primitive types")
              else:
                  warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.type, self.operand.type))
          elif from_py and to_py:
              if self.typecheck:
                  self.operand = PyTypeTestNode(self.operand, self.type, env, notnone=True)
              elif isinstance(self.operand, SliceIndexNode):
                  # This cast can influence the created type of string slices.
                  self.operand = self.operand.coerce_to(self.type, env)
          elif self.type.is_complex and self.operand.type.is_complex:
              self.operand = self.operand.coerce_to_simple(env)
          elif self.operand.type.is_fused:
              self.operand = self.operand.coerce_to(self.type, env)
              #self.type = self.operand.type
          return self
  
      def is_simple(self):
          # either temp or a C cast => no side effects other than the operand's
          return self.operand.is_simple()
  
      def nonlocally_immutable(self):
          return self.is_temp or self.operand.nonlocally_immutable()
  
      def nogil_check(self, env):
          if self.type and self.type.is_pyobject and self.is_temp:
              self.gil_error()
  
      def check_const(self):
          return self.operand.check_const()
  
      def calculate_constant_result(self):
          self.constant_result = self.calculate_result_code(self.operand.constant_result)
  
      def calculate_result_code(self, operand_result = None):
          if operand_result is None:
              operand_result = self.operand.result()
          if self.type.is_complex:
              operand_result = self.operand.result()
              if self.operand.type.is_complex:
                  real_part = self.type.real_type.cast_code("__Pyx_CREAL(%s)" % operand_result)
                  imag_part = self.type.real_type.cast_code("__Pyx_CIMAG(%s)" % operand_result)
              else:
                  real_part = self.type.real_type.cast_code(operand_result)
                  imag_part = "0"
              return "%s(%s, %s)" % (
                      self.type.from_parts,
                      real_part,
                      imag_part)
          else:
              return self.type.cast_code(operand_result)
  
      def get_constant_c_result_code(self):
          operand_result = self.operand.get_constant_c_result_code()
          if operand_result:
              return self.type.cast_code(operand_result)
  
      def result_as(self, type):
          if self.type.is_pyobject and not self.is_temp:
              #  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 = (PyObject *)%s;" % (
                      self.result(),
                      self.operand.result()))
              code.put_incref(self.result(), self.ctype())
  
  
  ERR_START = "Start may not be given"
  ERR_NOT_STOP = "Stop must be provided to indicate shape"
  ERR_STEPS = ("Strides may only be given to indicate contiguity. "
               "Consider slicing it after conversion")
  ERR_NOT_POINTER = "Can only create cython.array from pointer or array"
  ERR_BASE_TYPE = "Pointer base type does not match cython.array base type"
  
  class CythonArrayNode(ExprNode):
      """
      Used when a pointer of base_type is cast to a memoryviewslice with that
      base type. i.e.
  
          <int[:M:1, :N]> p
  
      creates a fortran-contiguous cython.array.
  
      We leave the type set to object so coercions to object are more efficient
      and less work. Acquiring a memoryviewslice from this will be just as
      efficient. ExprNode.coerce_to() will do the additional typecheck on
      self.compile_time_type
  
      This also handles <int[:, :]> my_c_array
  
  
      operand             ExprNode                 the thing we're casting
      base_type_node      MemoryViewSliceTypeNode  the cast expression node
      """
  
      subexprs = ['operand', 'shapes']
  
      shapes = None
      is_temp = True
      mode = "c"
      array_dtype = None
  
      shape_type = PyrexTypes.c_py_ssize_t_type
  
      def analyse_types(self, env):
          import MemoryView
  
          self.operand = self.operand.analyse_types(env)
          if self.array_dtype:
              array_dtype = self.array_dtype
          else:
              array_dtype = self.base_type_node.base_type_node.analyse(env)
          axes = self.base_type_node.axes
  
          MemoryView.validate_memslice_dtype(self.pos, array_dtype)
  
          self.type = error_type
          self.shapes = []
          ndim = len(axes)
  
          # Base type of the pointer or C array we are converting
          base_type = self.operand.type
  
          if not self.operand.type.is_ptr and not self.operand.type.is_array:
              error(self.operand.pos, ERR_NOT_POINTER)
              return self
  
          # Dimension sizes of C array
          array_dimension_sizes = []
          if base_type.is_array:
              while base_type.is_array:
                  array_dimension_sizes.append(base_type.size)
                  base_type = base_type.base_type
          elif base_type.is_ptr:
              base_type = base_type.base_type
          else:
              error(self.pos, "unexpected base type %s found" % base_type)
              return self
  
          if not (base_type.same_as(array_dtype) or base_type.is_void):
              error(self.operand.pos, ERR_BASE_TYPE)
              return self
          elif self.operand.type.is_array and len(array_dimension_sizes) != ndim:
              error(self.operand.pos,
                    "Expected %d dimensions, array has %d dimensions" %
                                              (ndim, len(array_dimension_sizes)))
              return self
  
          # Verify the start, stop and step values
          # In case of a C array, use the size of C array in each dimension to
          # get an automatic cast
          for axis_no, axis in enumerate(axes):
              if not axis.start.is_none:
                  error(axis.start.pos, ERR_START)
                  return self
  
              if axis.stop.is_none:
                  if array_dimension_sizes:
                      dimsize = array_dimension_sizes[axis_no]
                      axis.stop = IntNode(self.pos, value=str(dimsize),
                                          constant_result=dimsize,
                                          type=PyrexTypes.c_int_type)
                  else:
                      error(axis.pos, ERR_NOT_STOP)
                      return self
  
              axis.stop = axis.stop.analyse_types(env)
              shape = axis.stop.coerce_to(self.shape_type, env)
              if not shape.is_literal:
                  shape.coerce_to_temp(env)
  
              self.shapes.append(shape)
  
              first_or_last = axis_no in (0, ndim - 1)
              if not axis.step.is_none and first_or_last:
                  # '1' in the first or last dimension denotes F or C contiguity
                  axis.step = axis.step.analyse_types(env)
                  if (not axis.step.type.is_int and axis.step.is_literal and not
                          axis.step.type.is_error):
                      error(axis.step.pos, "Expected an integer literal")
                      return self
  
                  if axis.step.compile_time_value(env) != 1:
                      error(axis.step.pos, ERR_STEPS)
                      return self
  
                  if axis_no == 0:
                      self.mode = "fortran"
  
              elif not axis.step.is_none and not first_or_last:
                  # step provided in some other dimension
                  error(axis.step.pos, ERR_STEPS)
                  return self
  
          if not self.operand.is_name:
              self.operand = self.operand.coerce_to_temp(env)
  
          axes = [('direct', 'follow')] * len(axes)
          if self.mode == "fortran":
              axes[0] = ('direct', 'contig')
          else:
              axes[-1] = ('direct', 'contig')
  
          self.coercion_type = PyrexTypes.MemoryViewSliceType(array_dtype, axes)
          self.type = self.get_cython_array_type(env)
          MemoryView.use_cython_array_utility_code(env)
          env.use_utility_code(MemoryView.typeinfo_to_format_code)
          return self
  
      def allocate_temp_result(self, code):
          if self.temp_code:
              raise RuntimeError("temp allocated mulitple times")
  
          self.temp_code = code.funcstate.allocate_temp(self.type, True)
  
      def infer_type(self, env):
          return self.get_cython_array_type(env)
  
      def get_cython_array_type(self, env):
          return env.global_scope().context.cython_scope.viewscope.lookup("array").type
  
      def generate_result_code(self, code):
          import Buffer
  
          shapes = [self.shape_type.cast_code(shape.result())
                        for shape in self.shapes]
          dtype = self.coercion_type.dtype
  
          shapes_temp = code.funcstate.allocate_temp(py_object_type, True)
          format_temp = code.funcstate.allocate_temp(py_object_type, True)
  
          itemsize = "sizeof(%s)" % dtype.declaration_code("")
          type_info = Buffer.get_type_information_cname(code, dtype)
  
          if self.operand.type.is_ptr:
              code.putln("if (!%s) {" % self.operand.result())
              code.putln(    'PyErr_SetString(PyExc_ValueError,'
                                  '"Cannot create cython.array from NULL pointer");')
              code.putln(code.error_goto(self.operand.pos))
              code.putln("}")
  
          code.putln("%s = __pyx_format_from_typeinfo(&%s);" %
                                                  (format_temp, type_info))
          buildvalue_fmt = " __PYX_BUILD_PY_SSIZE_T " * len(shapes)
          code.putln('%s = Py_BuildValue((char*) "(" %s ")", %s);' % (
              shapes_temp, buildvalue_fmt, ", ".join(shapes)))
  
          err = "!%s || !%s || !PyBytes_AsString(%s)" % (format_temp,
                                                         shapes_temp,
                                                         format_temp)
          code.putln(code.error_goto_if(err, self.pos))
          code.put_gotref(format_temp)
          code.put_gotref(shapes_temp)
  
          tup = (self.result(), shapes_temp, itemsize, format_temp,
                 self.mode, self.operand.result())
          code.putln('%s = __pyx_array_new('
                              '%s, %s, PyBytes_AS_STRING(%s), '
                              '(char *) "%s", (char *) %s);' % tup)
          code.putln(code.error_goto_if_null(self.result(), self.pos))
          code.put_gotref(self.result())
  
          def dispose(temp):
              code.put_decref_clear(temp, py_object_type)
              code.funcstate.release_temp(temp)
  
          dispose(shapes_temp)
          dispose(format_temp)
  
      @classmethod
      def from_carray(cls, src_node, env):
          """
          Given a C array type, return a CythonArrayNode
          """
          pos = src_node.pos
          base_type = src_node.type
  
          none_node = NoneNode(pos)
          axes = []
  
          while base_type.is_array:
              axes.append(SliceNode(pos, start=none_node, stop=none_node,
                                         step=none_node))
              base_type = base_type.base_type
          axes[-1].step = IntNode(pos, value="1", is_c_literal=True)
  
          memslicenode = Nodes.MemoryViewSliceTypeNode(pos, axes=axes,
                                                       base_type_node=base_type)
          result = CythonArrayNode(pos, base_type_node=memslicenode,
                                   operand=src_node, array_dtype=base_type)
          result = result.analyse_types(env)
          return result
  
  class SizeofNode(ExprNode):
      #  Abstract base class for sizeof(x) expression nodes.
  
      type = PyrexTypes.c_size_t_type
  
      def check_const(self):
          return True
  
      def generate_result_code(self, code):
          pass
  
  
  class SizeofTypeNode(SizeofNode):
      #  C sizeof function applied to a type
      #
      #  base_type   CBaseTypeNode
      #  declarator  CDeclaratorNode
  
      subexprs = []
      arg_type = None
  
      def analyse_types(self, env):
          # we may have incorrectly interpreted a dotted name as a type rather than an attribute
          # this could be better handled by more uniformly treating types as runtime-available objects
          if 0 and self.base_type.module_path:
              path = self.base_type.module_path
              obj = env.lookup(path[0])
              if obj.as_module is None:
                  operand = NameNode(pos=self.pos, name=path[0])
                  for attr in path[1:]:
                      operand = AttributeNode(pos=self.pos, obj=operand, attribute=attr)
                  operand = AttributeNode(pos=self.pos, obj=operand, attribute=self.base_type.name)
                  self.operand = operand
                  self.__class__ = SizeofVarNode
                  node = self.analyse_types(env)
                  return node
          if self.arg_type is None:
              base_type = self.base_type.analyse(env)
              _, arg_type = self.declarator.analyse(base_type, env)
              self.arg_type = arg_type
          self.check_type()
          return self
  
      def check_type(self):
          arg_type = self.arg_type
          if arg_type.is_pyobject and not arg_type.is_extension_type:
              error(self.pos, "Cannot take sizeof Python object")
          elif arg_type.is_void:
              error(self.pos, "Cannot take sizeof void")
          elif not arg_type.is_complete():
              error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type)
  
      def calculate_result_code(self):
          if self.arg_type.is_extension_type:
              # the size of the pointer is boring
              # we want the size of the actual struct
              arg_code = self.arg_type.declaration_code("", deref=1)
          else:
              arg_code = self.arg_type.declaration_code("")
          return "(sizeof(%s))" % arg_code
  
  
  class SizeofVarNode(SizeofNode):
      #  C sizeof function applied to a variable
      #
      #  operand   ExprNode
  
      subexprs = ['operand']
  
      def analyse_types(self, env):
          # We may actually be looking at a type rather than a variable...
          # If we are, traditional analysis would fail...
          operand_as_type = self.operand.analyse_as_type(env)
          if operand_as_type:
              self.arg_type = operand_as_type
              if self.arg_type.is_fused:
                  self.arg_type = self.arg_type.specialize(env.fused_to_specific)
              self.__class__ = SizeofTypeNode
              self.check_type()
          else:
              self.operand = self.operand.analyse_types(env)
          return self
  
      def calculate_result_code(self):
          return "(sizeof(%s))" % self.operand.result()
  
      def generate_result_code(self, code):
          pass
  
  class TypeofNode(ExprNode):
      #  Compile-time type of an expression, as a string.
      #
      #  operand   ExprNode
      #  literal   StringNode # internal
  
      literal = None
      type = py_object_type
  
      subexprs = ['literal'] # 'operand' will be ignored after type analysis!
  
      def analyse_types(self, env):
          self.operand = self.operand.analyse_types(env)
          value = StringEncoding.EncodedString(str(self.operand.type)) #self.operand.type.typeof_name())
          literal = StringNode(self.pos, value=value)
          literal = literal.analyse_types(env)
          self.literal = literal.coerce_to_pyobject(env)
          return self
  
      def may_be_none(self):
          return False
  
      def generate_evaluation_code(self, code):
          self.literal.generate_evaluation_code(code)
  
      def calculate_result_code(self):
          return self.literal.calculate_result_code()
  
  #-------------------------------------------------------------------
  #
  #  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.truediv,
      '//': operator.floordiv,
      '<<': operator.lshift,
      '%': operator.mod,
      '*': operator.mul,
      '|': operator.or_,
      '**': operator.pow,
      '>>': operator.rshift,
      '-': operator.sub,
      '^': operator.xor,
      'in': lambda x, seq: x in seq,
      'not_in': lambda x, seq: x not in seq,
  }
  
  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']
      inplace = False
  
      def calculate_constant_result(self):
          func = compile_time_binary_operators[self.operator]
          self.constant_result = func(
              self.operand1.constant_result,
              self.operand2.constant_result)
  
      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 infer_type(self, env):
          return self.result_type(self.operand1.infer_type(env),
                                  self.operand2.infer_type(env))
  
      def analyse_types(self, env):
          self.operand1 = self.operand1.analyse_types(env)
          self.operand2 = self.operand2.analyse_types(env)
          self.analyse_operation(env)
          return self
  
      def analyse_operation(self, env):
          if self.is_py_operation():
              self.coerce_operands_to_pyobjects(env)
              self.type = self.result_type(self.operand1.type,
                                           self.operand2.type)
              assert self.type.is_pyobject
              self.is_temp = 1
          elif self.is_cpp_operation():
              self.analyse_cpp_operation(env)
          else:
              self.analyse_c_operation(env)
  
      def is_py_operation(self):
          return self.is_py_operation_types(self.operand1.type, self.operand2.type)
  
      def is_py_operation_types(self, type1, type2):
          return type1.is_pyobject or type2.is_pyobject
  
      def is_cpp_operation(self):
          return (self.operand1.type.is_cpp_class
              or self.operand2.type.is_cpp_class)
  
      def analyse_cpp_operation(self, env):
          entry = env.lookup_operator(self.operator, [self.operand1, self.operand2])
          if not entry:
              self.type_error()
              return
          func_type = entry.type
          if func_type.is_ptr:
              func_type = func_type.base_type
          if len(func_type.args) == 1:
              self.operand2 = self.operand2.coerce_to(func_type.args[0].type, env)
          else:
              self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env)
              self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env)
          self.type = func_type.return_type
  
      def result_type(self, type1, type2):
          if self.is_py_operation_types(type1, type2):
              if type2.is_string:
                  type2 = Builtin.bytes_type
              elif type2.is_pyunicode_ptr:
                  type2 = Builtin.unicode_type
              if type1.is_string:
                  type1 = Builtin.bytes_type
              elif type1.is_pyunicode_ptr:
                  type1 = Builtin.unicode_type
              if type1.is_builtin_type or type2.is_builtin_type:
                  if type1 is type2 and self.operator in '**%+|&^':
                      # FIXME: at least these operators should be safe - others?
                      return type1
                  result_type = self.infer_builtin_types_operation(type1, type2)
                  if result_type is not None:
                      return result_type
              return py_object_type
          else:
              return self.compute_c_result_type(type1, type2)
  
      def infer_builtin_types_operation(self, type1, type2):
          return None
  
      def nogil_check(self, env):
          if self.is_py_operation():
              self.gil_error()
  
      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):
          return self.operand1.check_const() and 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 self.operator == '**':
                  extra_args = ", Py_None"
              else:
                  extra_args = ""
              code.putln(
                  "%s = %s(%s, %s%s); %s" % (
                      self.result(),
                      function,
                      self.operand1.py_result(),
                      self.operand2.py_result(),
                      extra_args,
                      code.error_goto_if_null(self.result(), self.pos)))
              code.put_gotref(self.py_result())
          elif self.is_temp:
              code.putln("%s = %s;" % (self.result(), self.calculate_result_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 CBinopNode(BinopNode):
  
      def analyse_types(self, env):
          node = BinopNode.analyse_types(self, env)
          if node.is_py_operation():
              node.type = PyrexTypes.error_type
          return node
  
      def py_operation_function(self):
          return ""
  
      def calculate_result_code(self):
          return "(%s %s %s)" % (
              self.operand1.result(),
              self.operator,
              self.operand2.result())
  
      def compute_c_result_type(self, type1, type2):
          cpp_type = None
          if type1.is_cpp_class or type1.is_ptr:
              cpp_type = type1.find_cpp_operation_type(self.operator, type2)
          # FIXME: handle the reversed case?
          #if cpp_type is None and (type2.is_cpp_class or type2.is_ptr):
          #    cpp_type = type2.find_cpp_operation_type(self.operator, type1)
          # FIXME: do we need to handle other cases here?
          return cpp_type
  
  
  def c_binop_constructor(operator):
      def make_binop_node(pos, **operands):
          return CBinopNode(pos, operator=operator, **operands)
      return make_binop_node
  
  class NumBinopNode(BinopNode):
      #  Binary operation taking numeric arguments.
  
      infix = True
      overflow_check = False
      overflow_bit_node = None
  
      def analyse_c_operation(self, env):
          type1 = self.operand1.type
          type2 = self.operand2.type
          self.type = self.compute_c_result_type(type1, type2)
          if not self.type:
              self.type_error()
              return
          if self.type.is_complex:
              self.infix = False
          if (self.type.is_int
                  and env.directives['overflowcheck']
                  and self.operator in self.overflow_op_names):
              if (self.operator in ('+', '*')
                      and self.operand1.has_constant_result()
                      and not self.operand2.has_constant_result()):
                  self.operand1, self.operand2 = self.operand2, self.operand1
              self.overflow_check = True
              self.overflow_fold = env.directives['overflowcheck.fold']
              self.func = self.type.overflow_check_binop(
                  self.overflow_op_names[self.operator],
                  env,
                  const_rhs = self.operand2.has_constant_result())
              self.is_temp = True
          if not self.infix or (type1.is_numeric and type2.is_numeric):
              self.operand1 = self.operand1.coerce_to(self.type, env)
              self.operand2 = self.operand2.coerce_to(self.type, env)
  
      def compute_c_result_type(self, type1, type2):
          if self.c_types_okay(type1, type2):
              widest_type = PyrexTypes.widest_numeric_type(type1, type2)
              if widest_type is PyrexTypes.c_bint_type:
                  if self.operator not in '|^&':
                      # False + False == 0 # not False!
                      widest_type = PyrexTypes.c_int_type
              else:
                  widest_type = PyrexTypes.widest_numeric_type(
                      widest_type, PyrexTypes.c_int_type)
              return widest_type
          else:
              return None
  
      def may_be_none(self):
          if self.type and self.type.is_builtin_type:
              # if we know the result type, we know the operation, so it can't be None
              return False
          type1 = self.operand1.type
          type2 = self.operand2.type
          if type1 and type1.is_builtin_type and type2 and type2.is_builtin_type:
              # XXX: I can't think of any case where a binary operation
              # on builtin types evaluates to None - add a special case
              # here if there is one.
              return False
          return super(NumBinopNode, self).may_be_none()
  
      def get_constant_c_result_code(self):
          value1 = self.operand1.get_constant_c_result_code()
          value2 = self.operand2.get_constant_c_result_code()
          if value1 and value2:
              return "(%s %s %s)" % (value1, self.operator, value2)
          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 generate_evaluation_code(self, code):
          if self.overflow_check:
              self.overflow_bit_node = self
              self.overflow_bit = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
              code.putln("%s = 0;" % self.overflow_bit)
          super(NumBinopNode, self).generate_evaluation_code(code)
          if self.overflow_check:
              code.putln("if (unlikely(%s)) {" % self.overflow_bit)
              code.putln('PyErr_SetString(PyExc_OverflowError, "value too large");')
              code.putln(code.error_goto(self.pos))
              code.putln("}")
              code.funcstate.release_temp(self.overflow_bit)
  
      def calculate_result_code(self):
          if self.overflow_bit_node is not None:
              return "%s(%s, %s, &%s)" % (
                  self.func,
                  self.operand1.result(),
                  self.operand2.result(),
                  self.overflow_bit_node.overflow_bit)
          elif self.infix:
              return "(%s %s %s)" % (
                  self.operand1.result(),
                  self.operator,
                  self.operand2.result())
          else:
              func = self.type.binary_op(self.operator)
              if func is None:
                  error(self.pos, "binary operator %s not supported for %s" % (self.operator, self.type))
              return "%s(%s, %s)" % (
                  func,
                  self.operand1.result(),
                  self.operand2.result())
  
      def is_py_operation_types(self, type1, type2):
          return (type1.is_unicode_char or
                  type2.is_unicode_char or
                  BinopNode.is_py_operation_types(self, type1, type2))
  
      def py_operation_function(self):
          function_name = self.py_functions[self.operator]
          if self.inplace:
              function_name = function_name.replace('PyNumber_', 'PyNumber_InPlace')
          return function_name
  
      py_functions = {
          "|":        "PyNumber_Or",
          "^":        "PyNumber_Xor",
          "&":        "PyNumber_And",
          "<<":       "PyNumber_Lshift",
          ">>":       "PyNumber_Rshift",
          "+":        "PyNumber_Add",
          "-":        "PyNumber_Subtract",
          "*":        "PyNumber_Multiply",
          "/":        "__Pyx_PyNumber_Divide",
          "//":       "PyNumber_FloorDivide",
          "%":        "PyNumber_Remainder",
          "**":       "PyNumber_Power"
      }
  
      overflow_op_names = {
          "+":  "add",
          "-":  "sub",
          "*":  "mul",
          "<<":  "lshift",
      }
  
  
  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_types(self, type1, type2):
          if type1.is_string and type2.is_string or type1.is_pyunicode_ptr and type2.is_pyunicode_ptr:
              return 1
          else:
              return NumBinopNode.is_py_operation_types(self, type1, type2)
  
      def infer_builtin_types_operation(self, type1, type2):
          # b'abc' + 'abc' raises an exception in Py3,
          # so we can safely infer the Py2 type for bytes here
          string_types = [bytes_type, str_type, basestring_type, unicode_type]  # Py2.4 lacks tuple.index()
          if type1 in string_types and type2 in string_types:
              return string_types[max(string_types.index(type1),
                                      string_types.index(type2))]
          return None
  
      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)
  
      def py_operation_function(self):
          type1, type2 = self.operand1.type, self.operand2.type
          if type1 is unicode_type or type2 is unicode_type:
              if type1.is_builtin_type and type2.is_builtin_type:
                  if self.operand1.may_be_none() or self.operand2.may_be_none():
                      return '__Pyx_PyUnicode_ConcatSafe'
                  else:
                      return '__Pyx_PyUnicode_Concat'
          return super(AddNode, self).py_operation_function()
  
  
  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_ptrdiff_t_type
          else:
              return NumBinopNode.compute_c_result_type(
                  self, type1, type2)
  
  
  class MulNode(NumBinopNode):
      #  '*' operator.
  
      def is_py_operation_types(self, type1, type2):
          if ((type1.is_string and type2.is_int) or
                  (type2.is_string and type1.is_int)):
              return 1
          else:
              return NumBinopNode.is_py_operation_types(self, type1, type2)
  
      def infer_builtin_types_operation(self, type1, type2):
          # let's assume that whatever builtin type you multiply a string with
          # will either return a string of the same type or fail with an exception
          string_types = (bytes_type, str_type, basestring_type, unicode_type)
          if type1 in string_types and type2.is_builtin_type:
              return type1
          if type2 in string_types and type1.is_builtin_type:
              return type2
          # multiplication of containers/numbers with an integer value
          # always (?) returns the same type
          if type1.is_int:
              return type2
          if type2.is_int:
              return type1
          return None
  
  
  class DivNode(NumBinopNode):
      #  '/' or '//' operator.
  
      cdivision = None
      truedivision = None   # == "unknown" if operator == '/'
      ctruedivision = False
      cdivision_warnings = False
      zerodivision_check = None
  
      def find_compile_time_binary_operator(self, op1, op2):
          func = compile_time_binary_operators[self.operator]
          if self.operator == '/' and self.truedivision is None:
              # => true div for floats, floor div for integers
              if isinstance(op1, (int,long)) and isinstance(op2, (int,long)):
                  func = compile_time_binary_operators['//']
          return func
  
      def calculate_constant_result(self):
          op1 = self.operand1.constant_result
          op2 = self.operand2.constant_result
          func = self.find_compile_time_binary_operator(op1, op2)
          self.constant_result = func(
              self.operand1.constant_result,
              self.operand2.constant_result)
  
      def compile_time_value(self, denv):
          operand1 = self.operand1.compile_time_value(denv)
          operand2 = self.operand2.compile_time_value(denv)
          try:
              func = self.find_compile_time_binary_operator(
                  operand1, operand2)
              return func(operand1, operand2)
          except Exception, e:
              self.compile_time_value_error(e)
  
      def analyse_operation(self, env):
          if self.cdivision or env.directives['cdivision']:
              self.ctruedivision = False
          else:
              self.ctruedivision = self.truedivision
          NumBinopNode.analyse_operation(self, env)
          if self.is_cpp_operation():
              self.cdivision = True
          if not self.type.is_pyobject:
              self.zerodivision_check = (
                  self.cdivision is None and not env.directives['cdivision']
                  and (not self.operand2.has_constant_result() or
                       self.operand2.constant_result == 0))
              if self.zerodivision_check or env.directives['cdivision_warnings']:
                  # Need to check ahead of time to warn or raise zero division error
                  self.operand1 = self.operand1.coerce_to_simple(env)
                  self.operand2 = self.operand2.coerce_to_simple(env)
  
      def compute_c_result_type(self, type1, type2):
          if self.operator == '/' and self.ctruedivision:
              if not type1.is_float and not type2.is_float:
                  widest_type = PyrexTypes.widest_numeric_type(type1, PyrexTypes.c_double_type)
                  widest_type = PyrexTypes.widest_numeric_type(type2, widest_type)
                  return widest_type
          return NumBinopNode.compute_c_result_type(self, type1, type2)
  
      def zero_division_message(self):
          if self.type.is_int:
              return "integer division or modulo by zero"
          else:
              return "float division"
  
      def generate_evaluation_code(self, code):
          if not self.type.is_pyobject and not self.type.is_complex:
              if self.cdivision is None:
                  self.cdivision = (code.globalstate.directives['cdivision']
                                      or not self.type.signed
                                      or self.type.is_float)
              if not self.cdivision:
                  code.globalstate.use_utility_code(div_int_utility_code.specialize(self.type))
          NumBinopNode.generate_evaluation_code(self, code)
          self.generate_div_warning_code(code)
  
      def generate_div_warning_code(self, code):
          if not self.type.is_pyobject:
              if self.zerodivision_check:
                  if not self.infix:
                      zero_test = "%s(%s)" % (self.type.unary_op('zero'), self.operand2.result())
                  else:
                      zero_test = "%s == 0" % self.operand2.result()
                  code.putln("if (unlikely(%s)) {" % zero_test)
                  code.put_ensure_gil()
                  code.putln('PyErr_SetString(PyExc_ZeroDivisionError, "%s");' % self.zero_division_message())
                  code.put_release_ensured_gil()
                  code.putln(code.error_goto(self.pos))
                  code.putln("}")
                  if self.type.is_int and self.type.signed and self.operator != '%':
                      code.globalstate.use_utility_code(division_overflow_test_code)
                      if self.operand2.type.signed == 2:
                          # explicitly signed, no runtime check needed
                          minus1_check = 'unlikely(%s == -1)' % self.operand2.result()
                      else:
                          type_of_op2 = self.operand2.type.declaration_code('')
                          minus1_check = '(!(((%s)-1) > 0)) && unlikely(%s == (%s)-1)' % (
                              type_of_op2, self.operand2.result(), type_of_op2)
                      code.putln("else if (sizeof(%s) == sizeof(long) && %s "
                                 " && unlikely(UNARY_NEG_WOULD_OVERFLOW(%s))) {" % (
                                 self.type.declaration_code(''),
                                 minus1_check,
                                 self.operand1.result()))
                      code.put_ensure_gil()
                      code.putln('PyErr_SetString(PyExc_OverflowError, "value too large to perform division");')
                      code.put_release_ensured_gil()
                      code.putln(code.error_goto(self.pos))
                      code.putln("}")
              if code.globalstate.directives['cdivision_warnings'] and self.operator != '/':
                  code.globalstate.use_utility_code(cdivision_warning_utility_code)
                  code.putln("if (unlikely((%s < 0) ^ (%s < 0))) {" % (
                                  self.operand1.result(),
                                  self.operand2.result()))
                  code.put_ensure_gil()
                  code.putln(code.set_error_info(self.pos, used=True))
                  code.putln("if (__Pyx_cdivision_warning(%(FILENAME)s, "
                                                         "%(LINENO)s)) {" % {
                      'FILENAME': Naming.filename_cname,
                      'LINENO':  Naming.lineno_cname,
                      })
                  code.put_release_ensured_gil()
                  code.put_goto(code.error_label)
                  code.putln("}")
                  code.put_release_ensured_gil()
                  code.putln("}")
  
      def calculate_result_code(self):
          if self.type.is_complex:
              return NumBinopNode.calculate_result_code(self)
          elif self.type.is_float and self.operator == '//':
              return "floor(%s / %s)" % (
                  self.operand1.result(),
                  self.operand2.result())
          elif self.truedivision or self.cdivision:
              op1 = self.operand1.result()
              op2 = self.operand2.result()
              if self.truedivision:
                  if self.type != self.operand1.type:
                      op1 = self.type.cast_code(op1)
                  if self.type != self.operand2.type:
                      op2 = self.type.cast_code(op2)
              return "(%s / %s)" % (op1, op2)
          else:
              return "__Pyx_div_%s(%s, %s)" % (
                  self.type.specialization_name(),
                  self.operand1.result(),
                  self.operand2.result())
  
  
  class ModNode(DivNode):
      #  '%' operator.
  
      def is_py_operation_types(self, type1, type2):
          return (type1.is_string
                  or type2.is_string
                  or NumBinopNode.is_py_operation_types(self, type1, type2))
  
      def infer_builtin_types_operation(self, type1, type2):
          # b'%s' % xyz  raises an exception in Py3, so it's safe to infer the type for Py2
          if type1 is unicode_type:
              # None + xyz  may be implemented by RHS
              if type2.is_builtin_type or not self.operand1.may_be_none():
                  return type1
          elif type1 in (bytes_type, str_type, basestring_type):
              if type2 is unicode_type:
                  return type2
              elif type2.is_numeric:
                  return type1
              elif type1 is bytes_type and not type2.is_builtin_type:
                  return None   # RHS might implement '% operator differently in Py3
              else:
                  return basestring_type  # either str or unicode, can't tell
          return None
  
      def zero_division_message(self):
          if self.type.is_int:
              return "integer division or modulo by zero"
          else:
              return "float divmod()"
  
      def analyse_operation(self, env):
          DivNode.analyse_operation(self, env)
          if not self.type.is_pyobject:
              if self.cdivision is None:
                  self.cdivision = env.directives['cdivision'] or not self.type.signed
              if not self.cdivision and not self.type.is_int and not self.type.is_float:
                  error(self.pos, "mod operator not supported for type '%s'" % self.type)
  
      def generate_evaluation_code(self, code):
          if not self.type.is_pyobject and not self.cdivision:
              if self.type.is_int:
                  code.globalstate.use_utility_code(
                      mod_int_utility_code.specialize(self.type))
              else:  # float
                  code.globalstate.use_utility_code(
                      mod_float_utility_code.specialize(
                          self.type, math_h_modifier=self.type.math_h_modifier))
          # note: skipping over DivNode here
          NumBinopNode.generate_evaluation_code(self, code)
          self.generate_div_warning_code(code)
  
      def calculate_result_code(self):
          if self.cdivision:
              if self.type.is_float:
                  return "fmod%s(%s, %s)" % (
                      self.type.math_h_modifier,
                      self.operand1.result(),
                      self.operand2.result())
              else:
                  return "(%s %% %s)" % (
                      self.operand1.result(),
                      self.operand2.result())
          else:
              return "__Pyx_mod_%s(%s, %s)" % (
                      self.type.specialization_name(),
                      self.operand1.result(),
                      self.operand2.result())
  
      def py_operation_function(self):
          if self.operand1.type is unicode_type:
              if self.operand1.may_be_none():
                  return '__Pyx_PyUnicode_FormatSafe'
              else:
                  return 'PyUnicode_Format'
          elif self.operand1.type is str_type:
              if self.operand1.may_be_none():
                  return '__Pyx_PyString_FormatSafe'
              else:
                  return '__Pyx_PyString_Format'
          return super(ModNode, self).py_operation_function()
  
  
  class PowNode(NumBinopNode):
      #  '**' operator.
  
      def analyse_c_operation(self, env):
          NumBinopNode.analyse_c_operation(self, env)
          if self.type.is_complex:
              if self.type.real_type.is_float:
                  self.operand1 = self.operand1.coerce_to(self.type, env)
                  self.operand2 = self.operand2.coerce_to(self.type, env)
                  self.pow_func = "__Pyx_c_pow" + self.type.real_type.math_h_modifier
              else:
                  error(self.pos, "complex int powers not supported")
                  self.pow_func = "<error>"
          elif self.type.is_float:
              self.pow_func = "pow" + self.type.math_h_modifier
          elif self.type.is_int:
              self.pow_func = "__Pyx_pow_%s" % self.type.declaration_code('').replace(' ', '_')
              env.use_utility_code(
                  int_pow_utility_code.specialize(
                      func_name=self.pow_func,
                      type=self.type.declaration_code(''),
                      signed=self.type.signed and 1 or 0))
          elif not self.type.is_error:
              error(self.pos, "got unexpected types for C power operator: %s, %s" %
                              (self.operand1.type, self.operand2.type))
  
      def calculate_result_code(self):
          # Work around MSVC overloading ambiguity.
          def typecast(operand):
              if self.type == operand.type:
                  return operand.result()
              else:
                  return self.type.cast_code(operand.result())
          return "%s(%s, %s)" % (
              self.pow_func,
              typecast(self.operand1),
              typecast(self.operand2))
  
  
  # Note: This class is temporarily "shut down" into an ineffective temp
  # allocation mode.
  #
  # More sophisticated temp reuse was going on before, one could have a
  # look at adding this again after /all/ classes are converted to the
  # new temp scheme. (The temp juggling cannot work otherwise).
  class BoolBinopNode(ExprNode):
      #  Short-circuiting boolean operation.
      #
      #  operator     string
      #  operand1     ExprNode
      #  operand2     ExprNode
  
      subexprs = ['operand1', 'operand2']
  
      def infer_type(self, env):
          type1 = self.operand1.infer_type(env)
          type2 = self.operand2.infer_type(env)
          return PyrexTypes.independent_spanning_type(type1, type2)
  
      def may_be_none(self):
          if self.operator == 'or':
              return self.operand2.may_be_none()
          else:
              return self.operand1.may_be_none() or self.operand2.may_be_none()
  
      def calculate_constant_result(self):
          if self.operator == 'and':
              self.constant_result = \
                  self.operand1.constant_result and \
                  self.operand2.constant_result
          else:
              self.constant_result = \
                  self.operand1.constant_result or \
                  self.operand2.constant_result
  
      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 coerce_to_boolean(self, env):
          return BoolBinopNode(
              self.pos,
              operator = self.operator,
              operand1 = self.operand1.coerce_to_boolean(env),
              operand2 = self.operand2.coerce_to_boolean(env),
              type = PyrexTypes.c_bint_type,
              is_temp = self.is_temp)
  
      def analyse_types(self, env):
          self.operand1 = self.operand1.analyse_types(env)
          self.operand2 = self.operand2.analyse_types(env)
          self.type = PyrexTypes.independent_spanning_type(self.operand1.type, self.operand2.type)
          self.operand1 = self.operand1.coerce_to(self.type, env)
          self.operand2 = self.operand2.coerce_to(self.type, env)
  
          # For what we're about to do, it's vital that
          # both operands be temp nodes.
          self.operand1 = self.operand1.coerce_to_simple(env)
          self.operand2 = self.operand2.coerce_to_simple(env)
          self.is_temp = 1
          return self
  
      gil_message = "Truth-testing Python object"
  
      def check_const(self):
          return self.operand1.check_const() and self.operand2.check_const()
  
      def generate_evaluation_code(self, code):
          code.mark_pos(self.pos)
          self.operand1.generate_evaluation_code(code)
          test_result, uses_temp = self.generate_operand1_test(code)
          if self.operator == 'and':
              sense = ""
          else:
              sense = "!"
          code.putln(
              "if (%s%s) {" % (
                  sense,
                  test_result))
          if uses_temp:
              code.funcstate.release_temp(test_result)
          self.operand1.generate_disposal_code(code)
          self.operand2.generate_evaluation_code(code)
          self.allocate_temp_result(code)
          self.operand2.make_owned_reference(code)
          code.putln("%s = %s;" % (self.result(), self.operand2.result()))
          self.operand2.generate_post_assignment_code(code)
          self.operand2.free_temps(code)
          code.putln("} else {")
          self.operand1.make_owned_reference(code)
          code.putln("%s = %s;" % (self.result(), self.operand1.result()))
          self.operand1.generate_post_assignment_code(code)
          self.operand1.free_temps(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 = code.funcstate.allocate_temp(PyrexTypes.c_bint_type,
                                                         manage_ref=False)
              code.putln(
                  "%s = __Pyx_PyObject_IsTrue(%s); %s" % (
                      test_result,
                      self.operand1.py_result(),
                      code.error_goto_if_neg(test_result, self.pos)))
          else:
              test_result = self.operand1.result()
          return (test_result, self.type.is_pyobject)
  
  
  class CondExprNode(ExprNode):
      #  Short-circuiting conditional expression.
      #
      #  test        ExprNode
      #  true_val    ExprNode
      #  false_val   ExprNode
  
      true_val = None
      false_val = None
  
      subexprs = ['test', 'true_val', 'false_val']
  
      def type_dependencies(self, env):
          return self.true_val.type_dependencies(env) + self.false_val.type_dependencies(env)
  
      def infer_type(self, env):
          return PyrexTypes.independent_spanning_type(
              self.true_val.infer_type(env),
              self.false_val.infer_type(env))
  
      def calculate_constant_result(self):
          if self.test.constant_result:
              self.constant_result = self.true_val.constant_result
          else:
              self.constant_result = self.false_val.constant_result
  
      def analyse_types(self, env):
          self.test = self.test.analyse_types(env).coerce_to_boolean(env)
          self.true_val = self.true_val.analyse_types(env)
          self.false_val = self.false_val.analyse_types(env)
          self.is_temp = 1
          return self.analyse_result_type(env)
  
      def analyse_result_type(self, env):
          self.type = PyrexTypes.independent_spanning_type(
              self.true_val.type, self.false_val.type)
          if self.type.is_pyobject:
              self.result_ctype = py_object_type
          if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject:
              self.true_val = self.true_val.coerce_to(self.type, env)
              self.false_val = self.false_val.coerce_to(self.type, env)
          if self.type == PyrexTypes.error_type:
              self.type_error()
          return self
  
      def coerce_to(self, dst_type, env):
          self.true_val = self.true_val.coerce_to(dst_type, env)
          self.false_val = self.false_val.coerce_to(dst_type, env)
          self.result_ctype = None
          return self.analyse_result_type(env)
  
      def type_error(self):
          if not (self.true_val.type.is_error or self.false_val.type.is_error):
              error(self.pos, "Incompatible types in conditional expression (%s; %s)" %
                  (self.true_val.type, self.false_val.type))
          self.type = PyrexTypes.error_type
  
      def check_const(self):
          return (self.test.check_const()
              and self.true_val.check_const()
              and self.false_val.check_const())
  
      def generate_evaluation_code(self, code):
          # Because subexprs may not be evaluated we can use a more optimal
          # subexpr allocation strategy than the default, so override evaluation_code.
  
          code.mark_pos(self.pos)
          self.allocate_temp_result(code)
          self.test.generate_evaluation_code(code)
          code.putln("if (%s) {" % self.test.result() )
          self.eval_and_get(code, self.true_val)
          code.putln("} else {")
          self.eval_and_get(code, self.false_val)
          code.putln("}")
          self.test.generate_disposal_code(code)
          self.test.free_temps(code)
  
      def eval_and_get(self, code, expr):
          expr.generate_evaluation_code(code)
          expr.make_owned_reference(code)
          code.putln('%s = %s;' % (self.result(), expr.result_as(self.ctype())))
          expr.generate_post_assignment_code(code)
          expr.free_temps(code)
  
  richcmp_constants = {
      "<" : "Py_LT",
      "<=": "Py_LE",
      "==": "Py_EQ",
      "!=": "Py_NE",
      "<>": "Py_NE",
      ">" : "Py_GT",
      ">=": "Py_GE",
      # the following are faked by special compare functions
      "in"    : "Py_EQ",
      "not_in": "Py_NE",
  }
  
  class CmpNode(object):
      #  Mixin class containing code common to PrimaryCmpNodes
      #  and CascadedCmpNodes.
  
      special_bool_cmp_function = None
      special_bool_cmp_utility_code = None
  
      def infer_type(self, env):
          # TODO: Actually implement this (after merging with -unstable).
          return py_object_type
  
      def calculate_cascaded_constant_result(self, operand1_result):
          func = compile_time_binary_operators[self.operator]
          operand2_result = self.operand2.constant_result
          if (isinstance(operand1_result, (bytes, unicode)) and
                  isinstance(operand2_result, (bytes, unicode)) and
                  type(operand1_result) != type(operand2_result)):
              # string comparison of different types isn't portable
              return
  
          if self.operator in ('in', 'not_in'):
              if isinstance(self.operand2, (ListNode, TupleNode, SetNode)):
                  if not self.operand2.args:
                      self.constant_result = self.operator == 'not_in'
                      return
                  elif isinstance(self.operand2, ListNode) and not self.cascade:
                      # tuples are more efficient to store than lists
                      self.operand2 = self.operand2.as_tuple()
              elif isinstance(self.operand2, DictNode):
                  if not self.operand2.key_value_pairs:
                      self.constant_result = self.operator == 'not_in'
                      return
  
          self.constant_result = func(operand1_result, operand2_result)
  
      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.cascaded_compile_time_value(operand2, denv)
          return result
  
      def is_cpp_comparison(self):
          return self.operand1.type.is_cpp_class or self.operand2.type.is_cpp_class
  
      def find_common_int_type(self, env, op, operand1, operand2):
          # type1 != type2 and at least one of the types is not a C int
          type1 = operand1.type
          type2 = operand2.type
          type1_can_be_int = False
          type2_can_be_int = False
  
          if operand1.is_string_literal and operand1.can_coerce_to_char_literal():
              type1_can_be_int = True
          if operand2.is_string_literal and operand2.can_coerce_to_char_literal():
              type2_can_be_int = True
  
          if type1.is_int:
              if type2_can_be_int:
                  return type1
          elif type2.is_int:
              if type1_can_be_int:
                  return type2
          elif type1_can_be_int:
              if type2_can_be_int:
                  if Builtin.unicode_type in (type1, type2):
                      return PyrexTypes.c_py_ucs4_type
                  else:
                      return PyrexTypes.c_uchar_type
  
          return None
  
      def find_common_type(self, env, op, operand1, common_type=None):
          operand2 = self.operand2
          type1 = operand1.type
          type2 = operand2.type
  
          new_common_type = None
  
          # catch general errors
          if type1 == str_type and (type2.is_string or type2 in (bytes_type, unicode_type)) or \
                 type2 == str_type and (type1.is_string or type1 in (bytes_type, unicode_type)):
              error(self.pos, "Comparisons between bytes/unicode and str are not portable to Python 3")
              new_common_type = error_type
  
          # try to use numeric comparisons where possible
          elif type1.is_complex or type2.is_complex:
              if op not in ('==', '!=') \
                 and (type1.is_complex or type1.is_numeric) \
                 and (type2.is_complex or type2.is_numeric):
                  error(self.pos, "complex types are unordered")
                  new_common_type = error_type
              elif type1.is_pyobject:
                  new_common_type = type1
              elif type2.is_pyobject:
                  new_common_type = type2
              else:
                  new_common_type = PyrexTypes.widest_numeric_type(type1, type2)
          elif type1.is_numeric and type2.is_numeric:
              new_common_type = PyrexTypes.widest_numeric_type(type1, type2)
          elif common_type is None or not common_type.is_pyobject:
              new_common_type = self.find_common_int_type(env, op, operand1, operand2)
  
          if new_common_type is None:
              # fall back to generic type compatibility tests
              if type1 == type2:
                  new_common_type = type1
              elif type1.is_pyobject or type2.is_pyobject:
                  if type2.is_numeric or type2.is_string:
                      if operand2.check_for_coercion_error(type1, env):
                          new_common_type = error_type
                      else:
                          new_common_type = py_object_type
                  elif type1.is_numeric or type1.is_string:
                      if operand1.check_for_coercion_error(type2, env):
                          new_common_type = error_type
                      else:
                          new_common_type = py_object_type
                  elif py_object_type.assignable_from(type1) and py_object_type.assignable_from(type2):
                      new_common_type = py_object_type
                  else:
                      # one Python type and one non-Python type, not assignable
                      self.invalid_types_error(operand1, op, operand2)
                      new_common_type = error_type
              elif type1.assignable_from(type2):
                  new_common_type = type1
              elif type2.assignable_from(type1):
                  new_common_type = type2
              else:
                  # C types that we couldn't handle up to here are an error
                  self.invalid_types_error(operand1, op, operand2)
                  new_common_type = error_type
  
          if new_common_type.is_string and (isinstance(operand1, BytesNode) or
                                            isinstance(operand2, BytesNode)):
              # special case when comparing char* to bytes literal: must
              # compare string values!
              new_common_type = bytes_type
  
          # recursively merge types
          if common_type is None or new_common_type.is_error:
              common_type = new_common_type
          else:
              # we could do a lot better by splitting the comparison
              # into a non-Python part and a Python part, but this is
              # safer for now
              common_type = PyrexTypes.spanning_type(common_type, new_common_type)
  
          if self.cascade:
              common_type = self.cascade.find_common_type(env, self.operator, operand2, common_type)
  
          return common_type
  
      def invalid_types_error(self, operand1, op, operand2):
          error(self.pos, "Invalid types for '%s' (%s, %s)" %
                (op, operand1.type, operand2.type))
  
      def is_python_comparison(self):
          return (not self.is_ptr_contains()
              and not self.is_c_string_contains()
              and (self.has_python_operands()
                   or (self.cascade and self.cascade.is_python_comparison())
                   or self.operator in ('in', 'not_in')))
  
      def coerce_operands_to(self, dst_type, env):
          operand2 = self.operand2
          if operand2.type != dst_type:
              self.operand2 = operand2.coerce_to(dst_type, env)
          if self.cascade:
              self.cascade.coerce_operands_to(dst_type, env)
  
      def is_python_result(self):
          return ((self.has_python_operands() and
                   self.special_bool_cmp_function is None and
                   self.operator not in ('is', 'is_not', 'in', 'not_in') and
                   not self.is_c_string_contains() and
                   not self.is_ptr_contains())
              or (self.cascade and self.cascade.is_python_result()))
  
      def is_c_string_contains(self):
          return self.operator in ('in', 'not_in') and \
                 ((self.operand1.type.is_int
                   and (self.operand2.type.is_string or self.operand2.type is bytes_type)) or
                  (self.operand1.type.is_unicode_char
                   and self.operand2.type is unicode_type))
  
      def is_ptr_contains(self):
          if self.operator in ('in', 'not_in'):
              container_type = self.operand2.type
              return (container_type.is_ptr or container_type.is_array) \
                  and not container_type.is_string
  
      def find_special_bool_compare_function(self, env, operand1, result_is_bool=False):
          # note: currently operand1 must get coerced to a Python object if we succeed here!
          if self.operator in ('==', '!='):
              type1, type2 = operand1.type, self.operand2.type
              if result_is_bool or (type1.is_builtin_type and type2.is_builtin_type):
                  if type1 is Builtin.unicode_type or type2 is Builtin.unicode_type:
                      self.special_bool_cmp_utility_code = UtilityCode.load_cached("UnicodeEquals", "StringTools.c")
                      self.special_bool_cmp_function = "__Pyx_PyUnicode_Equals"
                      return True
                  elif type1 is Builtin.bytes_type or type2 is Builtin.bytes_type:
                      self.special_bool_cmp_utility_code = UtilityCode.load_cached("BytesEquals", "StringTools.c")
                      self.special_bool_cmp_function = "__Pyx_PyBytes_Equals"
                      return True
                  elif type1 is Builtin.basestring_type or type2 is Builtin.basestring_type:
                      self.special_bool_cmp_utility_code = UtilityCode.load_cached("UnicodeEquals", "StringTools.c")
                      self.special_bool_cmp_function = "__Pyx_PyUnicode_Equals"
                      return True
                  elif type1 is Builtin.str_type or type2 is Builtin.str_type:
                      self.special_bool_cmp_utility_code = UtilityCode.load_cached("StrEquals", "StringTools.c")
                      self.special_bool_cmp_function = "__Pyx_PyString_Equals"
                      return True
          elif self.operator in ('in', 'not_in'):
              if self.operand2.type is Builtin.dict_type:
                  self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable")
                  self.special_bool_cmp_utility_code = UtilityCode.load_cached("PyDictContains", "ObjectHandling.c")
                  self.special_bool_cmp_function = "__Pyx_PyDict_Contains"
                  return True
              elif self.operand2.type is Builtin.unicode_type:
                  self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable")
                  self.special_bool_cmp_utility_code = UtilityCode.load_cached("PyUnicodeContains", "StringTools.c")
                  self.special_bool_cmp_function = "__Pyx_PyUnicode_Contains"
                  return True
              else:
                  if not self.operand2.type.is_pyobject:
                      self.operand2 = self.operand2.coerce_to_pyobject(env)
                  self.special_bool_cmp_utility_code = UtilityCode.load_cached("PySequenceContains", "ObjectHandling.c")
                  self.special_bool_cmp_function = "__Pyx_PySequence_Contains"
                  return True
          return False
  
      def generate_operation_code(self, code, result_code,
              operand1, op , operand2):
          if self.type.is_pyobject:
              error_clause = code.error_goto_if_null
              got_ref = "__Pyx_XGOTREF(%s); " % result_code
              if self.special_bool_cmp_function:
                  code.globalstate.use_utility_code(
                      UtilityCode.load_cached("PyBoolOrNullFromLong", "ObjectHandling.c"))
                  coerce_result = "__Pyx_PyBoolOrNull_FromLong"
              else:
                  coerce_result = "__Pyx_PyBool_FromLong"
          else:
              error_clause = code.error_goto_if_neg
              got_ref = ""
              coerce_result = ""
  
          if self.special_bool_cmp_function:
              if operand1.type.is_pyobject:
                  result1 = operand1.py_result()
              else:
                  result1 = operand1.result()
              if operand2.type.is_pyobject:
                  result2 = operand2.py_result()
              else:
                  result2 = operand2.result()
              if self.special_bool_cmp_utility_code:
                  code.globalstate.use_utility_code(self.special_bool_cmp_utility_code)
              code.putln(
                  "%s = %s(%s(%s, %s, %s)); %s%s" % (
                      result_code,
                      coerce_result,
                      self.special_bool_cmp_function,
                      result1, result2, richcmp_constants[op],
                      got_ref,
                      error_clause(result_code, self.pos)))
  
          elif operand1.type.is_pyobject and op not in ('is', 'is_not'):
              assert op not in ('in', 'not_in'), op
              code.putln("%s = PyObject_RichCompare(%s, %s, %s); %s%s" % (
                      result_code,
                      operand1.py_result(),
                      operand2.py_result(),
                      richcmp_constants[op],
                      got_ref,
                      error_clause(result_code, self.pos)))
  
          elif operand1.type.is_complex:
              code.putln("%s = %s(%s%s(%s, %s));" % (
                  result_code,
                  coerce_result,
                  op == "!=" and "!" or "",
                  operand1.type.unary_op('eq'),
                  operand1.result(),
                  operand2.result()))
  
          else:
              type1 = operand1.type
              type2 = operand2.type
              if (type1.is_extension_type or type2.is_extension_type) \
                      and not type1.same_as(type2):
                  common_type = py_object_type
              elif type1.is_numeric:
                  common_type = PyrexTypes.widest_numeric_type(type1, type2)
              else:
                  common_type = type1
              code1 = operand1.result_as(common_type)
              code2 = operand2.result_as(common_type)
              code.putln("%s = %s(%s %s %s);" % (
                  result_code,
                  coerce_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.
  
      child_attrs = ['operand1', 'operand2', 'coerced_operand2', 'cascade']
  
      cascade = None
      coerced_operand2 = None
      is_memslice_nonecheck = False
  
      def infer_type(self, env):
          # TODO: Actually implement this (after merging with -unstable).
          return py_object_type
  
      def type_dependencies(self, env):
          return ()
  
      def calculate_constant_result(self):
          assert not self.cascade
          self.calculate_cascaded_constant_result(self.operand1.constant_result)
  
      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 = self.operand1.analyse_types(env)
          self.operand2 = self.operand2.analyse_types(env)
          if self.is_cpp_comparison():
              self.analyse_cpp_comparison(env)
              if self.cascade:
                  error(self.pos, "Cascading comparison not yet supported for cpp types.")
              return self
  
          if self.analyse_memoryviewslice_comparison(env):
              return self
  
          if self.cascade:
              self.cascade = self.cascade.analyse_types(env)
  
          if self.operator in ('in', 'not_in'):
              if self.is_c_string_contains():
                  self.is_pycmp = False
                  common_type = None
                  if self.cascade:
                      error(self.pos, "Cascading comparison not yet supported for 'int_val in string'.")
                      return self
                  if self.operand2.type is unicode_type:
                      env.use_utility_code(UtilityCode.load_cached("PyUCS4InUnicode", "StringTools.c"))
                  else:
                      if self.operand1.type is PyrexTypes.c_uchar_type:
                          self.operand1 = self.operand1.coerce_to(PyrexTypes.c_char_type, env)
                      if self.operand2.type is not bytes_type:
                          self.operand2 = self.operand2.coerce_to(bytes_type, env)
                      env.use_utility_code(UtilityCode.load_cached("BytesContains", "StringTools.c"))
                  self.operand2 = self.operand2.as_none_safe_node(
                      "argument of type 'NoneType' is not iterable")
              elif self.is_ptr_contains():
                  if self.cascade:
                      error(self.pos, "Cascading comparison not supported for 'val in sliced pointer'.")
                  self.type = PyrexTypes.c_bint_type
                  # Will be transformed by IterationTransform
                  return self
              elif self.find_special_bool_compare_function(env, self.operand1):
                  if not self.operand1.type.is_pyobject:
                      self.operand1 = self.operand1.coerce_to_pyobject(env)
                  common_type = None # if coercion needed, the method call above has already done it
                  self.is_pycmp = False # result is bint
              else:
                  common_type = py_object_type
                  self.is_pycmp = True
          elif self.find_special_bool_compare_function(env, self.operand1):
              if not self.operand1.type.is_pyobject:
                  self.operand1 = self.operand1.coerce_to_pyobject(env)
              common_type = None # if coercion needed, the method call above has already done it
              self.is_pycmp = False # result is bint
          else:
              common_type = self.find_common_type(env, self.operator, self.operand1)
              self.is_pycmp = common_type.is_pyobject
  
          if common_type is not None and not common_type.is_error:
              if self.operand1.type != common_type:
                  self.operand1 = self.operand1.coerce_to(common_type, env)
              self.coerce_operands_to(common_type, env)
  
          if self.cascade:
              self.operand2 = self.operand2.coerce_to_simple(env)
              self.cascade.coerce_cascaded_operands_to_temp(env)
              operand2 = self.cascade.optimise_comparison(self.operand2, env)
              if operand2 is not self.operand2:
                  self.coerced_operand2 = operand2
          if self.is_python_result():
              self.type = PyrexTypes.py_object_type
          else:
              self.type = PyrexTypes.c_bint_type
          cdr = self.cascade
          while cdr:
              cdr.type = self.type
              cdr = cdr.cascade
          if self.is_pycmp or self.cascade or self.special_bool_cmp_function:
              # 1) owned reference, 2) reused value, 3) potential function error return value
              self.is_temp = 1
          return self
  
      def analyse_cpp_comparison(self, env):
          type1 = self.operand1.type
          type2 = self.operand2.type
          entry = env.lookup_operator(self.operator, [self.operand1, self.operand2])
          if entry is None:
              error(self.pos, "Invalid types for '%s' (%s, %s)" %
                  (self.operator, type1, type2))
              self.type = PyrexTypes.error_type
              self.result_code = "<error>"
              return
          func_type = entry.type
          if func_type.is_ptr:
              func_type = func_type.base_type
          if len(func_type.args) == 1:
              self.operand2 = self.operand2.coerce_to(func_type.args[0].type, env)
          else:
              self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env)
              self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env)
          self.is_pycmp = False
          self.type = func_type.return_type
  
      def analyse_memoryviewslice_comparison(self, env):
          have_none = self.operand1.is_none or self.operand2.is_none
          have_slice = (self.operand1.type.is_memoryviewslice or
                        self.operand2.type.is_memoryviewslice)
          ops = ('==', '!=', 'is', 'is_not')
          if have_slice and have_none and self.operator in ops:
              self.is_pycmp = False
              self.type = PyrexTypes.c_bint_type
              self.is_memslice_nonecheck = True
              return True
  
          return False
  
      def coerce_to_boolean(self, env):
          if self.is_pycmp:
              # coercing to bool => may allow for more efficient comparison code
              if self.find_special_bool_compare_function(
                      env, self.operand1, result_is_bool=True):
                  self.is_pycmp = False
                  self.type = PyrexTypes.c_bint_type
                  self.is_temp = 1
                  if self.cascade:
                      operand2 = self.cascade.optimise_comparison(
                          self.operand2, env, result_is_bool=True)
                      if operand2 is not self.operand2:
                          self.coerced_operand2 = operand2
                  return self
          # TODO: check if we can optimise parts of the cascade here
          return ExprNode.coerce_to_boolean(self, env)
  
      def has_python_operands(self):
          return (self.operand1.type.is_pyobject
              or self.operand2.type.is_pyobject)
  
      def check_const(self):
          if self.cascade:
              self.not_const()
              return False
          else:
              return self.operand1.check_const() and self.operand2.check_const()
  
      def calculate_result_code(self):
          if self.operand1.type.is_complex:
              if self.operator == "!=":
                  negation = "!"
              else:
                  negation = ""
              return "(%s%s(%s, %s))" % (
                  negation,
                  self.operand1.type.binary_op('=='),
                  self.operand1.result(),
                  self.operand2.result())
          elif self.is_c_string_contains():
              if self.operand2.type is unicode_type:
                  method = "__Pyx_UnicodeContainsUCS4"
              else:
                  method = "__Pyx_BytesContains"
              if self.operator == "not_in":
                  negation = "!"
              else:
                  negation = ""
              return "(%s%s(%s, %s))" % (
                  negation,
                  method,
                  self.operand2.result(),
                  self.operand1.result())
          else:
              result1 = self.operand1.result()
              result2 = self.operand2.result()
              if self.is_memslice_nonecheck:
                  if self.operand1.type.is_memoryviewslice:
                      result1 = "((PyObject *) %s.memview)" % result1
                  else:
                      result2 = "((PyObject *) %s.memview)" % result2
  
              return "(%s %s %s)" % (
                  result1,
                  self.c_operator(self.operator),
                  result2)
  
      def generate_evaluation_code(self, code):
          self.operand1.generate_evaluation_code(code)
          self.operand2.generate_evaluation_code(code)
          if self.is_temp:
              self.allocate_temp_result(code)
              self.generate_operation_code(code, self.result(),
                  self.operand1, self.operator, self.operand2)
              if self.cascade:
                  self.cascade.generate_evaluation_code(
                      code, self.result(), self.coerced_operand2 or self.operand2,
                      needs_evaluation=self.coerced_operand2 is not None)
              self.operand1.generate_disposal_code(code)
              self.operand1.free_temps(code)
              self.operand2.generate_disposal_code(code)
              self.operand2.free_temps(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)
  
      def free_subexpr_temps(self, code):
          #  If this is called, it is a non-cascaded cmp,
          #  so only need to dispose of the two main operands.
          self.operand1.free_temps(code)
          self.operand2.free_temps(code)
  
      def annotate(self, code):
          self.operand1.annotate(code)
          self.operand2.annotate(code)
          if self.cascade:
              self.cascade.annotate(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
  
      child_attrs = ['operand2', 'coerced_operand2', 'cascade']
  
      cascade = None
      coerced_operand2 = None
      constant_result = constant_value_not_set # FIXME: where to calculate this?
  
      def infer_type(self, env):
          # TODO: Actually implement this (after merging with -unstable).
          return py_object_type
  
      def type_dependencies(self, env):
          return ()
  
      def has_constant_result(self):
          return self.constant_result is not constant_value_not_set and \
                 self.constant_result is not not_a_constant
  
      def analyse_types(self, env):
          self.operand2 = self.operand2.analyse_types(env)
          if self.cascade:
              self.cascade = self.cascade.analyse_types(env)
          return self
  
      def has_python_operands(self):
          return self.operand2.type.is_pyobject
  
      def optimise_comparison(self, operand1, env, result_is_bool=False):
          if self.find_special_bool_compare_function(env, operand1, result_is_bool):
              self.is_pycmp = False
              self.type = PyrexTypes.c_bint_type
              if not operand1.type.is_pyobject:
                  operand1 = operand1.coerce_to_pyobject(env)
          if self.cascade:
              operand2 = self.cascade.optimise_comparison(self.operand2, env, result_is_bool)
              if operand2 is not self.operand2:
                  self.coerced_operand2 = operand2
          return operand1
  
      def coerce_operands_to_pyobjects(self, env):
          self.operand2 = self.operand2.coerce_to_pyobject(env)
          if self.operand2.type is dict_type and self.operator in ('in', 'not_in'):
              self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable")
          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 generate_evaluation_code(self, code, result, operand1, needs_evaluation=False):
          if self.type.is_pyobject:
              code.putln("if (__Pyx_PyObject_IsTrue(%s)) {" % result)
              code.put_decref(result, self.type)
          else:
              code.putln("if (%s) {" % result)
          if needs_evaluation:
              operand1.generate_evaluation_code(code)
          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.coerced_operand2 or self.operand2,
                  needs_evaluation=self.coerced_operand2 is not None)
          if needs_evaluation:
              operand1.generate_disposal_code(code)
              operand1.free_temps(code)
          # Cascaded cmp result is always temp
          self.operand2.generate_disposal_code(code)
          self.operand2.free_temps(code)
          code.putln("}")
  
      def annotate(self, code):
          self.operand2.annotate(code)
          if self.cascade:
              self.cascade.annotate(code)
  
  
  binop_node_classes = {
      "or":       BoolBinopNode,
      "and":      BoolBinopNode,
      "|":        IntBinopNode,
      "^":        IntBinopNode,
      "&":        IntBinopNode,
      "<<":       IntBinopNode,
      ">>":       IntBinopNode,
      "+":        AddNode,
      "-":        SubNode,
      "*":        MulNode,
      "/":        DivNode,
      "//":       DivNode,
      "%":        ModNode,
      "**":       PowNode
  }
  
  def binop_node(pos, operator, operand1, operand2, inplace=False):
      # Construct binop node of appropriate class for
      # given operator.
      return binop_node_classes[operator](pos,
          operator = operator,
          operand1 = operand1,
          operand2 = operand2,
          inplace = inplace)
  
  #-------------------------------------------------------------------
  #
  #  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']
      constant_result = not_a_constant
  
      def __init__(self, arg):
          super(CoercionNode, self).__init__(arg.pos)
          self.arg = arg
          if debug_coercion:
              print("%s Coercing %s" % (self, self.arg))
  
      def calculate_constant_result(self):
          # constant folding can break type coercion, so this is disabled
          pass
  
      def annotate(self, code):
          self.arg.annotate(code)
          if self.arg.type != self.type:
              file, line, col = self.pos
              code.annotate((file, line, col-1), AnnotationItem(
                  style='coerce', tag='coerce', text='[%s] to [%s]' % (self.arg.type, self.type)))
  
  class CoerceToMemViewSliceNode(CoercionNode):
      """
      Coerce an object to a memoryview slice. This holds a new reference in
      a managed temp.
      """
  
      def __init__(self, arg, dst_type, env):
          assert dst_type.is_memoryviewslice
          assert not arg.type.is_memoryviewslice
          CoercionNode.__init__(self, arg)
          self.type = dst_type
          self.is_temp = 1
          self.env = env
          self.use_managed_ref = True
          self.arg = arg
  
      def generate_result_code(self, code):
          self.type.create_from_py_utility_code(self.env)
          code.putln("%s = %s(%s);" % (self.result(),
                                       self.type.from_py_function,
                                       self.arg.py_result()))
  
          error_cond = self.type.error_condition(self.result())
          code.putln(code.error_goto_if(error_cond, self.pos))
  
  
  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 may_be_none(self):
          return self.arg.may_be_none()
  
      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.
  
      exact_builtin_type = True
  
      def __init__(self, arg, dst_type, env, notnone=False):
          #  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 or dst_type.is_builtin_type, "PyTypeTest on non extension type"
          CoercionNode.__init__(self, arg)
          self.type = dst_type
          self.result_ctype = arg.ctype()
          self.notnone = notnone
  
      nogil_check = Node.gil_error
      gil_message = "Python type test"
  
      def analyse_types(self, env):
          return self
  
      def may_be_none(self):
          if self.notnone:
              return False
          return self.arg.may_be_none()
  
      def is_simple(self):
          return self.arg.is_simple()
  
      def result_in_temp(self):
          return self.arg.result_in_temp()
  
      def is_ephemeral(self):
          return self.arg.is_ephemeral()
  
      def nonlocally_immutable(self):
          return self.arg.nonlocally_immutable()
  
      def calculate_constant_result(self):
          # FIXME
          pass
  
      def calculate_result_code(self):
          return self.arg.result()
  
      def generate_result_code(self, code):
          if self.type.typeobj_is_available():
              if self.type.is_builtin_type:
                  type_test = self.type.type_test_code(
                      self.arg.py_result(),
                      self.notnone, exact=self.exact_builtin_type)
              else:
                  type_test = self.type.type_test_code(
                      self.arg.py_result(), self.notnone)
                  code.globalstate.use_utility_code(
                      UtilityCode.load_cached("ExtTypeTest", "ObjectHandling.c"))
              code.putln("if (!(%s)) %s" % (
                  type_test, 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)
  
      def free_temps(self, code):
          self.arg.free_temps(code)
  
  
  class NoneCheckNode(CoercionNode):
      # This node is used to check that a Python object is not None and
      # raises an appropriate exception (as specified by the creating
      # transform).
  
      is_nonecheck = True
  
      def __init__(self, arg, exception_type_cname, exception_message,
                   exception_format_args):
          CoercionNode.__init__(self, arg)
          self.type = arg.type
          self.result_ctype = arg.ctype()
          self.exception_type_cname = exception_type_cname
          self.exception_message = exception_message
          self.exception_format_args = tuple(exception_format_args or ())
  
      nogil_check = None # this node only guards an operation that would fail already
  
      def analyse_types(self, env):
          return self
  
      def may_be_none(self):
          return False
  
      def is_simple(self):
          return self.arg.is_simple()
  
      def result_in_temp(self):
          return self.arg.result_in_temp()
  
      def nonlocally_immutable(self):
          return self.arg.nonlocally_immutable()
  
      def calculate_result_code(self):
          return self.arg.result()
  
      def condition(self):
          if self.type.is_pyobject:
              return self.arg.py_result()
          elif self.type.is_memoryviewslice:
              return "((PyObject *) %s.memview)" % self.arg.result()
          else:
              raise Exception("unsupported type")
  
      def put_nonecheck(self, code):
          code.putln(
              "if (unlikely(%s == Py_None)) {" % self.condition())
  
          if self.in_nogil_context:
              code.put_ensure_gil()
  
          escape = StringEncoding.escape_byte_string
          if self.exception_format_args:
              code.putln('PyErr_Format(%s, "%s", %s);' % (
                  self.exception_type_cname,
                  StringEncoding.escape_byte_string(
                      self.exception_message.encode('UTF-8')),
                  ', '.join([ '"%s"' % escape(str(arg).encode('UTF-8'))
                              for arg in self.exception_format_args ])))
          else:
              code.putln('PyErr_SetString(%s, "%s");' % (
                  self.exception_type_cname,
                  escape(self.exception_message.encode('UTF-8'))))
  
          if self.in_nogil_context:
              code.put_release_ensured_gil()
  
          code.putln(code.error_goto(self.pos))
          code.putln("}")
  
      def generate_result_code(self, code):
          self.put_nonecheck(code)
  
      def generate_post_assignment_code(self, code):
          self.arg.generate_post_assignment_code(code)
  
      def free_temps(self, code):
          self.arg.free_temps(code)
  
  
  class CoerceToPyTypeNode(CoercionNode):
      #  This node is used to convert a C data type
      #  to a Python object.
  
      type = py_object_type
      is_temp = 1
  
      def __init__(self, arg, env, type=py_object_type):
          if not arg.type.create_to_py_utility_code(env):
              error(arg.pos, "Cannot convert '%s' to Python object" % arg.type)
          elif arg.type.is_complex:
              # special case: complex coercion is so complex that it
              # uses a macro ("__pyx_PyComplex_FromComplex()"), for
              # which the argument must be simple
              arg = arg.coerce_to_simple(env)
          CoercionNode.__init__(self, arg)
          if type is py_object_type:
              # be specific about some known types
              if arg.type.is_string or arg.type.is_cpp_string:
                  self.type = default_str_type(env)
              elif arg.type.is_pyunicode_ptr or arg.type.is_unicode_char:
                  self.type = unicode_type
              elif arg.type.is_complex:
                  self.type = Builtin.complex_type
          elif arg.type.is_string or arg.type.is_cpp_string:
              if (type not in (bytes_type, bytearray_type)
                      and not env.directives['c_string_encoding']):
                  error(arg.pos,
                      "default encoding required for conversion from '%s' to '%s'" %
                      (arg.type, type))
              self.type = type
          else:
              # FIXME: check that the target type and the resulting type are compatible
              pass
  
          if arg.type.is_memoryviewslice:
              # Register utility codes at this point
              arg.type.get_to_py_function(env, arg)
  
          self.env = env
  
      gil_message = "Converting to Python object"
  
      def may_be_none(self):
          # FIXME: is this always safe?
          return False
  
      def coerce_to_boolean(self, env):
          arg_type = self.arg.type
          if (arg_type == PyrexTypes.c_bint_type or
              (arg_type.is_pyobject and arg_type.name == 'bool')):
              return self.arg.coerce_to_temp(env)
          else:
              return CoerceToBooleanNode(self, env)
  
      def coerce_to_integer(self, env):
          # If not already some C integer type, coerce to longint.
          if self.arg.type.is_int:
              return self.arg
          else:
              return self.arg.coerce_to(PyrexTypes.c_long_type, env)
  
      def analyse_types(self, env):
          # The arg is always already analysed
          return self
  
      def generate_result_code(self, code):
          arg_type = self.arg.type
          if arg_type.is_memoryviewslice:
              funccall = arg_type.get_to_py_function(self.env, self.arg)
          else:
              func = arg_type.to_py_function
              if arg_type.is_string or arg_type.is_cpp_string:
                  if self.type in (bytes_type, str_type, unicode_type):
                      func = func.replace("Object", self.type.name.title())
                  elif self.type is bytearray_type:
                      func = func.replace("Object", "ByteArray")
              funccall = "%s(%s)" % (func, self.arg.result())
  
          code.putln('%s = %s; %s' % (
              self.result(),
              funccall,
              code.error_goto_if_null(self.result(), self.pos)))
  
          code.put_gotref(self.py_result())
  
  
  class CoerceIntToBytesNode(CoerceToPyTypeNode):
      #  This node is used to convert a C int type to a Python bytes
      #  object.
  
      is_temp = 1
  
      def __init__(self, arg, env):
          arg = arg.coerce_to_simple(env)
          CoercionNode.__init__(self, arg)
          self.type = Builtin.bytes_type
  
      def generate_result_code(self, code):
          arg = self.arg
          arg_result = arg.result()
          if arg.type not in (PyrexTypes.c_char_type,
                              PyrexTypes.c_uchar_type,
                              PyrexTypes.c_schar_type):
              if arg.type.signed:
                  code.putln("if ((%s < 0) || (%s > 255)) {" % (
                      arg_result, arg_result))
              else:
                  code.putln("if (%s > 255) {" % arg_result)
              code.putln('PyErr_SetString(PyExc_OverflowError, '
                         '"value too large to pack into a byte"); %s' % (
                             code.error_goto(self.pos)))
              code.putln('}')
          temp = None
          if arg.type is not PyrexTypes.c_char_type:
              temp = code.funcstate.allocate_temp(PyrexTypes.c_char_type, manage_ref=False)
              code.putln("%s = (char)%s;" % (temp, arg_result))
              arg_result = temp
          code.putln('%s = PyBytes_FromStringAndSize(&%s, 1); %s' % (
              self.result(),
              arg_result,
              code.error_goto_if_null(self.result(), self.pos)))
          if temp is not None:
              code.funcstate.release_temp(temp)
          code.put_gotref(self.py_result())
  
  
  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.create_from_py_utility_code(env):
              error(arg.pos,
                    "Cannot convert Python object to '%s'" % result_type)
          if self.type.is_string or self.type.is_pyunicode_ptr:
              if self.arg.is_ephemeral():
                  error(arg.pos,
                        "Obtaining '%s' from temporary Python value" % result_type)
              elif self.arg.is_name and self.arg.entry and self.arg.entry.is_pyglobal:
                  warning(arg.pos,
                          "Obtaining '%s' from externally modifiable global Python value" % result_type,
                          level=1)
  
      def analyse_types(self, env):
          # The arg is always already analysed
          return self
  
      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)
          code.putln('%s = %s; %s' % (
              self.result(),
              rhs,
              code.error_goto_if(self.type.error_condition(self.result()), self.pos)))
          if self.type.is_pyobject:
              code.put_gotref(self.py_result())
  
      def nogil_check(self, env):
          error(self.pos, "Coercion from Python not allowed without the GIL")
  
  
  class CoerceToBooleanNode(CoercionNode):
      #  This node is used when a result needs to be used
      #  in a boolean context.
  
      type = PyrexTypes.c_bint_type
  
      _special_builtins = {
          Builtin.list_type    : 'PyList_GET_SIZE',
          Builtin.tuple_type   : 'PyTuple_GET_SIZE',
          Builtin.bytes_type   : 'PyBytes_GET_SIZE',
          Builtin.unicode_type : 'PyUnicode_GET_SIZE',
          }
  
      def __init__(self, arg, env):
          CoercionNode.__init__(self, arg)
          if arg.type.is_pyobject:
              self.is_temp = 1
  
      def nogil_check(self, env):
          if self.arg.type.is_pyobject and self._special_builtins.get(self.arg.type) is None:
              self.gil_error()
  
      gil_message = "Truth-testing Python object"
  
      def check_const(self):
          if self.is_temp:
              self.not_const()
              return False
          return self.arg.check_const()
  
      def calculate_result_code(self):
          return "(%s != 0)" % self.arg.result()
  
      def generate_result_code(self, code):
          if not self.is_temp:
              return
          test_func = self._special_builtins.get(self.arg.type)
          if test_func is not None:
              code.putln("%s = (%s != Py_None) && (%s(%s) != 0);" % (
                         self.result(),
                         self.arg.py_result(),
                         test_func,
                         self.arg.py_result()))
          else:
              code.putln(
                  "%s = __Pyx_PyObject_IsTrue(%s); %s" % (
                      self.result(),
                      self.arg.py_result(),
                      code.error_goto_if_neg(self.result(), self.pos)))
  
  class CoerceToComplexNode(CoercionNode):
  
      def __init__(self, arg, dst_type, env):
          if arg.type.is_complex:
              arg = arg.coerce_to_simple(env)
          self.type = dst_type
          CoercionNode.__init__(self, arg)
          dst_type.create_declaration_utility_code(env)
  
      def calculate_result_code(self):
          if self.arg.type.is_complex:
              real_part = "__Pyx_CREAL(%s)" % self.arg.result()
              imag_part = "__Pyx_CIMAG(%s)" % self.arg.result()
          else:
              real_part = self.arg.result()
              imag_part = "0"
          return "%s(%s, %s)" % (
                  self.type.from_parts,
                  real_part,
                  imag_part)
  
      def generate_result_code(self, code):
          pass
  
  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.as_argument_type()
          self.constant_result = self.arg.constant_result
          self.is_temp = 1
          if self.type.is_pyobject:
              self.result_ctype = py_object_type
  
      gil_message = "Creating temporary Python reference"
  
      def analyse_types(self, env):
          # The arg is always already analysed
          return self
  
      def coerce_to_boolean(self, env):
          self.arg = self.arg.coerce_to_boolean(env)
          if self.arg.is_simple():
              return self.arg
          self.type = self.arg.type
          self.result_ctype = self.type
          return self
  
      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.use_managed_ref:
              if self.type.is_pyobject:
                  code.put_incref(self.result(), self.ctype())
              elif self.type.is_memoryviewslice:
                  code.put_incref_memoryviewslice(self.result(),
                                                  not self.in_nogil_context)
  
  class ProxyNode(CoercionNode):
      """
      A node that should not be replaced by transforms or other means,
      and hence can be useful to wrap the argument to a clone node
  
      MyNode    -> ProxyNode -> ArgNode
      CloneNode -^
      """
  
      nogil_check = None
  
      def __init__(self, arg):
          super(ProxyNode, self).__init__(arg)
          self.constant_result = arg.constant_result
          self._proxy_type()
  
      def analyse_expressions(self, env):
          self.arg = self.arg.analyse_expressions(env)
          self._proxy_type()
          return self
  
      def _proxy_type(self):
          if hasattr(self.arg, 'type'):
              self.type = self.arg.type
              self.result_ctype = self.arg.result_ctype
          if hasattr(self.arg, 'entry'):
              self.entry = self.arg.entry
  
      def generate_result_code(self, code):
          self.arg.generate_result_code(code)
  
      def result(self):
          return self.arg.result()
  
      def is_simple(self):
          return self.arg.is_simple()
  
      def may_be_none(self):
          return self.arg.may_be_none()
  
      def generate_evaluation_code(self, code):
          self.arg.generate_evaluation_code(code)
  
      def generate_result_code(self, code):
          self.arg.generate_result_code(code)
  
      def generate_disposal_code(self, code):
          self.arg.generate_disposal_code(code)
  
      def free_temps(self, code):
          self.arg.free_temps(code)
  
  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
      nogil_check = None
  
      def __init__(self, arg):
          CoercionNode.__init__(self, arg)
          self.constant_result = arg.constant_result
          if hasattr(arg, 'type'):
              self.type = arg.type
              self.result_ctype = arg.result_ctype
          if hasattr(arg, 'entry'):
              self.entry = arg.entry
  
      def result(self):
          return self.arg.result()
  
      def may_be_none(self):
          return self.arg.may_be_none()
  
      def type_dependencies(self, env):
          return self.arg.type_dependencies(env)
  
      def infer_type(self, env):
          return self.arg.infer_type(env)
  
      def analyse_types(self, env):
          self.type = self.arg.type
          self.result_ctype = self.arg.result_ctype
          self.is_temp = 1
          if hasattr(self.arg, 'entry'):
              self.entry = self.arg.entry
          return self
  
      def is_simple(self):
          return True # result is always in a temp (or a name)
  
      def generate_evaluation_code(self, code):
          pass
  
      def generate_result_code(self, code):
          pass
  
      def generate_disposal_code(self, code):
          pass
  
      def free_temps(self, code):
          pass
  
  
  class CMethodSelfCloneNode(CloneNode):
      # Special CloneNode for the self argument of builtin C methods
      # that accepts subtypes of the builtin type.  This is safe only
      # for 'final' subtypes, as subtypes of the declared type may
      # override the C method.
  
      def coerce_to(self, dst_type, env):
          if dst_type.is_builtin_type and self.type.subtype_of(dst_type):
              return self
          return CloneNode.coerce_to(self, dst_type, env)
  
  
  class ModuleRefNode(ExprNode):
      # Simple returns the module object
  
      type = py_object_type
      is_temp = False
      subexprs = []
  
      def analyse_types(self, env):
          return self
  
      def may_be_none(self):
          return False
  
      def calculate_result_code(self):
          return Naming.module_cname
  
      def generate_result_code(self, code):
          pass
  
  class DocstringRefNode(ExprNode):
      # Extracts the docstring of the body element
  
      subexprs = ['body']
      type = py_object_type
      is_temp = True
  
      def __init__(self, pos, body):
          ExprNode.__init__(self, pos)
          assert body.type.is_pyobject
          self.body = body
  
      def analyse_types(self, env):
          return self
  
      def generate_result_code(self, code):
          code.putln('%s = __Pyx_GetAttr(%s, %s); %s' % (
              self.result(), self.body.result(),
              code.intern_identifier(StringEncoding.EncodedString("__doc__")),
              code.error_goto_if_null(self.result(), self.pos)))
          code.put_gotref(self.result())
  
  
  
  #------------------------------------------------------------------------------------
  #
  #  Runtime support code
  #
  #------------------------------------------------------------------------------------
  
  pyerr_occurred_withgil_utility_code= UtilityCode(
  proto = """
  static CYTHON_INLINE int __Pyx_ErrOccurredWithGIL(void); /* proto */
  """,
  impl = """
  static CYTHON_INLINE int __Pyx_ErrOccurredWithGIL(void) {
    int err;
    #ifdef WITH_THREAD
    PyGILState_STATE _save = PyGILState_Ensure();
    #endif
    err = !!PyErr_Occurred();
    #ifdef WITH_THREAD
    PyGILState_Release(_save);
    #endif
    return err;
  }
  """
  )
  
  #------------------------------------------------------------------------------------
  
  raise_unbound_local_error_utility_code = UtilityCode(
  proto = """
  static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname);
  """,
  impl = """
  static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) {
      PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname);
  }
  """)
  
  raise_closure_name_error_utility_code = UtilityCode(
  proto = """
  static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname);
  """,
  impl = """
  static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname) {
      PyErr_Format(PyExc_NameError, "free variable '%s' referenced before assignment in enclosing scope", varname);
  }
  """)
  
  # Don't inline the function, it should really never be called in production
  raise_unbound_memoryview_utility_code_nogil = UtilityCode(
  proto = """
  static void __Pyx_RaiseUnboundMemoryviewSliceNogil(const char *varname);
  """,
  impl = """
  static void __Pyx_RaiseUnboundMemoryviewSliceNogil(const char *varname) {
      #ifdef WITH_THREAD
      PyGILState_STATE gilstate = PyGILState_Ensure();
      #endif
      __Pyx_RaiseUnboundLocalError(varname);
      #ifdef WITH_THREAD
      PyGILState_Release(gilstate);
      #endif
  }
  """,
  requires = [raise_unbound_local_error_utility_code])
  
  #------------------------------------------------------------------------------------
  
  raise_too_many_values_to_unpack = UtilityCode.load_cached("RaiseTooManyValuesToUnpack", "ObjectHandling.c")
  raise_need_more_values_to_unpack = UtilityCode.load_cached("RaiseNeedMoreValuesToUnpack", "ObjectHandling.c")
  tuple_unpacking_error_code = UtilityCode.load_cached("UnpackTupleError", "ObjectHandling.c")
  
  #------------------------------------------------------------------------------------
  
  int_pow_utility_code = UtilityCode(
  proto="""
  static CYTHON_INLINE %(type)s %(func_name)s(%(type)s, %(type)s); /* proto */
  """,
  impl="""
  static CYTHON_INLINE %(type)s %(func_name)s(%(type)s b, %(type)s e) {
      %(type)s t = b;
      switch (e) {
          case 3:
              t *= b;
          case 2:
              t *= b;
          case 1:
              return t;
          case 0:
              return 1;
      }
      #if %(signed)s
      if (unlikely(e<0)) return 0;
      #endif
      t = 1;
      while (likely(e)) {
          t *= (b * (e&1)) | ((~e)&1);    /* 1 or b */
          b *= b;
          e >>= 1;
      }
      return t;
  }
  """)
  
  # ------------------------------ Division ------------------------------------
  
  div_int_utility_code = UtilityCode(
  proto="""
  static CYTHON_INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s, %(type)s); /* proto */
  """,
  impl="""
  static CYTHON_INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) {
      %(type)s q = a / b;
      %(type)s r = a - q*b;
      q -= ((r != 0) & ((r ^ b) < 0));
      return q;
  }
  """)
  
  mod_int_utility_code = UtilityCode(
  proto="""
  static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */
  """,
  impl="""
  static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) {
      %(type)s r = a %% b;
      r += ((r != 0) & ((r ^ b) < 0)) * b;
      return r;
  }
  """)
  
  mod_float_utility_code = UtilityCode(
  proto="""
  static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */
  """,
  impl="""
  static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) {
      %(type)s r = fmod%(math_h_modifier)s(a, b);
      r += ((r != 0) & ((r < 0) ^ (b < 0))) * b;
      return r;
  }
  """)
  
  cdivision_warning_utility_code = UtilityCode(
  proto="""
  static int __Pyx_cdivision_warning(const char *, int); /* proto */
  """,
  impl="""
  static int __Pyx_cdivision_warning(const char *filename, int lineno) {
  #if CYTHON_COMPILING_IN_PYPY
      filename++; // avoid compiler warnings
      lineno++;
      return PyErr_Warn(PyExc_RuntimeWarning,
                       "division with oppositely signed operands, C and Python semantics differ");
  #else
      return PyErr_WarnExplicit(PyExc_RuntimeWarning,
                                "division with oppositely signed operands, C and Python semantics differ",
                                filename,
                                lineno,
                                __Pyx_MODULE_NAME,
                                NULL);
  #endif
  }
  """)
  
  # from intobject.c
  division_overflow_test_code = UtilityCode(
  proto="""
  #define UNARY_NEG_WOULD_OVERFLOW(x)    \
          (((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x)))
  """)
  