Working on Lisp-Like Parser Functions

Today I've been hard at work filling in the parser I'm creating with the obvious collection of functions that any script is going to need. Things like add, subtract, multiply, divide... plus the more advanced math calculations - they all need to be done, but what makes this all slow going is the fact that to do this right, we need to implement these features in the variant class first, and then use them in the parser. In fact, using them in the parser is the easy part. It's getting them all in the variant class in the first place.

The reason it's slow going is that it's not enough to make a simple inequality set:

  bool operator==( variant & anOther ) const;
  bool operator==( const variant & anOther ) const;
  bool operator!=( variant & anOther ) const;
  bool operator!=( const variant & anOther ) const;

we're going to need the complete compliment of inequalities:

  bool operator==( variant & anOther ) const;
  bool operator==( const variant & anOther ) const;
  bool operator!=( variant & anOther ) const;
  bool operator!=( const variant & anOther ) const;
  bool operator<( variant & anOther ) const;
  bool operator<( const variant & anOther ) const;
  bool operator<=( variant & anOther ) const;
  bool operator<=( const variant & anOther ) const;
  bool operator>( variant & anOther ) const;
  bool operator>( const variant & anOther ) const;
  bool operator>=( variant & anOther ) const;
  bool operator>=( const variant & anOther ) const;

For the most part, this isn't too terribly hard, but you have to remember that I've got more than a dozen different types of values to check in a variant, and then there's the real work - all the convenience methods.

To make it easy to write:

  variant    v(25.0);
  if (v < 12) {
    ...
  }

I need to have a lot more operators as well. If I look at just the equality operator, I end up with something more like this:

  bool operator==( variant & anOther ) const;
  bool operator==( const variant & anOther ) const;
  bool operator==( varmap & anOther ) const;
  bool operator==( const varmap & anOther ) const;
  bool operator==( varlist & anOther ) const;
  bool operator==( const varlist & anOther ) const;
  bool operator==( uint8_t aValue ) const;
  bool operator==( int aValue ) const;
  bool operator==( int64_t aValue ) const;
  bool operator==( uint64_t aValue ) const;
  bool operator==( float aValue ) const;
  bool operator==( double aValue ) const;
  bool operator==( bool aValue ) const;
  bool operator==( std::string & aValue ) const;
  bool operator==( const std::string & aValue ) const;
  bool operator==( char *aValue ) const;
  bool operator==( const char *aValue ) const;
  bool operator==( uuid_t & aValue ) const;
  bool operator==( const uuid_t & aValue ) const;
  bool operator==( secID_t & aValue ) const;
  bool operator==( const secID_t & aValue ) const;
  bool operator==( error_t & aValue ) const;
  bool operator==( const error_t & aValue ) const;

So even if we are as clever as can be, this is a ton of code to write, and test. It's just brutal at times to make sure you haven't made any typos in the code.

I will say that I was very pleased with the one simplification I made. It's pretty easy to see that you can write the inequalities in terms of one another. However, that can take a while, and you might not end up with valid inequalities. For example, when you have two lists - which one is greater than the other? It's not easy.

My solution was to implement the:

  bool operator>=(...) const;
  bool operator<=(...) const;

methods, and then define the others in terms of them:

  bool variant::operator<(...) const
  {
    return !this->operator>=(...);
  }

So that I could be assured of at least having the "equality" in the code. Then, the others are logical combinations of these. It's not perfect, but it saves time and code, and it's a lot less headache than trying to implement a greater than on a list.