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

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::symex_other

  Inputs:

 Outputs:

 Purpose:

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

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

  codet deref_code(to_code(instruction.code));
  replace_dynamic_allocation(state, deref_code);
  dereference(deref_code, state);

  const irep_idt &statement=deref_code.get("statement");
  
  if(statement=="assign" || statement=="init")
  {
    assert(deref_code.operands().size()==2);
    
    if(deref_code.op1().id()=="sideeffect" &&
       deref_code.op1().get("statement")=="functioncall")
      symex_functioncall(
        goto_functions, state,
        deref_code.op0(), deref_code.op1());
    else
      basic_symext::symex_assign(state, deref_code, statement=="init");
  }
  else if(statement=="functioncall")
  {
    symex_functioncall(
      goto_functions, state,
      (const exprt &)nil_rep, deref_code);
  }
  else if(statement=="function_pointer_call")
  {
    if(deref_code.operands().size()!=2)
      throw "function_pointer_call takes two arguments";

    symex_functioncall(
      goto_functions, state,
      deref_code.op0(), deref_code.op1());
  }
  else if(statement=="expression")
  {
    // ignore
  }
  else if(statement=="cpp_delete" ||
          statement=="cpp_delete[]")
    symex_cpp_delete(state, deref_code);
  else if(statement=="printf")
    symex_printf(state, (const exprt &)nil_rep, deref_code);
  else if(statement=="decl")
  {
    if(deref_code.operands().size()!=1 &&
       deref_code.operands().size()!=2)
      throw "decl expects one or two operands";
    
    if(deref_code.op0().id()!="symbol")
      throw "decl expects symbol as first operand";

    // includes assignment? this is like "assign"
    if(deref_code.operands().size()==2)
      basic_symext::symex_assign(state, deref_code, false);
    else
    {
      // just do the L2 renaming to preseve locality
      const irep_idt &identifier=deref_code.op0().get("identifier");

      const std::string l1_identifier=
        state.level1.current_name(identifier);
        
      // seen it before?
      statet::level2t::current_namest::iterator it=
        state.level2.current_names.find(l1_identifier);
      
      if(it!=state.level2.current_names.end())
      {
        state.level2.rename(l1_identifier, it->second.count+1);
        it->second.constant.make_nil();
      }
    }
  }
  else if(statement=="nondet")
  {
    // like skip
  }
  else
    throw "unexpected statement: "+id2string(statement);
}
