/*******************************************************************\

Module: Generate Equation using Symbolic Execution

Author: Daniel Kroening, kroening@cs.cmu.edu

\*******************************************************************/

#ifndef CPROVER_BASIC_SYMEX_EQUATION_H
#define CPROVER_BASIC_SYMEX_EQUATION_H

#include <list>
#include <map>

#include <namespace.h>

#include <goto-programs/goto_program.h>
#include <propdec/prop_conv.h>

#include "symex_target.h"
#include "goto_trace.h"

class symex_target_equationt:public symex_targett
{
public:
  symex_target_equationt(const namespacet &_ns):ns(_ns) { }

  // assignment to a variable - must be symbol
  // the value is destroyed
  virtual void assignment(
    const guardt &guard,
    const exprt &lhs,
    const exprt &original_lhs,
    exprt &rhs,
    const sourcet &source,
    assignment_typet assignment_type);
    
  // just record a location
  virtual void location(
    const guardt &guard,
    const sourcet &source);
  
  // output
  virtual void output(
    const guardt &guard,
    const sourcet &source,
    const std::list<exprt> &args);
  
  // record an assumption
  // cond is destroyed
  virtual void assumption(
    const guardt &guard,
    exprt &cond,
    const sourcet &source);

  // record an assertion
  // cond is destroyed
  virtual void assertion(
    const guardt &guard,
    exprt &cond,
    const std::string &msg,
    const sourcet &source);

  void convert(prop_convt &prop_conv);
  void convert_assignments(decision_proceduret &decision_procedure) const;
  void convert_assumptions(prop_convt &prop_conv);
  void convert_assertions(prop_convt &prop_conv);
  void convert_guards(prop_convt &prop_conv);
  
  class statet
  {
  public:
    unsigned thread_nr;
    goto_programt::const_targett pc;
    
    void set_source(const sourcet &source)
    {
      thread_nr=source.thread_nr;
      pc=source.pc;
    }

    goto_trace_stept::typet type;
    
    bool is_assert() const     { return type==goto_trace_stept::ASSERT; }
    bool is_assume() const     { return type==goto_trace_stept::ASSUME; }
    bool is_assignment() const { return type==goto_trace_stept::ASSIGNMENT; }
    bool is_location() const   { return type==goto_trace_stept::LOCATION; }
    bool is_output() const     { return type==goto_trace_stept::OUTPUT; }
    
    exprt guard;

    // for ASSIGNMENT  
    exprt lhs, rhs, original_lhs;
    assignment_typet assignment_type;
    
    // for ASSUME/ASSERT
    exprt cond; 
    std::string comment;

    // for OUTPUT
    std::list<exprt> output_args;

    // for conversion
    literalt guard_literal, cond_literal;
    
    // for slicing
    bool ignore;
    
    statet():thread_nr(0), pc(NULL),
      guard((const exprt &)nil_rep),
      cond((const exprt &)nil_rep),
      ignore(false)
    {
    }
    
    void output(
      const namespacet &ns,
      std::ostream &out) const;
  };
  
  unsigned count_ignored_states() const
  {
    unsigned i=0;
    for(statest::const_iterator
        it=states.begin();
        it!=states.end(); it++)
      if(it->ignore) i++;
    return i;
  }

  typedef std::list<statet> statest;
  statest states;
  
  friend bool operator<(
    const statest::const_iterator a,
    const statest::const_iterator b)
  {
    return &(*a)<&(*b);
  }
  
  statest::iterator get_state(unsigned s)
  {
    statest::iterator it=states.begin();
    for(; s!=0; s--)
    {
      assert(it!=states.end());
      it++;
    }
    return it;
  }

  void output(std::ostream &out) const;
  
  void clear()
  {
    states.clear();
  }
  
protected:
  const namespacet &ns;
};

std::ostream &operator<<(std::ostream &out, const symex_target_equationt::statet &state);
std::ostream &operator<<(std::ostream &out, const symex_target_equationt &equation);

#endif
