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

Module: Slicer for symex traces

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

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

#include <hash_cont.h>

#include "slice.h"

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

   Class: symex_slicet

 Purpose:

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

class symex_slicet
{
public:
  void slice(symex_target_equationt &equation);

protected:
  typedef hash_set_cont<irep_idt, irep_id_hash> symbol_sett;
  
  symbol_sett depends;
  
  void get_symbols(const exprt &expr);
  void get_symbols(const typet &type);

  void slice(symex_target_equationt::statet &state);
  void slice_assignment(symex_target_equationt::statet &state);
};

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

Function: symex_slicet::get_symbols

  Inputs:

 Outputs:

 Purpose:

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

void symex_slicet::get_symbols(const exprt &expr)
{
  get_symbols(expr.type());

  forall_operands(it, expr)
    get_symbols(*it);

  if(expr.id()=="symbol")
    depends.insert(expr.get("identifier"));
}

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

Function: symex_slicet::get_symbols

  Inputs:

 Outputs:

 Purpose:

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

void symex_slicet::get_symbols(const typet &type)
{
}

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

Function: symex_slicet::slice

  Inputs:

 Outputs:

 Purpose:

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

void symex_slicet::slice(symex_target_equationt &equation)
{
  depends.clear();

  for(symex_target_equationt::statest::reverse_iterator
      it=equation.states.rbegin();
      it!=equation.states.rend();
      it++)
    slice(*it);
}

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

Function: symex_slicet::slice

  Inputs:

 Outputs:

 Purpose:

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

void symex_slicet::slice(symex_target_equationt::statet &state)
{
  get_symbols(state.guard);

  switch(state.type)
  {
  case goto_trace_stept::ASSERT:
    get_symbols(state.cond);
    break;

  case goto_trace_stept::ASSUME:
    get_symbols(state.cond);
    break;

  case goto_trace_stept::LOCATION:
    // ignore
    break;

  case goto_trace_stept::ASSIGNMENT:
    slice_assignment(state);
    break;

  case goto_trace_stept::OUTPUT:
    break;

  default:
    assert(false);  
  }
}

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

Function: symex_slicet::slice_assignment

  Inputs:

 Outputs:

 Purpose:

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

void symex_slicet::slice_assignment(
  symex_target_equationt::statet &state)
{
  assert(state.lhs.id()=="symbol");

  if(depends.find(state.lhs.get("identifier"))==
     depends.end())
  {
    // we don't really need it
    state.ignore=true;
  }
  else
    get_symbols(state.rhs);
}

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

Function: slice

  Inputs:

 Outputs:

 Purpose:

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

void slice(symex_target_equationt &equation)
{
  symex_slicet symex_slice;
  symex_slice.slice(equation);
}

