// 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 __WeaverBase_h__
#define __WeaverBase_h__

// This class encapsulates all code manipulation or analysis functions
// that are needed by AspectC++, but which do not depend on AspectC++
// specific classes. They can be seen as a general purpose PUMA extension.

#include <iostream>
#include <set>
using namespace std;

#include "Puma/ManipCommander.h"
#include "Puma/CProtection.h"
using namespace Puma;

#include "ACUnit.h"
#include "BackEndProblems.h"

namespace Puma {
  class ErrorSink;
  class CObjectInfo;
  class CFunctionInfo;
  class CArgumentInfo;
  class CClassInfo;
  class CTree;
} // namespace Puma

class WeaverBase;
class LineDirectiveMgr;

class WeavePos {
public:
  enum Pos { WP_BEFORE, WP_AFTER };
  int operator < (const WeavePos& key) const {
    return _token == key._token ?
      (_pos < key._pos) : (_token < key._token);
  }
private:
  friend class WeaverBase;
  WeavePos (Token *t, Pos p) : _token (t), _pos (p) {}
  Token *_token;
  Pos _pos;
};

class WeaverBase {

  // These data structures are needed to store and find weaving positions that
  // were already used. Some of them are stored separately, because they are
  // relevant for the insertion of #line directives
  typedef set<WeavePos> WPSet;
  WPSet _positions;
  typedef set<WeavePos*> WPPtrSet;
  WPPtrSet _line_done;
  WPPtrSet _line_todo;
  ManipCommander _commander;
  
protected:
  ErrorSink &_err;
  LineDirectiveMgr &_line_mgr;
  BackEndProblems _problems;      

  // not a very good function
  void print_tree (ostream &out, CTree *node);

  // checks whether a function needs a 'this'-pointer
  bool needs_this (CFunctionInfo *func);
  
  // scope functions
  CClassInfo *cscope (CObjectInfo *obj);
  CScopeInfo *nscope (CObjectInfo *obj);
  
  void rename_args (CFunctionInfo *func, const char * new_name);
  void rename (CArgumentInfo *arg, const string &new_name, int app = -1);
  void rename_simple_name (CObjectInfo *renamed_obj,
                           const char *new_name, int app,
                           CTree *node);
  CT_SimpleName *is_name (CTree *node);
  CT_FctDeclarator *fct_declarator (CT_Declarator *declarator);
  CT_SimpleName *name (CT_Declarator *&declarator);

  // return LinkageSpec node for extern "C" <decl> like declarations
  CTree *linkage_adjust (CT_Decl *decl);
  
public:
  WeaverBase (ErrorSink &e, LineDirectiveMgr &ldm) :
    _err (e), _line_mgr (ldm) {}

  // get the associate line directive manager
  LineDirectiveMgr &line_directive_mgr () const { return _line_mgr; }
  
  // set weaver parameters
  void problems (const BackEndProblems &problems) { _problems = problems; }
  
  // helper functions (could be regarded as Puma extensions)
  
  // returns "\nprivate:\n", ...
  static string protection_string (CProtection::Type prot);

  // code manipulation layer:
  
  // get a weaving position
  const WeavePos &weave_pos (Token *t, WeavePos::Pos p);
  
  // check/ignore manipulations for unbalanced preprocessor directives
  void ignore_unbalanced () { _commander.ignore_mask (MIM_UNBALANCED); }
  void check_unbalanced () { _commander.ignore_mask (MIM_NONE); }
   
  // insert the contents of a generated unit at a given position (with move)
  void paste (const WeavePos &pos, Unit *unit);

  // insert a generated string a given position
  void paste (const WeavePos &pos, const string &str);
  
  // replace the text between two positions with some new text
  void replace (const WeavePos &from, const WeavePos &to, const string &str);
  
  // replace the text of a syntax tree with some new text
  void replace (CTree *node, const string &str);

  // copy the text between two position to another location
  void copy (const WeavePos &from, const WeavePos &to, const WeavePos &dest);
  
  // copy the text of a syntax tree to another location
  void copy (CTree *node, const WeavePos &dest);
  
  // kill the text between two positions
  void kill (const WeavePos &from, const WeavePos &to);
  
  // kill the text of a syntax tree
  void kill (CTree *node);

  // commit a transformation transaction  
  bool commit ();
  
  // check if there is a problem
  bool macro_problem (const WeavePos &pos);
  
};

#endif // __WeaverBase_h__
