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

Module: Goto Programs with Functions

Author: Daniel Kroening

Date: October 2005

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

#include "function_dependencies.h"

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

Function: function_dependenciest::compute

  Inputs:

 Outputs:

 Purpose:

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

void function_dependenciest::compute(
  const goto_functiont &goto_function,
  function_sett &function_set)
{
  compute(goto_function.body, function_set);
}

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

Function: function_dependenciest::compute

  Inputs:

 Outputs:

 Purpose:

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

void function_dependenciest::compute(
  const goto_programt &goto_program,
  function_sett &function_set)
{
  for(goto_programt::instructionst::const_iterator
      it=goto_program.instructions.begin();
      it!=goto_program.instructions.end(); it++)
  {
    if(it->is_other())
    {
      if(it->code.get("statement")=="functioncall")
      {
        if(it->code.operands().size()<1)
          throw "functioncall takes at least one argument";

        call_rec(it->code.op0(), function_set);
      }
      else if(it->code.get("statement")=="assign" &&
              it->code.operands().size()==2 &&
              it->code.op1().id()=="sideeffect" &&
              it->code.op1().get("statement")=="functioncall")
      {
        if(it->code.op1().operands().size()<1)
          throw "functioncall takes at least one argument";

        call_rec(it->code.op1().op0(), function_set);
      }
    }
  }
}

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

Function: function_dependenciest::get_all_calls

  Inputs:

 Outputs:

 Purpose:

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

void function_dependenciest::get_all_calls(
  const irep_idt &identifier,
  function_sett &function_set)
{
  const function_sett &c=calls[identifier];

  for(function_sett::const_iterator f_it=c.begin();
      f_it!=c.end();
      f_it++)
  {
    if(function_set.find(*f_it)==function_set.end())
    {
      function_set.insert(*f_it);
      get_all_calls(*f_it, function_set);
    }
  }
}

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

Function: function_dependenciest::get_all_calls

  Inputs:

 Outputs:

 Purpose:

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

void function_dependenciest::get_all_calls(function_sett &function_set)
{
  get_all_calls("main", function_set);
}

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

Function: function_dependenciest::compute

  Inputs:

 Outputs:

 Purpose:

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

void function_dependenciest::compute(
  const goto_functionst &goto_functions)
{
  for(goto_functionst::function_mapt::const_iterator
      it=goto_functions.function_map.begin();
      it!=goto_functions.function_map.end();
      it++)
  {
    function_sett &c=calls[it->first];
  
    compute(it->second, c);
    
    for(function_sett::const_iterator f_it=c.begin();
        f_it!=c.end();
        f_it++)
      called_by[*f_it].insert(it->first);
  }
}

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

Function: function_dependenciest::call_rec

  Inputs:

 Outputs:

 Purpose:

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

void function_dependenciest::call_rec(
  const exprt &function,
  function_sett &function_set)
{
  if(function.id()=="symbol")
  {
    const irep_idt &identifier=function.get("identifier");
    function_set.insert(identifier);
  }
  else if(function.id()=="if")
  {
    if(function.operands().size()!=3)
      throw "if takes three arguments";
    
    call_rec(function.op1(), function_set);
    call_rec(function.op2(), function_set);
  }
  else
  {
    throw "unexpected functioncall argument: "+function.id_string();
  }
}

