//=-- VarTable.h - Data structures used for variable tables ------------------=
//
//  The file contains definitions for data structures used when manipulating
//  variable tables.  Each variable may have a value that is either a String,
//  or a list.  Each element of the lists may (recursively) be either lists or
//  strings, etc...
//
//=---------------------------------------------------------------------------=
//  This file is copyright (c) 1997-2000 Chris Lattner
//=---------------------------------------------------------------------------=

#ifndef VARTABLE_H
#define VARTABLE_H

class VTExp;
class CSString;
template <class Key, class Value> class Table;

typedef Table <CSString,VTExp*> VarTable;
template <class C> class LinkedList;

//=---------------------------------------------------------------------------=
//   VTExp class and subclasses...
//=---------------------------------------------------------------------------=

class MSAPI VTExp {
public :
  enum ExpTypeEnum {   // ExpTypeEnum, valid values returned from GetExpType()
    StringTy,          // Exp is a string, cast to VTStrExp
    ListTy,            // Exp is a list, cast to a VTListExp
    FunctionTy,        // Exp is a partially evaluated function (VTFunctionExp)
    InternalTy         // Exp node is for internal use, call Evaluate.
  };

  inline VTExp(int lineNo, ExpTypeEnum expType) { 
    LineNo = lineNo; ExpType = expType; 
    RefCount = 1;
  }

  // AddRef - Increase the reference count on this node...
  //
  VTExp *AddRef() {
    RefCount++;
    return this;
  }

  // UnRef - Decrement reference count on this node, delete if unused now
  void UnRef() {
    if (--RefCount == 0)
      delete this;
  }

  // Evaluate is used to cannonicalise an expression down to just StrExp and 
  // ListExp nodes, removing all InternalTy nodes...
  //
  virtual VTExp *Evaluate(VarTable &Vars, int *Lint = 0) = 0;

  // Figure out the line number that this expression comes from, or -1 if it 
  // was created.
  //
  inline int GetLineNo() const { return LineNo; }

  // GetExpType - Return the type of the expression node... This will return a 
  // member of the ExpTypeEnum, above.
  //
  inline ExpTypeEnum GetExpType() const { return ExpType; }

  // GetStringValue - Return the value of the expression as a string, if it is
  // a string expression, else as an empty string to signify an error...
  //
  inline virtual String GetStringValue() const { return ""; }

  // Print - Recursively print out this expression...
  virtual void Print(ostream &strm) const;

  // Helper functions that are generally useful
  static int IsTrue(const VTExp *Val);
  inline static int IsFalse(const VTExp *Val) { return !IsTrue(Val); }

private :
  int LineNo;
  ExpTypeEnum ExpType;
  int RefCount;

protected :
  // Protected destructor, should only be called by UnRef() member function...
  virtual ~VTExp() {
    if (RefCount != 0) 
      cout << "Error, VTExp destroyed with refcount = " << RefCount << endl;
  }
};


//=---------------------------------------------------------------------------=
//   VTStrExp class: String Primitive
//=---------------------------------------------------------------------------=

class MSAPI VTStrExp : public VTExp {
public :
  VTStrExp(int lineNo, const char *Str) 
          : VTExp(lineNo, StringTy), StrValue(Str) {}
  VTStrExp(int lineNo, const String &Str) 
          : VTExp(lineNo, StringTy), StrValue(Str) {}

  VTExp *Evaluate(VarTable &, int * = 0) {
    return this->AddRef();
  }

  inline virtual String GetStringValue() const { return StrValue; }
  inline const String &GetValue() const { return StrValue; }

private :
  String StrValue;
};


//=---------------------------------------------------------------------------=
//   VTListExp class: List Primitive
//=---------------------------------------------------------------------------=

class MSAPI VTListExp : public VTExp {
public :
  VTListExp(int LineNo);
  virtual ~VTListExp(); 

  // "Evaluate"ing the list means essentially to evaluate its arguments...
  //
  VTExp *Evaluate(VarTable &Vars, int *Lint = 0);

  // GetListElement - Return a numbered element of the expression list, or 0
  // if the index is invalid.
  //
  VTExp *GetListElement(int i) const;

  // RemoveElement - Remove an element from the list, unrefing the object along
  // the way.
  //
  void RemoveElement(unsigned i);

  // AddToTail - Append an element to the end of the list...
  void AddToTail(VTExp *Val);

  // GetNumElements - Return the number of elements in the list...
  //
  int GetNumElements() const;

  LinkedList<VTExp*> &GetList() { return TheList; }
  const LinkedList<VTExp*> &GetList() const { return TheList; }


  // GetStringValue - Return the value of the expression as a string, if it
  // is a string expression, else as an empty string to signify an error...
  //
  virtual String GetStringValue() const;

private :
  LinkedList<VTExp*> &TheList;
};


inline ostream& operator<<(ostream& strm, const VTExp *E) {
  if (E)
    E->Print(strm);
  else
    strm << "(null VTExp)";

  return strm;
}


//=---------------------------------------------------------------------------=
//   VTFunctionExp class: Function Primitive
//=---------------------------------------------------------------------------=

struct FuncRec;

class MSAPI VTFunctionExp : public VTExp {
public :
  VTFunctionExp(int lineNo, const FuncRec *funcInfo, VTListExp *params) 
       : VTExp(lineNo, FunctionTy) {
    FuncInfo = funcInfo;
    Params = params;
  }
 
  virtual VTExp *Evaluate(VarTable &Vars, int *Lint = 0);

  virtual String GetStringValue() const;

  // GetNumArgs - Get the number of arguments this (possibly) partially
  // evaluated function need before it can really run...
  //
  int GetNumArgs();

  // EvaluateWith - Apply some more parameters to this partially evaluated
  // function.  If the number is too many then a string is returned 
  // indicating the error condition.  If the number of parameters is 
  // < GetNumArgs() then a VTFunctionExp is returned.  If the number of
  // parameters is just right, then the function is executed.
  //
  VTExp *EvaluateWith(VTListExp *Params, VarTable &Vars, int *Lint = 0);

private :
  const FuncRec *FuncInfo;
  VTListExp *Params;
};

#endif
