docs: private Object evalInternal(
      Selector sel,
      MatchSpaceKey bind,
      EvalCache cache,
      Object contextValue,
      boolean permissive)
      throws BadMessageFormatMatchingException
    {
      if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
        tc.entry(cclass, "evalInternal", new Object[] { sel, bind, cache, contextValue, new Boolean(permissive) });
      
      Object theReturn = null;
      // If sel is a literal, its value is simply the literal's value
      if (sel instanceof Literal)
      {
        if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
          tc.debug(cclass, "Selector is a literal");         
        theReturn = ((Literal) sel).getValue();
        if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
          tc.exit(cclass, "evalInternal", theReturn);  
        return theReturn;
      }
  
      // If sel is an Identifier, we let the MatchSpaceKey evaluate it.  The MatchSpaceKey is
      // given explicit type information unless the evaluation mode is permissive, in which
      // case the value is retrieved regardless and the permissive casts are applied.
  
      if (sel instanceof Identifier)
      {
        if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
          tc.debug(cclass, "Selector is an Identifier");        
        Identifier id = (Identifier) sel;
        if (permissive && id.getType() != Selector.UNKNOWN)
        {
          // Result may require permissive mode casts.  First, get the value, whatever it
          // is.
          boolean returnList = true;
          if(id.getType() == Selector.BOOLEAN)
            returnList = false;
          Object idVal = 
            bind.getIdentifierValue(id,
                                    true,
                                    contextValue, 
                                    returnList); // true means return a nodelist
          if (idVal == null)
          {
            if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
              tc.exit(cclass, "evalInternal", null);            
            return null;
          }
          // Perform permissive casts
          switch (id.getType())
          {
            case Selector.NUMERIC :
              if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
                tc.debug(cclass, "Selector type is numeric");               
              if (idVal instanceof Number) // was NumericValue
              {
                if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                  tc.exit(cclass, "evalInternal", idVal);                
                return idVal;
              }
              else
              {
                if(idVal instanceof ArrayList)
                {
                  theReturn = castToNumberList((ArrayList)idVal);
                }
                else
                  theReturn = castToNumber(idVal);
                if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                  tc.exit(cclass, "evalInternal", theReturn);
                return theReturn;
              }
            case Selector.STRING :
              if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
                tc.debug(cclass, "Selector type is string");              
              if (idVal instanceof String)
              {
                if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                  tc.exit(cclass, "evalInternal", idVal);                
                return idVal;
              }
              else
              {
                if(idVal instanceof ArrayList)
                {
                  theReturn = castToStringList((ArrayList)idVal);
                }
                else
                  theReturn = idVal.toString();
                if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                  tc.exit(cclass, "evalInternal", theReturn);
                return theReturn;
              }            
            case Selector.BOOLEAN :
              if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
                tc.debug(cclass, "Selector type is boolean");              
              if (idVal instanceof Boolean) // was BooleanValue
              {
                if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                  tc.exit(cclass, "evalInternal", idVal);                
                return idVal;
              }
              else
              {
                theReturn = castToBoolean(idVal);
                if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                  tc.exit(cclass, "evalInternal", theReturn);            
                return theReturn;              
              }
            default :
              if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
                tc.debug(cclass, "Selector type is default");              
              // Normally, permissive mode evaluation would not apply to TOPIC and OBJECT
              // Identifiers.  But, in any case, there are no valid casts to those types.
              if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                tc.exit(cclass, "evalInternal", null);              
              return null;
          }
        }
        else
        {
          // not permissive, or the type is UNKNOWN so no permissive mode casts apply
          boolean returnList = true;
          if(id.getType() == Selector.BOOLEAN)
            returnList = false;
          theReturn = 
            bind.getIdentifierValue(id,
                                    false,
                                    contextValue, 
                                    returnList); // true means return a nodelist
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn);         
          return theReturn;
        }
      }
  
      // Otherwise, it's an Operator
      Operator op = (Operator) sel;
      if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
        tc.debug(cclass, "Selector is an operator");  
      // Evaluate the operands to obtain the values needed to evaluate the operator
      Object val0 = eval(op.getOperands()[0], bind, cache, contextValue, permissive); // was false
      Object val1 =
        (op.getOperands().length == 1)
          ? null
          : eval(op.getOperands()[1], bind, cache, contextValue, permissive); // was false
  
      // Evaluate according to the operator
      switch (op.getOp())
      {
        case Selector.NOT :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is NOT");         
          if (val0 instanceof Boolean) 
          {
            theReturn = not((Boolean) val0);
            if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
              tc.exit(cclass, "evalInternal", theReturn);         
            return theReturn;          
          }
          else
            if (permissive && val0 != null)
            {
              theReturn = not(castToBoolean(val0));
              if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                tc.exit(cclass, "evalInternal", theReturn);         
              return theReturn;            
            }
            else
            {
              if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                tc.exit(cclass, "evalInternal", null);              
              return null; 
            }
        case Selector.NEG :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is NEG");         
          if (!(val0 instanceof Number)) // was NumericValue
            if (permissive && val0 != null)
            {
              val0 = castToNumber(val0);
              if (val0 == null)
              {
                if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                  tc.exit(cclass, "evalInternal", null);               
                return null;
              }
            }
            else
            {
              if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                tc.exit(cclass, "evalInternal", null);             
              return null;
            }
          // val0 is now definitely a Number
          return neg((Number)val0);
        case Selector.ISNULL :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type ISNULL");
          theReturn = Boolean.valueOf(val0 == null);
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn);         
          return theReturn;         
        case Selector.LIKE :
        case Selector.TOPIC_LIKE:
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is LIKE");        
          if (!(val0 instanceof String))
            if (permissive && val0 != null)
              val0 = val0.toString();
            else
            {
              if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
                tc.exit(cclass, "evalInternal", null);              
              return null;
            }
          // val0 is a String
          theReturn = Boolean.valueOf(((LikeOperatorImpl) op)
              .getInternalPattern().match((String) val0));
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn);           
          return theReturn;
        case Selector.NE :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is NE");          
          if(val0 instanceof ArrayList)
            theReturn = compareList((ArrayList)val0, val1, false, permissive, false);
          else
            theReturn = not(compare(val0, val1, false, permissive));
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn);           
          return theReturn;        
        case Selector.EQ :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is EQ");          
          if(val0 instanceof ArrayList)
            theReturn = compareList((ArrayList)val0, val1, false, permissive, true);
          else        
            theReturn = compare(val0, val1, false, permissive);
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn); 
          return theReturn;
        case Selector.GT :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is GT");          
          if(val0 instanceof ArrayList)
            theReturn = compareList((ArrayList)val0, val1, false, permissive, true);
          else              
            theReturn = compare(val1, val0, true, permissive);
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn); 
          return theReturn;        
        case Selector.LT :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is LT");          
          if(val0 instanceof ArrayList)
            theReturn = compareList((ArrayList)val0, val1, false, permissive, true);
          else              
            theReturn = compare(val0, val1, true, permissive);
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn); 
          return theReturn;         
        case Selector.GE :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is GE");          
          if(val0 instanceof ArrayList)
            theReturn = compareList((ArrayList)val0, val1, false, permissive, false);
          else              
            theReturn = not(compare(val0, val1, true, permissive));
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn); 
          return theReturn;          
        case Selector.LE :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is LE");          
          if(val0 instanceof ArrayList)
            theReturn = compareList((ArrayList)val0, val1, false, permissive, false);
          else              
            theReturn = not(compare(val1, val0, true, permissive));
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn); 
          return theReturn;          
        case Selector.PLUS :
        case Selector.MINUS :
        case Selector.TIMES :
        case Selector.DIV :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is ARITHMETIC");          
          theReturn = promoteAndEvaluate(op.getOp(), val0, val1, permissive);
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn);         
          return theReturn;
        case Selector.AND :
        case Selector.OR :
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is ANDOR");          
          if (!(val0 instanceof Boolean)) // was BooleanValue
            if (permissive && val0 != null)
              val0 = castToBoolean(val0);
          if (!(val1 instanceof Boolean)) // was BooleanValue
            if (permissive && val1 != null)
              val1 = castToBoolean(val1);
          if (op.getOp() == Operator.AND)
            theReturn = and((Boolean) val0, (Boolean) val1);
          else
            theReturn = or((Boolean) val0, (Boolean) val1);
          if (tc.isAnyTracingEnabled() && tc.isEntryEnabled())
            tc.exit(cclass, "evalInternal", theReturn);         
          return theReturn;        
        default :
          // Should not occur
          if (tc.isAnyTracingEnabled() && tc.isDebugEnabled())
            tc.debug(cclass, "Selector type is DEFAULT");          
          throw new IllegalStateException();
      }
    }