// This file is part of the AspectC++ compiler 'ac++'.
// Copyright (C) 1999-2003  The 'ac++' developers (see aspectc.org)
//                                                                
// This program is free software;  you can redistribute it and/or 
// modify it under the terms of the GNU General Public License as 
// published by the Free Software Foundation; either version 2 of 
// the License, or (at your option) any later version.            
//                                                                
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
// GNU General Public License for more details.                   
//                                                                
// You should have received a copy of the GNU General Public      
// License along with this program; if not, write to the Free     
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
// MA  02111-1307  USA                                            

#ifndef __MatchTemplateArg_h__
#define __MatchTemplateArg_h__

#include <list>
using std::list;

namespace Puma {
  class CTemplateInstance;
  class DeducedArgument;
}

#include "MatchType.h"

// Common interface for all class that represent match expressions
// for template arguments.

class MatchTemplateArg {
public:
  virtual ~MatchTemplateArg () {}
  virtual void print (ostream &out) const = 0;
  virtual bool matches (DeducedArgument *arg) const = 0;
  virtual MatchTemplateArg *clone () const = 0;
  virtual bool is_ellipses () const { return false; }
};

// streamed output for template argument match expressions
inline ostream &operator << (ostream &out, const MatchTemplateArg &mta) {
  mta.print (out);
  return out;
}


// A list of template argument match expressions
class MatchTemplateArgList : private list <MatchTemplateArg*> {
public:
  MatchTemplateArgList () {}
  ~MatchTemplateArgList () {
    for (iterator iter = begin (); iter != end (); ++iter)
      delete *iter;
  }
  MatchTemplateArgList (const MatchTemplateArgList& mtal) { *this = mtal; }
  MatchTemplateArgList &operator = (const MatchTemplateArgList& mtal) {
    for (const_iterator iter = mtal.begin (); iter != mtal.end (); ++iter)
      append ((*iter)->clone ());
    return *this;
  } 
  void append (MatchTemplateArg *mta) { push_back (mta); }
  void print (ostream &out) const {
    out << "<";
    bool first = true;
    for (const_iterator iter = begin (); iter != end (); ++iter) {
      if (first)
        first = false;
      else
        out << ",";
      out << **iter;
    }
    out << ">";
  }
  bool matches (CTemplateInstance *instance) const;
};

inline ostream &operator << (ostream &out, MatchTemplateArgList &mtal) {
  mtal.print (out);
  return out;
}


// Template argument match expression that matches any template argument
class MTA_Any : public MatchTemplateArg {
public:
  void print (ostream &out) const { out << "%"; }
  bool matches (DeducedArgument *arg) const { return true; }
  MTA_Any *clone () const { return new MTA_Any (*this); }
};


// Template argument match expression that matches any number of
// arbitrary template argument
class MTA_Ellipses : public MatchTemplateArg {
public:
  void print (ostream &out) const { out << "..."; }
  // TODO: not correct
  bool matches (DeducedArgument *arg) const { return true; }
  MTA_Ellipses *clone () const { return new MTA_Ellipses (*this); }
  bool is_ellipses () const { return true; }
};


// This class represents match expressions for types in template
// argument lists.
class MTA_Type : public MatchTemplateArg {
  MatchTypeRef _match_type;
public:
  MTA_Type (const MatchTypeRef mt) : _match_type (mt) {}
  void print (ostream &out) const { out << _match_type; }
  bool matches (DeducedArgument *arg) const;
  MTA_Type *clone () const { return new MTA_Type (*this); }
};


// This class represents match expressions for value template arguments.
class MTA_Value : public MatchTemplateArg {
  long long _val;
public:
  MTA_Value (long long val) : _val (val) {}
  void print (ostream &out) const { out << _val; }
  bool matches (DeducedArgument *arg) const;
  MTA_Value *clone () const { return new MTA_Value (*this); }
};

#endif // __MatchTemplateArg_h__
