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

// The code weaver allows AspectC++ specific code manipulation transactions.
// All access to the syntax tree nodes for the transformation is 
// encapsulated here.
// The class does not know about class JoinPoint. It only knows join point
// locations (JPL_*).

#include <iostream>
using namespace std;

#include "PointCut.h" // Oh no, it knows JoinPoint
#include "WeaverBase.h"
#include "AspectIncludes.h"
#include "SliceIncludes.h"

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

namespace Puma {
  class CTree;
  class ACAspectInfo;
  class CClassInfo;
  class CProject;
} // namespace Puma

class AspectInfo;
class AdviceInfo;
class IntroductionInfo;
class JoinPointLoc;
class JPL_Class;
class JPP_Class;
class JPP_Code;
class JPL_Method;
class JPL_MethodCall;
class JPAdvice;
class ThisJoinPoint;

class CodeWeaver : public WeaverBase
 {
      JPP_Code *_code_plan;
      AspectIncludes _aspect_includes;
      SliceIncludes _slice_includes;

      void make_check_function (bool in_checked,
                                CRecord *in, CRecord *check_for);
      void provide_typename (CTree *node);
      void make_proceed_code (ostream &out, JoinPointLoc *loc, bool action,
                               int max_depth);
      void make_advice_call(ostream &out, JoinPointLoc *loc, AdviceInfo *ad,
                            bool inter, int depth);
      void make_advice_calls (ostream &out, JPAdvice *jpa,
                              JoinPointLoc *loc, bool inter = false);
      void make_action_wrapper(ostream &impl, JoinPointLoc *jpl,
                               JPAdvice *jpa);
      void make_proceed_func(ostream &impl, JoinPointLoc *loc, JPAdvice *jpa);
      bool check_special_member_function (CFunctionInfo *func);
      void gen_special_member_function (JoinPointLoc *loc, JPP_Code &plan);
      void wrap_function (JPL_Code *loc, JPP_Code &plan);
      void wrap_function_def (JPL_Code *loc, CFunctionInfo *func,
        bool wrapped_decl);
      bool wrap_function_decl (JPL_Code *loc, CFunctionInfo *func);
      void wrap_attribute_arrays (CT_MembList *members);
      void gen_wrapped_array (ostream &out, CObjectInfo *obj);

   public:

      CodeWeaver (ErrorSink& e, LineDirectiveMgr &ldm) :
        WeaverBase (e, ldm) {}

      void insert_namespace_ac_before (Token *inspos);
      void to_class (ACAspectInfo *ai);
      void invocation_functions (ACAspectInfo *ai, Token *first,
                                 const string &decls, const string &defs);
      void declare_friends (CClassInfo *cls, list<CClassInfo*> &friends);
      void open_namespace (ostream &out, CClassInfo *obj);
      void close_namespace (ostream &out, CClassInfo *obj);
      void provide_tjp (CFunctionInfo *func, ThisJoinPoint &tjp);
      void declare_function (CFunctionInfo *advice_func, CTree *advice_decl);
      void make_tjp_struct(ostream &out, JoinPointLoc *loc, JPAdvice *jpa);
      void make_tjp_common_init(ostream &code, JoinPointLoc *loc, JPAdvice *jpa);
      void introduce (JPL_Class *loc, CTree *decl, CProtection::Type prot,
                      Token *primary_end);
      void baseclass (JPL_Class &loc, JPP_Class &plan);
/*       void inherited (JPL_Class *loc, IntroductionInfo *intro); */
      void singleton (ACAspectInfo *ai);
      void make_result_type (ostream &out, CTypeInfo *type, bool reference);
      void make_result_declaration(ostream &out, CTypeInfo *type);
      void make_result_assignment(ostream &out, CTypeInfo *type);
      void make_action_result_assignment(ostream &out, CTypeInfo *type);
      void make_result_return(ostream &out, CTypeInfo *type);
      void exec_join_point (JPL_Method *loc, JPP_Code &plan);
      void call_join_point (JPL_MethodCall *loc, JPP_Code &plan);
      void cons_join_point (JPL_Construction *loc, JPP_Code &plan);
      void dest_join_point (JPL_Destruction *loc, JPP_Code &plan);
      void add_intro_include (JPL_Class *jpl, IntroductionInfo *ii);
      void add_aspect_include (JoinPointLoc *jpl, AspectInfo *ai,
                               ACAspectInfo *acai, AspectRef::Kind kind);
      void aspect_includes (CProject &project, Token *first);
      void slice_includes (CProject &project, Token *first);
      void type_check (CRecord *in, const string &name, bool result);
 };

#endif // __CodeWeaver_h__
