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

#include <vector>
#include <string>

class ACM_Arg;

// This class assigns arguments of advice code to context information
// from the join points. For example:
// advice args(a1) && that(a2) : before (int a1, C &a2) {}
// -> a1 is assigned to the first argument of each matched joinpoint
// -> a2 is assigned to the 'this' pointer of each matched joinpoint
// All bindings of a pointcut must be compatible.

// Internal data representation is a simple vector. The first three
// elements are used for the 'result', 'target', and 'that' argument
// pointers. The remaining elements are used for a variable number of
// 'args' argument pointers.
// Public enumerators (Binding::THAT, ...) are used to identify the
// binding that should be stored or retrieved. They are negatived numbers
// so that arguments can have numbers 0..N.

class Binding : private std::vector<ACM_Arg*> {
public:
  // Enumerators to identify the binding
  enum {
    THAT = -1, TARGET = -2, RESULT = -3, NOT_FOUND = -4,
    ARG0 = 0, ARG1 = 1, ARG2 = 2    // and so on.
  };

  Binding () {
    reset ();
  }

  // store a binding
  void bind(int what, ACM_Arg *val);

  // check if a binding is stored
  bool has(int what) const;

  // get a store binding
  ACM_Arg *get(int what) const;

  // check whether any argument binding has been stored
  bool has_args() const { return size() > _fixed; }

  // check whether two bindings are compatible
  bool is_compatible_with (const Binding &other) const;

  // check whether this object has already been used to store a binding
  bool is_used () const { return _used; }

  // find out what an argument is bound to
  int find (ACM_Arg*) const;

  // was a ternary operator (?:) matched by args(x,y,z)?
  // This is a problem, because short-circuit evaluation will never 
  // provide three arguments.
  bool problem_sc_arg_no_match() const { return _problem_sc_arg_no_match; }

  // was a an operator with short-circuit evaluation matched by args(...)
  // so that a condition had to be created?
  bool problem_sc_arg_used() const { return _problem_sc_arg_used; }

  // setter functions for the aforementionen problems
  void set_problem_sc_arg_no_match() { _problem_sc_arg_no_match = true; }
  void set_problem_sc_arg_used() { _problem_sc_arg_used = true; }

  // analyze short-circuit argument problems for a given operator,
  // set flags accordingly, and return the following number:
  // For built-in operators with short-circuit evavluation (||, &&, ?:)
  // return the number of the potentially unevaluated argument (1 or 2);
  // 0 means that there is not short-circuit argument, i.e. no problem
  // -1 means that the joinpoint cannot be matched.
  int short_circuit_arg(const std::string &operator_name); 

private:
  static constexpr int _fixed = 3; // correct this if you change the enum
  bool _used;
  bool _problem_sc_arg_no_match;
  bool _problem_sc_arg_used;

  // turn the object back to its initial (unused) state
  void reset ();
};

#endif // __Binding_h__
