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

Module:

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

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

#include "boolbv.h"

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

Function: boolbvt::convert_member

  Inputs:

 Outputs:

 Purpose:

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

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

  if(operands.size()!=1)
    throw "member takes one operand";

  bvt op0_bv;

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

  if(operands[0].type().id()=="union")
  {
    unsigned width;

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

    bv.resize(width);

    if(width>op0_bv.size())
      throw "member: unexpected widths";

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

    return false;
  }

  if(operands[0].type().id()!="struct") return true;

  const irep_idt &component_name=expr.get("component_name");
  const irept &components=operands[0].type().find("components");

  unsigned offset=0;

  forall_irep(it, components.get_sub())
  {
    unsigned sub_width;

    const typet &subtype=(typet &)it->find("type");

    if(get_width(subtype, sub_width))
      return true;

    if(it->get("name")==component_name)
    {
      if(subtype!=expr.type())
      {
        #if 0
        std::cout << "DEBUG " << expr.pretty() << "\n";
        #endif

        throw "member: component type does not match: "+
          subtype.to_string()+" vs. "+
          expr.type().to_string();
      }

      bv.resize(sub_width);
      for(unsigned i=0; i<sub_width; i++)
        bv[i]=op0_bv[offset+i];

      return false;
    }

    offset+=sub_width;
  }

  throw "component "+id2string(component_name)+" not found in structure";
}
