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

#include "Puma/DString.h"
#include "Puma/Array.h"
#include "Puma/Filter.h"
using namespace Puma;

#include "Condition.h"
#include "PointCut.h"
#include "MatchExpr.h"

class PointCutContext;
class JoinPointLoc;
class Binding;

namespace Puma {
  class CClassInfo;
  class CFunctionInfo;
  class CArgumentInfo;
  class CTypeInfo;
  class ErrorStream;
  class CTree;
} // namespace Puma

// Pointcut expression types are evaluated in a context-independant manner.
// For every pointcut expression a type can always be determined.
enum PCE_Type { 
  PCE_NAME, // NAME represents a name pointcut
  PCE_CODE // CODE represents a code pointcut
};


class PointCutExpr {

  CTree *_node;

protected:

  // do a semantic analysis of the child nodes
  void sem_args (ErrorStream &err, PointCutContext &context);

  // check if the argument pointcut types are as expected
  void check_arg_types (ErrorStream &err, const char *func, PCE_Type expected);

  // check if all argument types are equal
  void check_arg_types_equal (ErrorStream &err, const char *func);

  // get the real argument binding of a context variable
  const CArgumentInfo *get_binding (const char *name, ErrorStream &err, 
				    PointCutContext &context);
public:

  PointCutExpr () : _node (0) {}
  virtual ~PointCutExpr () {}

  // set and get the corresponding syntax tree and expression child nodes
  void node (CTree *node) { _node = node; }
  CTree *node () const { return _node; }
  virtual int args () const = 0;
  virtual PointCutExpr *arg (int) const = 0;

  // Return the type of pointcut described by this expression. This function
  // does not check any argument types etc. -> semantics!
  virtual PCE_Type type () const = 0;

  // run a semantic analysis (e.g. check types)
  virtual void semantics (ErrorStream &err, PointCutContext &context) = 0;

  // evaluate an expression, i.e. check if the expression evaluates as 'true'
  // for a particular join point
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond) = 0;
                         
  // mangle a string that represents a type check (for that/target arguments)                         
  virtual void mangle_type_check (ostream &) = 0;                         
};

class PCE_SingleArg : public PointCutExpr {
  PointCutExpr *_arg;
public:
  PCE_SingleArg (PointCutExpr *arg) : _arg (arg) {}
  virtual int args () const { return 1; }
  virtual PointCutExpr *arg (int i) const { return (i == 0) ? _arg : 0; }
  bool check_derived (CClassInfo *cls, CFunctionInfo *func, 
		      PointCutContext &context, Binding &binding, Condition &cond);
  bool check_base (CClassInfo *cls, CFunctionInfo *func, 
		   PointCutContext &context, Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << 1;
    _arg->mangle_type_check (out);
  }
};

class PCE_DoubleArg : public PointCutExpr {
  PointCutExpr *_args[2];
public:
  PCE_DoubleArg (PointCutExpr *arg0, PointCutExpr *arg1) {
    _args[0] = arg0; _args[1] = arg1; 
  }
  virtual int args () const { return 2; }
  virtual PointCutExpr *arg (int i) const { 
    return (i >= 0 && i < 2) ? _args[i] : 0; 
  }
  virtual void mangle_type_check (ostream &out) {
    out << 2;
    _args[0]->mangle_type_check (out);
    _args[1]->mangle_type_check (out);
  }
};

class PCE_VarArgs : public PointCutExpr {
  Array<PointCutExpr*> _args;
public:
  virtual ~PCE_VarArgs () {}
  void add_arg (PointCutExpr *arg) { _args.append (arg); }
  virtual int args () const { return _args.length (); }
  virtual PointCutExpr *arg (int i) const { return _args.lookup (i); }
  virtual void mangle_type_check (ostream &out) {
    out << args ();
    for (int i = 0; i < args (); i++)
      arg (i)->mangle_type_check (out);
  }
};

class PCE_Classes : public PCE_SingleArg {
public:
  PCE_Classes (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "classes_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Base : public PCE_SingleArg {
public:
  PCE_Base (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "base_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Derived : public PCE_SingleArg {
public:
  PCE_Derived (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "derived_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Within : public PCE_SingleArg {
public:
  PCE_Within (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "within_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Execution : public PCE_SingleArg {
public:
  PCE_Execution (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "execution_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Call : public PCE_SingleArg {
public:
  PCE_Call (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "call_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Construction : public PCE_SingleArg {
public:
  PCE_Construction (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "construction_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Destruction : public PCE_SingleArg {
public:
  PCE_Destruction (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "destruction_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_That : public PCE_SingleArg {
public:
  PCE_That (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "that_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Target : public PCE_SingleArg {
public:
  PCE_Target (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "target_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_CFlow : public PCE_SingleArg {
  int _index;
  PointCut _arg_pointcut;
public:
  PCE_CFlow (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual ~PCE_CFlow () {}
  virtual PCE_Type type () const;
  PointCut &arg_pointcut () { return _arg_pointcut; }
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "cflow_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Args : public PCE_VarArgs {
public:
  virtual ~PCE_Args () {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "args_";
    PCE_VarArgs::mangle_type_check (out);
  }
};

class PCE_Result : public PCE_SingleArg {
public:
  PCE_Result (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "result_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Or : public PCE_DoubleArg {
public:
  PCE_Or (PointCutExpr *arg0, PointCutExpr *arg1) : 
    PCE_DoubleArg (arg0, arg1) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "or_";
    PCE_DoubleArg::mangle_type_check (out);
  }
};

class PCE_And : public PCE_DoubleArg {
public:
  PCE_And (PointCutExpr *arg0, PointCutExpr *arg1) : 
    PCE_DoubleArg (arg0, arg1) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "and_";
    PCE_DoubleArg::mangle_type_check (out);
  }
};

class PCE_Not : public PCE_SingleArg {
public:
  PCE_Not (PointCutExpr *arg) : PCE_SingleArg (arg) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "not_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_Named : public PCE_SingleArg {
  CFunctionInfo *_func;
public:
  PCE_Named (CFunctionInfo *func, PointCutExpr *expr) : 
    PCE_SingleArg (expr), _func (func) {}
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out) {
    out << "named_";
    PCE_SingleArg::mangle_type_check (out);
  }
};

class PCE_ContextVar : public PointCutExpr {
  const char *_name;
  const CArgumentInfo *_bound_arg;
  const CTypeInfo *_check_type;
  enum { CV_THAT, CV_TARGET, CV_ARG, CV_RESULT } _bound_to;
  int _arg;
public:
  PCE_ContextVar (const char *name) : _name (name) {}
  virtual int args () const { return 0; }
  virtual PointCutExpr *arg (int) const { return 0; }
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out);
};

class PCE_Match : public PointCutExpr {
  MatchExpr _match_expr;
  Filter _filter;
  DString _dstr;
public:
  PCE_Match (const char *str) : _filter (str), _dstr (str) {}
  virtual ~PCE_Match () {}
  virtual int args () const { return 0; }
  virtual PointCutExpr *arg (int) const { return 0; }
  virtual PCE_Type type () const;
  virtual void semantics (ErrorStream &err, PointCutContext &context);
  virtual bool evaluate (JoinPointLoc &jpl, PointCutContext &context,
                         Binding &binding, Condition &cond);
  virtual void mangle_type_check (ostream &out);
};

#endif // __PointCutExpr_h__
