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

Module:

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

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

#include "boolbv.h"

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

Function: boolbvt::convert_cond

  Inputs:

 Outputs:

 Purpose:

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

bool boolbvt::convert_cond(const exprt &expr, bvt &bv)
{
  const exprt::operandst &operands=expr.operands();

  unsigned width;
  if(get_width(expr.type(), width))
    return true;

  bv.resize(width);

  // make it free variables
  for(unsigned i=0; i<bv.size(); i++)
    bv[i]=prop.new_literal();

  if(operands.size()<2)
    throw "cond takes at least two operands";

  if((operands.size()%2)!=0)
    throw "number of cond operands must be even";

  bool condition=true;
  literalt previous_cond=prop.constant(false);

  forall_operands(it, expr)
  {
    literalt cond_literal;

    if(condition)
    {
      cond_literal=convert(*it);
      cond_literal=prop.land(prop.lnot(previous_cond), cond_literal);

      previous_cond=prop.lor(previous_cond, cond_literal);
    }
    else
    {
      bvt op;

      if(convert_bv(*it, op))
        return true;

      if(bv.size()!=op.size())
      {
        std::cerr << "result size: " << bv.size()
                  << std::endl
                  << "operand: " << op.size() << std::endl
                  << it->pretty()
                  << std::endl;

        throw "size of value operand does not match";
      }

      literalt value_literal=bv_utils.equal(bv, op);

      prop.l_set_to_true(prop.limplies(cond_literal, value_literal));
    }

    condition=!condition;
  }

  return false;
}
