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

Module:

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

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

#include <arith_tools.h>
#include <i2string.h>

#include "boolbv.h"

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

Function: boolbvt::convert_extractbits

  Inputs:

 Outputs:

 Purpose:

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

bool boolbvt::convert_extractbits(const exprt &expr, bvt &bv)
{
  unsigned width;
  if(get_width(expr.type(), width))
    return true;
  
  if(expr.type().id()!="signedbv" &&
     expr.type().id()!="unsignedbv" &&
     expr.type().id()!="bv")
    return true;

  if(expr.operands().size()!=3)
    throw "extractbits takes three operands";

  mp_integer o1, o2;
  bvt bv0;

  if(convert_bv(expr.op0(), bv0))
    return true;

  if(to_integer(expr.op1(), o1) ||
     to_integer(expr.op2(), o2))
    return true;
    
  if(o1<0 || o1>=bv0.size())
    throw "extractbits: second operand out of range: "+expr.to_string();

  if(o2<0 || o2>=bv0.size())
    throw "extractbits: third operand out of range: "+expr.to_string();

  if(o2>o1) std::swap(o1, o2);

  // now o2<=o1

  if((o1-o2+1)!=width)
    throw "extractbits: wrong width (expected "+
          i2string(unsigned(integer2long(o1-o2+1)))+" but got "+
          i2string(width)+"): "+expr.to_string();

  unsigned offset=integer2long(o2);

  bv.resize(width);

  for(unsigned i=0; i<width; i++)
    bv[i]=bv0[offset+i];

  return false;
}
