text: #     Copyright 2019, Kay Hayen, mailto:kay.hayen@gmail.com
  #
  #     Part of "Nuitka", an optimizing Python compiler that is compatible and
  #     integrates with CPython, but also works on its own.
  #
  #     Licensed under the Apache License, Version 2.0 (the "License");
  #     you may not use this file except in compliance with the License.
  #     You may obtain a copy of the License at
  #
  #        http://www.apache.org/licenses/LICENSE-2.0
  #
  #     Unless required by applicable law or agreed to in writing, software
  #     distributed under the License is distributed on an "AS IS" BASIS,
  #     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  #     See the License for the specific language governing permissions and
  #     limitations under the License.
  #
  """ Node for constant expressions. Can be all common built-in types.
  
  """
  
  from logging import warning
  
  from nuitka.__past__ import (  # pylint: disable=I0021,redefined-builtin
      iterItems,
      long,
      unicode,
      xrange,
  )
  from nuitka.Builtins import (
      builtin_anon_values,
      builtin_exception_values_list,
      builtin_named_values,
  )
  from nuitka.Constants import (
      getConstantIterationLength,
      getUnhashableConstant,
      isConstant,
      isHashable,
      isIndexConstant,
      isIterableConstant,
      isMutable,
      isNumberConstant,
  )
  from nuitka.Options import isDebug
  
  from .ExpressionBases import CompileTimeConstantExpressionBase
  from .IterationHandles import (
      ConstantIndexableIterationHandle,
      ConstantSetAndDictIterationHandle,
  )
  from .NodeMakingHelpers import (
      getComputationResult,
      makeRaiseExceptionReplacementExpression,
      wrapExpressionWithSideEffects,
  )
  from .shapes.BuiltinTypeShapes import (
      ShapeTypeBool,
      ShapeTypeBytearray,
      ShapeTypeBytes,
      ShapeTypeDict,
      ShapeTypeEllipsisType,
      ShapeTypeFloat,
      ShapeTypeFrozenset,
      ShapeTypeInt,
      ShapeTypeList,
      ShapeTypeLong,
      ShapeTypeNoneType,
      ShapeTypeSet,
      ShapeTypeSlice,
      ShapeTypeStr,
      ShapeTypeTuple,
      ShapeTypeType,
      ShapeTypeUnicode,
      ShapeTypeXrange,
  )
  
  
  class ExpressionConstantRefBase(CompileTimeConstantExpressionBase):
      __slots__ = "constant", "user_provided"
  
      def __init__(self, constant, source_ref, user_provided=False):
          CompileTimeConstantExpressionBase.__init__(self, source_ref=source_ref)
  
          assert isConstant(constant), repr(constant)
  
          self.constant = constant
  
          # Memory saving method, have the attribute only where necessary.
          self.user_provided = user_provided
  
          if not user_provided and isDebug():
              try:
                  if type(constant) in (str, unicode, bytes):
                      max_size = 1000
                  elif type(constant) is xrange:
                      max_size = None
                  else:
                      max_size = 256
  
                  if max_size is not None and len(constant) > max_size:
                      warning(
                          "Too large constant (%s %d) encountered at %s.",
                          type(constant),
                          len(constant),
                          source_ref.getAsString(),
                      )
              except TypeError:
                  pass
  
      def finalize(self):
          del self.parent
          del self.constant
  
      def __repr__(self):
          return "<Node %s value %r at %s %s>" % (
              self.kind,
              self.constant,
              self.source_ref.getAsString(),
              self.user_provided,
          )
  
      def getDetails(self):
          return {"constant": self.constant, "user_provided": self.user_provided}
  
      def getDetailsForDisplay(self):
          result = self.getDetails()
  
          if "constant" in result:
              result["constant"] = repr(result["constant"])
  
          return result
  
      @staticmethod
      def isExpressionConstantRef():
          return True
  
      def computeExpressionRaw(self, trace_collection):
          # Cannot compute any further, this is already the best.
          return self, None, None
  
      def computeExpressionCall(self, call_node, call_args, call_kw, trace_collection):
  
          # The arguments don't matter. All constant values cannot be called, and
          # we just need to make and error out of that.
          new_node = wrapExpressionWithSideEffects(
              new_node=makeRaiseExceptionReplacementExpression(
                  expression=self,
                  exception_type="TypeError",
                  exception_value="'%s' object is not callable"
                  % type(self.constant).__name__,
              ),
              old_node=call_node,
              side_effects=call_node.extractSideEffectsPreCall(),
          )
  
          trace_collection.onExceptionRaiseExit(TypeError)
  
          return (
              new_node,
              "new_raise",
              "Predicted call of constant value to exception raise.",
          )
  
      def getCompileTimeConstant(self):
          return self.constant
  
      getConstant = getCompileTimeConstant
  
      def getIterationHandle(self):
          if self.isIterableConstant():
              return ConstantIndexableIterationHandle(self)
          else:
              return None
  
      def isMutable(self):
          return isMutable(self.constant)
  
      def isKnownToBeHashable(self):
          return isHashable(self.constant)
  
      def extractUnhashableNode(self):
          value = getUnhashableConstant(self.constant)
  
          if value is not None:
              return makeConstantRefNode(constant=value, source_ref=self.source_ref)
  
      def isNumberConstant(self):
          return isNumberConstant(self.constant)
  
      def isIndexConstant(self):
          return isIndexConstant(self.constant)
  
      def isIndexable(self):
          return self.constant is None or self.isNumberConstant()
  
      def isKnownToBeIterable(self, count):
          if isIterableConstant(self.constant):
              return count is None or getConstantIterationLength(self.constant) == count
          else:
              return False
  
      def isKnownToBeIterableAtMin(self, count):
          length = self.getIterationLength()
  
          return length is not None and length >= count
  
      def canPredictIterationValues(self):
          return self.isKnownToBeIterable(None)
  
      def getIterationValue(self, count):
          assert count < len(self.constant)
  
          return makeConstantRefNode(
              constant=self.constant[count], source_ref=self.source_ref
          )
  
      def getIterationValueRange(self, start, stop):
          return [
              makeConstantRefNode(constant=value, source_ref=self.source_ref)
              for value in self.constant[start:stop]
          ]
  
      def getIterationValues(self):
          source_ref = self.getSourceReference()
  
          return tuple(
              makeConstantRefNode(
                  constant=value, source_ref=source_ref, user_provided=self.user_provided
              )
              for value in self.constant
          )
  
      def isMapping(self):
          return type(self.constant) is dict
  
      def isMappingWithConstantStringKeys(self):
          assert self.isMapping()
  
          for key in self.constant:
              if type(key) not in (str, unicode):
                  return False
          return True
  
      def getMappingPairs(self):
          assert self.isMapping()
  
          pairs = []
  
          source_ref = self.getSourceReference()
  
          for key, value in iterItems(self.constant):
              pairs.append(
                  makeConstantRefNode(constant=key, source_ref=source_ref),
                  makeConstantRefNode(constant=value, source_ref=source_ref),
              )
  
          return pairs
  
      def getMappingStringKeyPairs(self):
          assert self.isMapping()
  
          pairs = []
  
          source_ref = self.getSourceReference()
  
          for key, value in iterItems(self.constant):
              pairs.append(
                  (key, makeConstantRefNode(constant=value, source_ref=source_ref))
              )
  
          return pairs
  
      @staticmethod
      def isBoolConstant():
          return False
  
      def mayHaveSideEffects(self):
          # Constants have no side effects
          return False
  
      def extractSideEffects(self):
          # Constants have no side effects
          return ()
  
      def getIntegerValue(self):
          if self.isNumberConstant():
              return int(self.constant)
          else:
              return None
  
      def getIndexValue(self):
          if self.isIndexConstant():
              return int(self.constant)
          else:
              return None
  
      def getStringValue(self):
          if self.isStringConstant():
              return self.constant
          else:
              return None
  
      def getIterationLength(self):
          if isIterableConstant(self.constant):
              return getConstantIterationLength(self.constant)
          else:
              return None
  
      def isIterableConstant(self):
          return isIterableConstant(self.constant)
  
      def isUnicodeConstant(self):
          return type(self.constant) is unicode
  
      def isStringConstant(self):
          return type(self.constant) is str
  
      def getStrValue(self):
          if type(self.constant) is str:
              # Nothing to do.
              return self
          else:
              try:
                  return makeConstantRefNode(
                      constant=str(self.constant),
                      user_provided=self.user_provided,
                      source_ref=self.getSourceReference(),
                  )
              except UnicodeEncodeError:
                  # Unicode constants may not be possible to encode.
                  return None
  
      def computeExpressionIter1(self, iter_node, trace_collection):
          constant_type = type(self.constant)
  
          if constant_type in (list, set, frozenset, dict):
              result = makeConstantRefNode(
                  constant=tuple(self.constant),
                  user_provided=self.user_provided,
                  source_ref=self.getSourceReference(),
              )
  
              self.parent.replaceChild(self, result)
              self.finalize()
  
              return (
                  iter_node,
                  "new_constant",
                  """\
  Iteration over constant %s changed to tuple."""
                  % constant_type.__name__,
              )
  
          if not isIterableConstant(self.constant):
              # An exception may be raised.
              trace_collection.onExceptionRaiseExit(TypeError)
  
              return getComputationResult(
                  node=iter_node,
                  computation=lambda: iter_node.simulator(self.constant),
                  description="Iteration of non-iterable constant.",
              )
  
          return iter_node, None, None
  
  
  class ExpressionConstantNoneRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_NONE_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=None, user_provided=user_provided, source_ref=source_ref
          )
  
      def getDetails(self):
          return {}
  
      def getTypeShape(self):
          return ShapeTypeNoneType
  
  
  class ExpressionConstantBoolRefBase(ExpressionConstantRefBase):
      @staticmethod
      def isBoolConstant():
          return True
  
      def computeExpressionBool(self, trace_collection):
          # Best case already.
          pass
  
      def getDetails(self):
          return {}
  
      def getTypeShape(self):
          return ShapeTypeBool
  
  
  class ExpressionConstantTrueRef(ExpressionConstantBoolRefBase):
      kind = "EXPRESSION_CONSTANT_TRUE_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, user_provided=False):
          ExpressionConstantBoolRefBase.__init__(
              self, constant=True, user_provided=user_provided, source_ref=source_ref
          )
  
  
  class ExpressionConstantFalseRef(ExpressionConstantBoolRefBase):
      kind = "EXPRESSION_CONSTANT_FALSE_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, user_provided=False):
          ExpressionConstantBoolRefBase.__init__(
              self, constant=False, user_provided=user_provided, source_ref=source_ref
          )
  
  
  class ExpressionConstantEllipsisRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_ELLIPSIS_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=Ellipsis, user_provided=user_provided, source_ref=source_ref
          )
  
      def getDetails(self):
          return {}
  
      def getTypeShape(self):
          return ShapeTypeEllipsisType
  
  
  class ExpressionConstantDictRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_DICT_REF"
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantDictRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeDict
  
      def hasShapeDictionaryExact(self):
          return True
  
      def getIterationHandle(self):
          return ConstantSetAndDictIterationHandle(self)
  
  
  class ExpressionConstantTupleRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_TUPLE_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantTupleRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeTuple
  
  
  the_empty_tuple = ()
  
  
  class ExpressionConstantTupleEmptyRef(ExpressionConstantTupleRef):
      kind = "EXPRESSION_CONSTANT_TUPLE_EMPTY_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, user_provided=False):
          ExpressionConstantTupleRef.__init__(
              self,
              constant=the_empty_tuple,
              user_provided=user_provided,
              source_ref=source_ref,
          )
  
      def getDetails(self):
          return {}
  
  
  class ExpressionConstantListRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_LIST_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantListRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeList
  
  
  the_empty_list = []
  
  
  class ExpressionConstantListEmptyRef(ExpressionConstantListRef):
      kind = "EXPRESSION_CONSTANT_LIST_EMPTY_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, user_provided=False):
          ExpressionConstantListRef.__init__(
              self,
              constant=the_empty_list,
              user_provided=user_provided,
              source_ref=source_ref,
          )
  
      def getDetails(self):
          return {}
  
  
  class ExpressionConstantSetRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_SET_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantSetRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeSet
  
      def getIterationHandle(self):
          return ConstantSetAndDictIterationHandle(self)
  
  
  the_empty_set = set()
  
  
  class ExpressionConstantSetEmptyRef(ExpressionConstantSetRef):
      kind = "EXPRESSION_CONSTANT_SET_EMPTY_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, user_provided=False):
          ExpressionConstantSetRef.__init__(
              self,
              constant=the_empty_set,
              user_provided=user_provided,
              source_ref=source_ref,
          )
  
      def getDetails(self):
          return {}
  
  
  class ExpressionConstantFrozensetRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_FROZENSET_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantFrozensetRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeFrozenset
  
  
  the_empty_frozenset = frozenset()
  
  
  class ExpressionConstantFrozensetEmptyRef(ExpressionConstantFrozensetRef):
      kind = "EXPRESSION_CONSTANT_FROZENSET_EMPTY_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, user_provided=False):
          ExpressionConstantFrozensetRef.__init__(
              self,
              constant=the_empty_frozenset,
              user_provided=user_provided,
              source_ref=source_ref,
          )
  
      def getDetails(self):
          return {}
  
  
  class ExpressionConstantIntRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_INT_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantIntRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeInt
  
  
  class ExpressionConstantLongRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_LONG_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantLongRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeLong
  
  
  class ExpressionConstantStrRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_STR_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantStrRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeStr
  
  
  class ExpressionConstantUnicodeRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_UNICODE_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantUnicodeRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeUnicode
  
  
  class ExpressionConstantBytesRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_BYTES_REF"
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantBytesRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeBytes
  
  
  class ExpressionConstantBytearrayRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_BYTEARRAY_REF"
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantBytearrayRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeBytearray
  
  
  class ExpressionConstantFloatRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_FLOAT_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantFloatRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeFloat
  
  
  class ExpressionConstantComplexRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_COMPLEX_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantComplexRef():
          return True
  
  
  class ExpressionConstantSliceRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_SLICE_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantSliceRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeSlice
  
  
  class ExpressionConstantXrangeRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_XRANGE_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantXrangeRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeXrange
  
  
  class ExpressionConstantTypeRef(ExpressionConstantRefBase):
      kind = "EXPRESSION_CONSTANT_TYPE_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, constant, user_provided=False):
          ExpressionConstantRefBase.__init__(
              self, constant=constant, user_provided=user_provided, source_ref=source_ref
          )
  
      @staticmethod
      def isExpressionConstantTypeRef():
          return True
  
      def getTypeShape(self):
          return ShapeTypeType
  
      def computeExpressionCall(self, call_node, call_args, call_kw, trace_collection):
          from nuitka.optimizations.OptimizeBuiltinCalls import computeBuiltinCall
  
          # Anything may happen. On next pass, if replaced, we might be better
          # but not now.
          trace_collection.onExceptionRaiseExit(BaseException)
  
          new_node, tags, message = computeBuiltinCall(
              builtin_name=self.constant.__name__, call_node=call_node
          )
  
          return new_node, tags, message
  
  
  the_empty_dict = {}
  
  
  class ExpressionConstantDictEmptyRef(ExpressionConstantDictRef):
      kind = "EXPRESSION_CONSTANT_DICT_EMPTY_REF"
  
      __slots__ = ()
  
      def __init__(self, source_ref, user_provided=False):
          ExpressionConstantDictRef.__init__(
              self,
              constant=the_empty_dict,
              user_provided=user_provided,
              source_ref=source_ref,
          )
  
      def getDetails(self):
          return {}
  
  
  def makeConstantRefNode(constant, source_ref, user_provided=False):
      # This is dispatching per constant value and types, every case
      # to be a return statement, pylint: disable=too-many-branches,too-many-return-statements
  
      # Dispatch based on constants first.
      if constant is None:
          return ExpressionConstantNoneRef(
              source_ref=source_ref, user_provided=user_provided
          )
      elif constant is True:
          return ExpressionConstantTrueRef(
              source_ref=source_ref, user_provided=user_provided
          )
      elif constant is False:
          return ExpressionConstantFalseRef(
              source_ref=source_ref, user_provided=user_provided
          )
      elif constant is Ellipsis:
          return ExpressionConstantEllipsisRef(
              source_ref=source_ref, user_provided=user_provided
          )
      else:
          # Next, dispatch based on type.
          constant_type = type(constant)
  
          if constant_type is int:
              return ExpressionConstantIntRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant_type is str:
              return ExpressionConstantStrRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant_type is float:
              return ExpressionConstantFloatRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant_type is long:
              return ExpressionConstantLongRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant_type is unicode:
              return ExpressionConstantUnicodeRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant_type is bytes:
              return ExpressionConstantBytesRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant_type is dict:
              if constant:
                  return ExpressionConstantDictRef(
                      source_ref=source_ref,
                      constant=constant,
                      user_provided=user_provided,
                  )
              else:
                  return ExpressionConstantDictEmptyRef(
                      source_ref=source_ref, user_provided=user_provided
                  )
          elif constant_type is tuple:
              if constant:
                  return ExpressionConstantTupleRef(
                      source_ref=source_ref,
                      constant=constant,
                      user_provided=user_provided,
                  )
              else:
                  return ExpressionConstantTupleEmptyRef(
                      source_ref=source_ref, user_provided=user_provided
                  )
          elif constant_type is list:
              if constant:
                  return ExpressionConstantListRef(
                      source_ref=source_ref,
                      constant=constant,
                      user_provided=user_provided,
                  )
              else:
                  return ExpressionConstantListEmptyRef(
                      source_ref=source_ref, user_provided=user_provided
                  )
          elif constant_type is set:
              if constant:
                  return ExpressionConstantSetRef(
                      source_ref=source_ref,
                      constant=constant,
                      user_provided=user_provided,
                  )
              else:
                  return ExpressionConstantSetEmptyRef(
                      source_ref=source_ref, user_provided=user_provided
                  )
          elif constant_type is frozenset:
              if constant:
                  return ExpressionConstantFrozensetRef(
                      source_ref=source_ref,
                      constant=constant,
                      user_provided=user_provided,
                  )
              else:
                  return ExpressionConstantFrozensetEmptyRef(
                      source_ref=source_ref, user_provided=user_provided
                  )
          elif constant_type is complex:
              return ExpressionConstantComplexRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant_type is slice:
              return ExpressionConstantSliceRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant_type is type:
              return ExpressionConstantTypeRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant_type is xrange:
              return ExpressionConstantXrangeRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant_type is bytearray:
              return ExpressionConstantBytearrayRef(
                  source_ref=source_ref, constant=constant, user_provided=user_provided
              )
          elif constant in builtin_anon_values:
              from .BuiltinRefNodes import ExpressionBuiltinAnonymousRef
  
              return ExpressionBuiltinAnonymousRef(
                  source_ref=source_ref, builtin_name=builtin_anon_values[constant]
              )
          elif constant in builtin_named_values:
              from .BuiltinRefNodes import ExpressionBuiltinRef
  
              return ExpressionBuiltinRef(
                  builtin_name=builtin_named_values[constant], source_ref=source_ref
              )
          elif constant in builtin_exception_values_list:
              from .BuiltinRefNodes import ExpressionBuiltinExceptionRef
  
              if constant is NotImplemented:
                  exception_name = "NotImplemented"
              else:
                  exception_name = constant.__name__
  
              return ExpressionBuiltinExceptionRef(
                  exception_name=exception_name, source_ref=source_ref
              )
          else:
              # Missing constant type, ought to not happen, please report.
              assert False, (constant, constant_type)
  