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

Module: Symbolic Execution

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

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

#include <assert.h>

#include <expr_util.h>
#include <rename.h>

#include "goto_symex.h"

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

Function: goto_symext::new_name

  Inputs:

 Outputs:

 Purpose:

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

void goto_symext::new_name(symbolt &symbol)
{
  get_new_name(symbol, ns);
  new_context.add(symbol);
}

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

Function: goto_symext::claim

  Inputs:

 Outputs:

 Purpose:

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

void goto_symext::claim(
  exprt &expr,
  const std::string &msg,
  statet &state)
{
  total_claims++;

  state.rename(expr);
  
  // first try simplifier on it
  if(!expr.is_false())
    do_simplify(expr);

  if(expr.is_true() &&
     !options.get_bool_option("all-assertions"))
    return;
    
  state.guard.guard_expr(expr);
  
  remaining_claims++;
  target.assertion(state.guard, expr, msg, state.source);
}

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

Function: goto_symext::symex_start

  Inputs:

 Outputs:

 Purpose:

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

void goto_symext::symex_start(
  const goto_functionst &goto_functions,
  const goto_programt &goto_program)
{
  statet state;

  for(state.source.pc=
      goto_program.instructions.begin();
      state.source.pc!=goto_program.instructions.end();
      )
    symex(goto_functions, state);
}

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

Function: goto_symext::symex

  Inputs:

 Outputs:

 Purpose:

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

void goto_symext::symex(
  const goto_functionst &goto_functions,
  statet &state)
{
  merge_gotos(state);
  
  const goto_programt::instructiont &instruction=*state.source.pc;

  if(state.guard.is_false())
  {
    if(instruction.is_goto())
    {
      // reset unwinding
      unwind_map[state.source]=0;
    }

    state.source.pc++;
    return; // nothing to do
  }
  
  // actually do instruction

  switch(instruction.type)
  {
  case SKIP:
    // really ignore
    break;

  case END_FUNCTION:
    // ignore
    break;
  
  case LOCATION:
    target.location(state.guard, state.source);
    break;
  
  case GOTO:
    symex_goto(state);
    break;
    
  case ASSUME:
    {
      exprt tmp(instruction.guard);
      replace_dynamic_allocation(state, tmp);
      dereference(tmp, state);
      state.rename(tmp);
      state.guard.guard_expr(tmp);
      target.assumption(state.guard, tmp, state.source);
    }
    break;

  case ASSERT:
    {
      exprt tmp(instruction.guard);
      replace_dynamic_allocation(state, tmp);
      dereference(tmp, state);

      if(options.get_bool_option("assertions") ||
         !state.source.pc->location.get_bool("user-provided"))
      {
        std::string msg=state.source.pc->location.get_string("comment");
        if(msg=="") msg="assertion";
        claim(tmp, msg, state);
      }
    }
    break;
    
  case RETURN:
    symex_return(state);
    break;

  case OTHER:
    symex_other(goto_functions, state);
    break;

  case SYNC: throw "SYNC not yet implemented";

  case START_THREAD: throw "START_THREAD not yet implemented";
  
  case END_THREAD: throw "END_TRHEAD not yet implemented";
  
  case ATOMIC_BEGIN: throw "ATOMIC_BEGIN not yet implemented";
  
  case ATOMIC_END: throw "ATOMIC_END not yet implemented";
  
  default:
    assert(false);
  }

  // next instruction

  if(instruction.type!=GOTO)
    state.source.pc++;
}
