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

Module:

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

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

#include <assert.h>

#include <arith_tools.h>

#include "boolbv.h"

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

Function: boolbvt::convert_extractbit

  Inputs:

 Outputs:

 Purpose:

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

literalt boolbvt::convert_extractbit(const exprt &expr)
{
  const exprt::operandst &operands=expr.operands();

  if(operands.size()!=2)
    throw "extractbit takes two operands";
    
  bvt bv0;

  if(!convert_bv(operands[0], bv0))
  {
    mp_integer o;

    if(operands[0].type().id()=="verilogbv")
    {
      // TODO
    }
    else
    {
      if(!to_integer(operands[1], o)) // constant?
      {
        if(o<0 || o>=bv0.size())
          throw "extractbit: second operand out of range";

        return bv0[integer2long(o)];
      }
      else
      {
        if(prop.has_set_to())
        {
          // free variable
          literalt l=prop.new_literal();

          // add implications

          exprt equality("=", typet("bool"));
          equality.operands().resize(2);
          equality.op0()=operands[1]; // index operand

          typet constant_type=operands[1].type(); // type of index operand

          for(unsigned i=0; i<bv0.size(); i++)
          {
            equality.op1()=from_integer(i, constant_type);

            literalt equal=prop.lequal(l, bv0[i]);

            prop.l_set_to_true(prop.limplies(convert(equality), equal));
          }

          return l;
        }
        else
          assert(false);
      }
    }
  }
   
  return SUB::convert_rest(expr);
}
