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

Module:

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

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

#ifndef CPROVER_BOOLBV_H
#define CPROVER_BOOLBV_H

//
// convert sequent to boolean formula
//
// true: did nothing
// false: simplified something
//

#include <hash_cont.h>
#include <string>

#include <mp_arith.h>

#include "prop_conv.h"
#include "bv_utils.h"
#include "boolbv_width.h"
#include "arrays.h"

class boolbvt:
  public arrayst,
  protected boolbv_widtht
{
public:
  boolbvt(propt &_prop):
    arrayst(_prop),
    unbounded_array(U_NONE),
    bv_utils(_prop)
  {
  }
 
  virtual bool convert_bv(const exprt &expr, bvt &bv); // check cache
  virtual bool convert_bitvector(const exprt &expr, bvt &bv); // no cache

  // overloading
  virtual void get(const exprt &expr, exprt &dest) const;
  virtual void set_to(const exprt &expr, bool value);

  virtual void post_process()
  {
    post_process_quantifiers();
    SUB::post_process();
  }

  // get literals for variables/expressions, if available
  virtual bool literal(
    const exprt &expr,
    unsigned bit,
    literalt &literal) const;
    
  typedef enum { U_NONE, U_ALL, U_AUTO } unbounded_arrayt;
  unbounded_arrayt unbounded_array;

protected:
  bv_utilst bv_utils;
  
  // overloading
  virtual literalt convert_rest(const exprt &expr);
  virtual bool boolbv_set_equality_to_true(const exprt &expr);
  
  typedef arrayst SUB;

  // new stuff
  typedef enum
  {
    IS_BV, IS_SIGNED, IS_UNSIGNED, IS_FLOAT, IS_FIXED,
    IS_VERILOGBV, IS_RANGE, IS_UNKNOWN, IS_C_ENUM
  } bvtypet;

  typedef std::map<unsigned, literalt> literal_mapt;

  class bv_map_entryt
  {
  public:
    unsigned width;
    bvtypet bvtype;
    typet type;

    literal_mapt literal_map;
  };
  
  typedef hash_map_cont<const exprt, bvt, irep_hash> bv_cachet;
  typedef hash_map_cont<irep_idt, bv_map_entryt, irep_id_hash> mappingt;  
  
  bool make_fresh_variables(const exprt &expr, bvt &bv);

  mappingt mapping;
  void show_mapping() const;
  
  bv_cachet bv_cache;
  
  bv_map_entryt &get_map_entry(
    const irep_idt &identifier,
    const typet &type);

  virtual literalt get_literal(
    const irep_idt &identifier,
    const unsigned bit,
    const typet &type);

  virtual void set_literal(
    const irep_idt &identifier,
    const unsigned bit,
    const typet &type,
    literalt literal);

  static bvtypet get_bvtype(const typet &type);

  virtual literalt convert_bv_rel(const exprt &expr);
  virtual literalt convert_typecast(const exprt &expr);
  virtual literalt convert_reduction(const exprt &expr);
  virtual literalt convert_extractbit(const exprt &expr);
  virtual literalt convert_overflow(const exprt &expr);
  virtual literalt convert_equality(const exprt &expr);
  virtual literalt convert_quantifier(const exprt &expr);

  virtual bool convert_index(const exprt &expr, const mp_integer &index, bvt &bv);
  virtual bool convert_index(const exprt &expr, bvt &bv);
  virtual bool convert_byte_extract(const exprt &expr, const mp_integer &index, bvt &bv, bool little_endian);
  virtual bool convert_byte_extract(const exprt &expr, bvt &bv);
  virtual bool convert_constraint_select_one(const exprt &expr, bvt &bv);
  virtual bool convert_if(const exprt &expr, bvt &bv);
  virtual bool convert_struct(const exprt &expr, bvt &bv);
  virtual bool convert_array(const exprt &expr, bvt &bv);
  virtual bool convert_lambda(const exprt &expr, bvt &bv);
  virtual bool convert_array_of(const exprt &expr, bvt &bv);
  virtual bool convert_union(const exprt &expr, bvt &bv);
  virtual bool convert_typecast(const exprt &expr, bvt &bv);
  virtual bool convert_add_sub(const exprt &expr, bvt &bv);
  virtual bool convert_mult(const exprt &expr, bvt &bv);
  virtual bool convert_div(const exprt &expr, bvt &bv);
  virtual bool convert_mod(const exprt &expr, bvt &bv);
  virtual bool convert_member(const exprt &expr, bvt &bv);
  virtual bool convert_with(const exprt &expr, bvt &bv);
  virtual bool convert_case(const exprt &expr, bvt &bv);
  virtual bool convert_cond(const exprt &expr, bvt &bv);
  virtual bool convert_shift(const exprt &expr, bvt &bv);
  virtual bool convert_bitwise(const exprt &expr, bvt &bv);
  virtual bool convert_unary_minus(const exprt &expr, bvt &bv);
  virtual bool convert_concatenation(const exprt &expr, bvt &bv);
  virtual bool convert_replication(const exprt &expr, bvt &bv);
  virtual bool convert_bv_literals(const exprt &expr, bvt &bv);
  virtual bool convert_constant(const exprt &expr, bvt &bv);
  virtual bool convert_extractbits(const exprt &expr, bvt &bv);
  virtual bool convert_symbol(const exprt &expr, bvt &bv);

  virtual void make_bv_expr(const typet &type, const bvt &bv, exprt &dest);
  virtual void make_free_bv_expr(const typet &type, exprt &dest);

  bool convert_with(
    const typet &type,
    const exprt &op1,
    const exprt &op2,
    const bvt &prev_bv,
    bvt &next_bv);

  bool convert_with_bv(
    const typet &type,
    const exprt &op1,
    const exprt &op2,
    const bvt &prev_bv,
    bvt &next_bv);

  bool convert_with_array(
    const typet &type,
    const exprt &op1,
    const exprt &op2,
    const bvt &prev_bv,
    bvt &next_bv);

  bool convert_with_union(
    const typet &type,
    const exprt &op1,
    const exprt &op2,
    const bvt &prev_bv,
    bvt &next_bv);

  bool convert_with_struct(
    const typet &type,
    const exprt &op1,
    const exprt &op2,
    const bvt &prev_bv,
    bvt &next_bv);

  virtual void bv_get_unbounded_array(
    const irep_idt &identifier,
    const typet &type,
    exprt &dest) const;
                    
  virtual void bv_get_rec(
    const bvt &bv,
    const std::vector<bool> &unknown,
    unsigned offset,
    const typet &type,
    exprt &dest) const;

  void bv_get(const bvt &bv, const typet &type, exprt &dest) const;
  void bv_get_cache(const exprt &expr, exprt &dest) const;
                          
  // unbounded arrays

  bool is_unbounded_array(const typet &type) const;
  
  // quantifier instantiations
  class quantifiert
  {
  public:
    exprt expr;
    literalt l;
  };

  typedef std::list<quantifiert> quantifier_listt;
  quantifier_listt quantifier_list;
  
  void post_process_quantifiers();
};

#endif
