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

#include <ostream>
#include <string>
using std::ostream;
using std::string;
using std::endl;
using std::ends;
#include <map>
using std::map;
#include <vector>
using std::vector;

#include "Puma/Signature.h"
#include "Puma/DString.h"
#include "Puma/CRecord.h"
#include "Puma/CAttributeInfo.h"
#include "Puma/CClassInfo.h"
#include "Puma/ACAspectInfo.h"
#include "Puma/CFunctionInfo.h"
#include "Puma/CTree.h"
#include "Puma/Filter.h"
using namespace Puma;

#include "MatchName.h"

namespace Puma {
  class CTypeInfo;
  class Unit;
} // namespace Puma

class JoinPointPlan;

class JoinPointLoc {

public:
  enum join_point_type {
    None            = 0x0000,
    FieldReference  = 0x0001,
    FieldAssignment = 0x0002,
    MethodCall      = 0x0004,
    Method          = 0x0008,
    Construction    = 0x0010,
    Destruction     = 0x0020,
    Code            = 0x003f,
    Class           = 0x0100,
    Aspect          = 0x0200,
    Function        = 0x0400,
    Type            = 0x0800,
    Name            = 0x0f00,
    Any             = 0x0f3f
  };

protected:
  
  string _sig;            // the signature of this jp as a string
  int _lid;               // local id for this jp inside the current function
  JoinPointPlan *_plan;   // the weaving plan for advised jps
  int _id;                // a unique id for each joinpoint location

  void signature (ostream &, CFunctionInfo *func_info);
  void signature (ostream &, CAttributeInfo *func_info);
  void signature (ostream &, CTypeInfo *type_info);
  
 public:

  JoinPointLoc () : _lid (0), _plan (0), _id (-1) {}
  virtual ~JoinPointLoc () {}

  const char *signature () { return _sig.c_str (); }
  int lid () const { return _lid; }
  JoinPointPlan *plan () const { return _plan; }
  void plan (JoinPointPlan *p) { _plan = p; }
  int line () const;
  int lines () const;
  Unit *unit () const;
  int id () const { return _id; }
  void id (int new_id) { _id = new_id; }

  virtual join_point_type type () { return None; }
  virtual const char *type_str () const { return (const char*)0; }
  virtual CTree *tree () const { return 0; }
  virtual CObjectInfo *assoc_obj () { return 0; }
  virtual Token *insertloc_tjp_struct() { return 0; }
  virtual Token *insertloc_before () { return 0; }
  virtual Token *insertloc_after () { return 0; }
  virtual CFunctionInfo *tjp_type() {return 0;}
  virtual CFunctionInfo *tjp_target() {return 0;}
  virtual CFunctionInfo *tjp_that() {return 0;}
  virtual CFunctionInfo *action_dst_func() {return 0;}
  virtual CFunctionInfo *action_src_func() {return 0;}
};

class JPL_Name : public JoinPointLoc {

  CTypeInfo *_ctype;
protected:    
  JPL_Name (CTypeInfo *t) : _ctype (t) {}
  virtual ~JPL_Name () {}
  
public:
  CTypeInfo *type_info () const { return _ctype; }
  virtual CObjectInfo *obj_info () = 0;
};

class JPL_Class : public JPL_Name {
  CClassInfo *class_obj;
  CObjectInfo *link_once_object (CClassInfo *);
  
public:
  JPL_Class (CClassInfo *c);
  CClassInfo *class_info () { return class_obj; }
  virtual CObjectInfo *obj_info () { return class_obj; }
  join_point_type type () { return Class; }
  virtual const char *type_str () const { return "class"; }
  virtual CTree *tree () const;
  // find a member that is/must be link-once (global) code
  CObjectInfo *link_once_object () { return link_once_object (class_obj); }
};

class JPL_Aspect : public JPL_Class {
  ACAspectInfo *aspect_obj;
public:
  JPL_Aspect (ACAspectInfo *a) : JPL_Class (a->ClassInfo ()), aspect_obj (a) {}
  ACAspectInfo *aspect_info () const { return aspect_obj; }
  virtual join_point_type type () { return Aspect; }
  virtual const char *type_str () const { return "aspect"; }
};

class JPL_Function : public JPL_Name {
  CFunctionInfo *func_obj;
public:
  JPL_Function (CFunctionInfo *f);
  CFunctionInfo *func_info () { return func_obj; }
  virtual CObjectInfo *obj_info () { return func_obj; }
  join_point_type type () { return Function; }
  virtual const char *type_str () const { return "function"; }
  virtual CTree *tree () const;
};

class JPL_Type : public JPL_Name {
public:
  JPL_Type (CTypeInfo *t);
  virtual CObjectInfo *obj_info () { return 0; }
  join_point_type type () { return Type; }
  virtual const char *type_str () const { return "type"; }
  virtual CTree *tree () const;
};


class JPL_Code : public JoinPointLoc {
  vector<JPL_Type *> _arg_types;
  JPL_Type *_result_type;
public:
  JPL_Code () : _result_type (0) {}
  ~JPL_Code ();

  virtual bool is_pseudo () const { return false; }
  
  // argument handling
  int arg_count () const {
    return (int)_arg_types.size ();
  }
  const JPL_Type &arg_type (int i) const {
    assert (i >= 0 && i < arg_count ());
    return *_arg_types[i]; 
  }
  void add_arg_type (CTypeInfo *ctype) {
    _arg_types.push_back (new JPL_Type (ctype));
  }
  
  // manage the result type
  void result_type (CTypeInfo *ctype) { _result_type = new JPL_Type (ctype); }
  const JPL_Type &result_type () const { return *_result_type; }
  
  // That and Target types for the JoinPoint-API
  virtual CTypeInfo *that_type () = 0;
  virtual CTypeInfo *target_type () const = 0;
  
  // helper functions for derived class
  CTypeInfo *get_that_type (CObjectInfo *obj);
  
  // generates the signature of a wrapper function for exec/cons/dest join pts
  string wrapper_function_signature (CFunctionInfo *func, bool def);
  
  // interface needed to generate proper proceed code
  virtual bool proceed_needs_args () const {
    return arg_count () > 0;
  }
  virtual bool proceed_needs_result () const {
    return _result_type && !_result_type->type_info ()->is_void ();
  }
  virtual bool proceed_needs_target () const { return false; }
  virtual bool proceed_needs_that () const { return false; }
  virtual bool proceed_needs_fptr () const { return false; }
  
  // helper function: check if a function is a method (needs a 'this' pointer)
  static bool needs_this (CFunctionInfo *func) {
    if (func->isMethod () && !func->isStaticMethod ()) {
      return !(func->isOperator () &&
        (strcmp (func->Name (), "operator new") == 0 ||
         strcmp (func->Name (), "operator new[]") == 0 ||
         strcmp (func->Name (), "operator delete") == 0 ||
         strcmp (func->Name (), "operator delete[]") == 0));
    }
    return false;
  }
};

class JPL_Method : public JPL_Code
 {
      CFunctionInfo *_func_info;

   public:

      JPL_Method (CFunctionInfo *f);

      join_point_type type () { return Method; }
      virtual const char *type_str () const { return "exec"; }
      virtual CTree *tree () const;
      virtual CTypeInfo *target_type () const;
      virtual CTypeInfo *that_type ();
      CFunctionInfo *func_info () { return _func_info; }
      virtual CObjectInfo *assoc_obj () { return _func_info; }
      virtual Token *insertloc_tjp_struct();
      virtual Token *insertloc_before () { return _func_info->Tree ()->token (); }
      virtual Token *insertloc_after () { return _func_info->Tree ()->end_token (); }
      CFunctionInfo *tjp_type() {return _func_info;}
      CFunctionInfo *tjp_target() {return _func_info;}
      CFunctionInfo *tjp_that() {return _func_info;}
      CFunctionInfo *action_dst_func() {return _func_info;}
      CFunctionInfo *action_src_func() {return _func_info;}
      virtual bool proceed_needs_that () const {
        return needs_this (_func_info);
      }
 };

class JPL_MethodCall : public JPL_Code
 {
      CFunctionInfo *called_func;
      CObjectInfo *caller_obj;
      CT_CallExpr *node;
      bool _member_init;

   public:

      JPL_MethodCall (CFunctionInfo *called, CT_CallExpr *ce,
		      CObjectInfo *caller, int local_id, bool mi);

      virtual bool is_pseudo () const { return !caller_obj; }
      CFunctionInfo *caller () { 
        return caller_obj ? caller_obj->FunctionInfo () : 0;
      }
      CFunctionInfo *called () const { return called_func; }
      bool in_member_init () const { return _member_init; }

      const char *type_called() { return _sig.c_str (); }
      
      // the call expression node in the syntax tree
      CT_CallExpr *CallExprNode() const { return node;}
      
      // the target object of the call or NULL
      CT_Expression *target_expr (bool &is_ptr) const;
      
      // checks if the original call uses a qualified target function name
      bool is_qualified () const;
      
      // returns true if the call needs special access rights
      bool needs_rights () const;
      
      join_point_type type () { return MethodCall; }
      virtual const char *type_str () const { return "call"; }
      virtual CTree *tree () const;
      virtual CTypeInfo *that_type ();
      virtual CTypeInfo *target_type () const;
      virtual CObjectInfo *assoc_obj () { return caller_obj; }
      virtual Token *insertloc_tjp_struct();
      virtual Token *insertloc_before ();
      virtual Token *insertloc_after ();
      CFunctionInfo *tjp_type() { return called_func;}
      CFunctionInfo *tjp_target() { return called_func;}
      CFunctionInfo *tjp_that() { return caller_obj->FunctionInfo ();}
      CFunctionInfo *action_dst_func() {return called_func;}
      CFunctionInfo *action_src_func() {return caller_obj->FunctionInfo ();}

      virtual bool proceed_needs_target () const {
        return needs_this (called_func);
      }
      virtual bool proceed_needs_fptr () const {
        return needs_rights ();
      }
 };

class JPL_FieldReference : public JPL_Code
 {
      CAttributeInfo *attr;
      CTree *field;
      
   public:

      JPL_FieldReference (CAttributeInfo *a, CTree *f, int local_id);
      join_point_type type () { return FieldReference; }
      virtual const char *type_str () const { return "get"; }
      virtual CTree *tree () const;
      virtual CTypeInfo *that_type ();
      virtual CTypeInfo *target_type () const;
 };

class JPL_FieldAssignment : public JPL_Code
 {
      CAttributeInfo *attr;
      CT_CallExpr *assignment;
      CTree *field;
      
   public:

      JPL_FieldAssignment (CAttributeInfo *a, CT_CallExpr *as,
			   CTree *f, int local_id);
      join_point_type type () { return FieldAssignment; }
      virtual const char *type_str () const { return "set"; }
      virtual CTree *tree () const;
      virtual CTypeInfo *that_type ();
      virtual CTypeInfo *target_type () const;
 };

class JPL_Construction : public JPL_Code
 {
      CFunctionInfo *_func_info;

   public:

      JPL_Construction (CFunctionInfo *f);

      join_point_type type () { return Construction; }
      virtual const char *type_str () const { return "construction"; }
      virtual CTree *tree () const;
      virtual CTypeInfo *that_type ();
      virtual CTypeInfo *target_type () const;
      CFunctionInfo *func_info () { return _func_info; }
      virtual CObjectInfo *assoc_obj () { return _func_info; }
      virtual Token *insertloc_tjp_struct();
      virtual Token *insertloc_before () { return _func_info->Tree ()->token (); }
      virtual Token *insertloc_after () { return _func_info->Tree ()->end_token (); }
      CFunctionInfo *tjp_type() {return _func_info;}
      CFunctionInfo *tjp_target() {return _func_info;}
      CFunctionInfo *tjp_that() {return _func_info;}
      CFunctionInfo *action_dst_func() {return _func_info;}
      CFunctionInfo *action_src_func() {return _func_info;}
      virtual bool proceed_needs_that () const { return true; }
 };

class JPL_Destruction : public JPL_Code
 {
      CFunctionInfo *_func_info;

   public:

      JPL_Destruction (CFunctionInfo *f);

      join_point_type type () { return Destruction; }
      virtual const char *type_str () const { return "destruction"; }
      virtual CTree *tree () const;
      virtual CTypeInfo *that_type ();
      virtual CTypeInfo *target_type () const;
      CFunctionInfo *func_info () { return _func_info; }
      virtual CObjectInfo *assoc_obj () { return _func_info; }
      virtual Token *insertloc_tjp_struct();
      virtual Token *insertloc_before () { return _func_info->Tree ()->token (); }
      virtual Token *insertloc_after () { return _func_info->Tree ()->end_token (); }
      CFunctionInfo *tjp_type() {return _func_info;}
      CFunctionInfo *tjp_target() {return _func_info;}
      CFunctionInfo *tjp_that() {return _func_info;}
      CFunctionInfo *action_dst_func() {return _func_info;}
      CFunctionInfo *action_src_func() {return _func_info;}
      virtual bool proceed_needs_that () const { return true; }
 };

#endif // __join_point_loc_h__
