open Prims
type sort =
  | Bool_sort 
  | Int_sort 
  | String_sort 
  | Term_sort 
  | Fuel_sort 
  | BitVec_sort of Prims.int 
  | Array of (sort * sort) 
  | Arrow of (sort * sort) 
  | Sort of Prims.string 
let uu___is_Bool_sort (projectee : sort) : Prims.bool=
  match projectee with | Bool_sort -> true | uu___ -> false
let uu___is_Int_sort (projectee : sort) : Prims.bool=
  match projectee with | Int_sort -> true | uu___ -> false
let uu___is_String_sort (projectee : sort) : Prims.bool=
  match projectee with | String_sort -> true | uu___ -> false
let uu___is_Term_sort (projectee : sort) : Prims.bool=
  match projectee with | Term_sort -> true | uu___ -> false
let uu___is_Fuel_sort (projectee : sort) : Prims.bool=
  match projectee with | Fuel_sort -> true | uu___ -> false
let uu___is_BitVec_sort (projectee : sort) : Prims.bool=
  match projectee with | BitVec_sort _0 -> true | uu___ -> false
let __proj__BitVec_sort__item___0 (projectee : sort) : Prims.int=
  match projectee with | BitVec_sort _0 -> _0
let uu___is_Array (projectee : sort) : Prims.bool=
  match projectee with | Array _0 -> true | uu___ -> false
let __proj__Array__item___0 (projectee : sort) : (sort * sort)=
  match projectee with | Array _0 -> _0
let uu___is_Arrow (projectee : sort) : Prims.bool=
  match projectee with | Arrow _0 -> true | uu___ -> false
let __proj__Arrow__item___0 (projectee : sort) : (sort * sort)=
  match projectee with | Arrow _0 -> _0
let uu___is_Sort (projectee : sort) : Prims.bool=
  match projectee with | Sort _0 -> true | uu___ -> false
let __proj__Sort__item___0 (projectee : sort) : Prims.string=
  match projectee with | Sort _0 -> _0
type op =
  | TrueOp 
  | FalseOp 
  | Not 
  | And 
  | Or 
  | Imp 
  | Iff 
  | Eq 
  | LT 
  | LTE 
  | GT 
  | GTE 
  | Add 
  | Sub 
  | Div 
  | RealDiv 
  | Mul 
  | Minus 
  | Mod 
  | BvAnd 
  | BvXor 
  | BvOr 
  | BvAdd 
  | BvSub 
  | BvShl 
  | BvShr 
  | BvUdiv 
  | BvMod 
  | BvMul 
  | BvUlt 
  | BvExtRol 
  | BvExtRor 
  | BvRol of Prims.int 
  | BvRor of Prims.int 
  | BvUext of Prims.int 
  | BvNot 
  | NatToBv of Prims.int 
  | BvToNat 
  | ITE 
  | Var of Prims.string 
let uu___is_TrueOp (projectee : op) : Prims.bool=
  match projectee with | TrueOp -> true | uu___ -> false
let uu___is_FalseOp (projectee : op) : Prims.bool=
  match projectee with | FalseOp -> true | uu___ -> false
let uu___is_Not (projectee : op) : Prims.bool=
  match projectee with | Not -> true | uu___ -> false
let uu___is_And (projectee : op) : Prims.bool=
  match projectee with | And -> true | uu___ -> false
let uu___is_Or (projectee : op) : Prims.bool=
  match projectee with | Or -> true | uu___ -> false
let uu___is_Imp (projectee : op) : Prims.bool=
  match projectee with | Imp -> true | uu___ -> false
let uu___is_Iff (projectee : op) : Prims.bool=
  match projectee with | Iff -> true | uu___ -> false
let uu___is_Eq (projectee : op) : Prims.bool=
  match projectee with | Eq -> true | uu___ -> false
let uu___is_LT (projectee : op) : Prims.bool=
  match projectee with | LT -> true | uu___ -> false
let uu___is_LTE (projectee : op) : Prims.bool=
  match projectee with | LTE -> true | uu___ -> false
let uu___is_GT (projectee : op) : Prims.bool=
  match projectee with | GT -> true | uu___ -> false
let uu___is_GTE (projectee : op) : Prims.bool=
  match projectee with | GTE -> true | uu___ -> false
let uu___is_Add (projectee : op) : Prims.bool=
  match projectee with | Add -> true | uu___ -> false
let uu___is_Sub (projectee : op) : Prims.bool=
  match projectee with | Sub -> true | uu___ -> false
let uu___is_Div (projectee : op) : Prims.bool=
  match projectee with | Div -> true | uu___ -> false
let uu___is_RealDiv (projectee : op) : Prims.bool=
  match projectee with | RealDiv -> true | uu___ -> false
let uu___is_Mul (projectee : op) : Prims.bool=
  match projectee with | Mul -> true | uu___ -> false
let uu___is_Minus (projectee : op) : Prims.bool=
  match projectee with | Minus -> true | uu___ -> false
let uu___is_Mod (projectee : op) : Prims.bool=
  match projectee with | Mod -> true | uu___ -> false
let uu___is_BvAnd (projectee : op) : Prims.bool=
  match projectee with | BvAnd -> true | uu___ -> false
let uu___is_BvXor (projectee : op) : Prims.bool=
  match projectee with | BvXor -> true | uu___ -> false
let uu___is_BvOr (projectee : op) : Prims.bool=
  match projectee with | BvOr -> true | uu___ -> false
let uu___is_BvAdd (projectee : op) : Prims.bool=
  match projectee with | BvAdd -> true | uu___ -> false
let uu___is_BvSub (projectee : op) : Prims.bool=
  match projectee with | BvSub -> true | uu___ -> false
let uu___is_BvShl (projectee : op) : Prims.bool=
  match projectee with | BvShl -> true | uu___ -> false
let uu___is_BvShr (projectee : op) : Prims.bool=
  match projectee with | BvShr -> true | uu___ -> false
let uu___is_BvUdiv (projectee : op) : Prims.bool=
  match projectee with | BvUdiv -> true | uu___ -> false
let uu___is_BvMod (projectee : op) : Prims.bool=
  match projectee with | BvMod -> true | uu___ -> false
let uu___is_BvMul (projectee : op) : Prims.bool=
  match projectee with | BvMul -> true | uu___ -> false
let uu___is_BvUlt (projectee : op) : Prims.bool=
  match projectee with | BvUlt -> true | uu___ -> false
let uu___is_BvExtRol (projectee : op) : Prims.bool=
  match projectee with | BvExtRol -> true | uu___ -> false
let uu___is_BvExtRor (projectee : op) : Prims.bool=
  match projectee with | BvExtRor -> true | uu___ -> false
let uu___is_BvRol (projectee : op) : Prims.bool=
  match projectee with | BvRol _0 -> true | uu___ -> false
let __proj__BvRol__item___0 (projectee : op) : Prims.int=
  match projectee with | BvRol _0 -> _0
let uu___is_BvRor (projectee : op) : Prims.bool=
  match projectee with | BvRor _0 -> true | uu___ -> false
let __proj__BvRor__item___0 (projectee : op) : Prims.int=
  match projectee with | BvRor _0 -> _0
let uu___is_BvUext (projectee : op) : Prims.bool=
  match projectee with | BvUext _0 -> true | uu___ -> false
let __proj__BvUext__item___0 (projectee : op) : Prims.int=
  match projectee with | BvUext _0 -> _0
let uu___is_BvNot (projectee : op) : Prims.bool=
  match projectee with | BvNot -> true | uu___ -> false
let uu___is_NatToBv (projectee : op) : Prims.bool=
  match projectee with | NatToBv _0 -> true | uu___ -> false
let __proj__NatToBv__item___0 (projectee : op) : Prims.int=
  match projectee with | NatToBv _0 -> _0
let uu___is_BvToNat (projectee : op) : Prims.bool=
  match projectee with | BvToNat -> true | uu___ -> false
let uu___is_ITE (projectee : op) : Prims.bool=
  match projectee with | ITE -> true | uu___ -> false
let uu___is_Var (projectee : op) : Prims.bool=
  match projectee with | Var _0 -> true | uu___ -> false
let __proj__Var__item___0 (projectee : op) : Prims.string=
  match projectee with | Var _0 -> _0
type qop =
  | Forall 
  | Exists 
let uu___is_Forall (projectee : qop) : Prims.bool=
  match projectee with | Forall -> true | uu___ -> false
let uu___is_Exists (projectee : qop) : Prims.bool=
  match projectee with | Exists -> true | uu___ -> false
type term' =
  | Integer of Prims.string 
  | String of Prims.string 
  | Real of Prims.string 
  | BoundV of Prims.int 
  | FreeV of fv 
  | App of (op * term Prims.list) 
  | Quant of (qop * term Prims.list Prims.list * Prims.int
  FStar_Pervasives_Native.option * sort Prims.list * term) 
  | Let of (term Prims.list * term) 
  | Labeled of (term * FStarC_Errors_Msg.error_message * FStarC_Range_Type.t) 
and term =
  {
  tm: term' ;
  freevars: fv Prims.list FStarC_Syntax_Syntax.memo ;
  rng: FStarC_Range_Type.t }
and fv =
  | FV of (Prims.string * sort * Prims.bool) 
let uu___is_Integer (projectee : term') : Prims.bool=
  match projectee with | Integer _0 -> true | uu___ -> false
let __proj__Integer__item___0 (projectee : term') : Prims.string=
  match projectee with | Integer _0 -> _0
let uu___is_String (projectee : term') : Prims.bool=
  match projectee with | String _0 -> true | uu___ -> false
let __proj__String__item___0 (projectee : term') : Prims.string=
  match projectee with | String _0 -> _0
let uu___is_Real (projectee : term') : Prims.bool=
  match projectee with | Real _0 -> true | uu___ -> false
let __proj__Real__item___0 (projectee : term') : Prims.string=
  match projectee with | Real _0 -> _0
let uu___is_BoundV (projectee : term') : Prims.bool=
  match projectee with | BoundV _0 -> true | uu___ -> false
let __proj__BoundV__item___0 (projectee : term') : Prims.int=
  match projectee with | BoundV _0 -> _0
let uu___is_FreeV (projectee : term') : Prims.bool=
  match projectee with | FreeV _0 -> true | uu___ -> false
let __proj__FreeV__item___0 (projectee : term') : fv=
  match projectee with | FreeV _0 -> _0
let uu___is_App (projectee : term') : Prims.bool=
  match projectee with | App _0 -> true | uu___ -> false
let __proj__App__item___0 (projectee : term') : (op * term Prims.list)=
  match projectee with | App _0 -> _0
let uu___is_Quant (projectee : term') : Prims.bool=
  match projectee with | Quant _0 -> true | uu___ -> false
let __proj__Quant__item___0 (projectee : term') :
  (qop * term Prims.list Prims.list * Prims.int
    FStar_Pervasives_Native.option * sort Prims.list * term)=
  match projectee with | Quant _0 -> _0
let uu___is_Let (projectee : term') : Prims.bool=
  match projectee with | Let _0 -> true | uu___ -> false
let __proj__Let__item___0 (projectee : term') : (term Prims.list * term)=
  match projectee with | Let _0 -> _0
let uu___is_Labeled (projectee : term') : Prims.bool=
  match projectee with | Labeled _0 -> true | uu___ -> false
let __proj__Labeled__item___0 (projectee : term') :
  (term * FStarC_Errors_Msg.error_message * FStarC_Range_Type.t)=
  match projectee with | Labeled _0 -> _0
let __proj__Mkterm__item__tm (projectee : term) : term'=
  match projectee with | { tm; freevars; rng;_} -> tm
let __proj__Mkterm__item__freevars (projectee : term) :
  fv Prims.list FStarC_Syntax_Syntax.memo=
  match projectee with | { tm; freevars; rng;_} -> freevars
let __proj__Mkterm__item__rng (projectee : term) : FStarC_Range_Type.t=
  match projectee with | { tm; freevars; rng;_} -> rng
let uu___is_FV (projectee : fv) : Prims.bool= true
let __proj__FV__item___0 (projectee : fv) :
  (Prims.string * sort * Prims.bool)= match projectee with | FV _0 -> _0
type pat = term
type fvs = fv Prims.list
type caption = Prims.string FStar_Pervasives_Native.option
type binders = (Prims.string * sort) Prims.list
type constructor_field =
  {
  field_name: Prims.string ;
  field_sort: sort ;
  field_projectible: Prims.bool }
let __proj__Mkconstructor_field__item__field_name
  (projectee : constructor_field) : Prims.string=
  match projectee with
  | { field_name; field_sort; field_projectible;_} -> field_name
let __proj__Mkconstructor_field__item__field_sort
  (projectee : constructor_field) : sort=
  match projectee with
  | { field_name; field_sort; field_projectible;_} -> field_sort
let __proj__Mkconstructor_field__item__field_projectible
  (projectee : constructor_field) : Prims.bool=
  match projectee with
  | { field_name; field_sort; field_projectible;_} -> field_projectible
type constructor_t =
  {
  constr_name: Prims.string ;
  constr_fields: constructor_field Prims.list ;
  constr_sort: sort ;
  constr_id: Prims.int FStar_Pervasives_Native.option ;
  constr_base: Prims.bool }
let __proj__Mkconstructor_t__item__constr_name (projectee : constructor_t) :
  Prims.string=
  match projectee with
  | { constr_name; constr_fields; constr_sort; constr_id; constr_base;_} ->
      constr_name
let __proj__Mkconstructor_t__item__constr_fields (projectee : constructor_t)
  : constructor_field Prims.list=
  match projectee with
  | { constr_name; constr_fields; constr_sort; constr_id; constr_base;_} ->
      constr_fields
let __proj__Mkconstructor_t__item__constr_sort (projectee : constructor_t) :
  sort=
  match projectee with
  | { constr_name; constr_fields; constr_sort; constr_id; constr_base;_} ->
      constr_sort
let __proj__Mkconstructor_t__item__constr_id (projectee : constructor_t) :
  Prims.int FStar_Pervasives_Native.option=
  match projectee with
  | { constr_name; constr_fields; constr_sort; constr_id; constr_base;_} ->
      constr_id
let __proj__Mkconstructor_t__item__constr_base (projectee : constructor_t) :
  Prims.bool=
  match projectee with
  | { constr_name; constr_fields; constr_sort; constr_id; constr_base;_} ->
      constr_base
type constructors = constructor_t Prims.list
type fact_db_id =
  | Name of FStarC_Ident.lid 
  | Namespace of FStarC_Ident.lid 
  | Tag of Prims.string 
let uu___is_Name (projectee : fact_db_id) : Prims.bool=
  match projectee with | Name _0 -> true | uu___ -> false
let __proj__Name__item___0 (projectee : fact_db_id) : FStarC_Ident.lid=
  match projectee with | Name _0 -> _0
let uu___is_Namespace (projectee : fact_db_id) : Prims.bool=
  match projectee with | Namespace _0 -> true | uu___ -> false
let __proj__Namespace__item___0 (projectee : fact_db_id) : FStarC_Ident.lid=
  match projectee with | Namespace _0 -> _0
let uu___is_Tag (projectee : fact_db_id) : Prims.bool=
  match projectee with | Tag _0 -> true | uu___ -> false
let __proj__Tag__item___0 (projectee : fact_db_id) : Prims.string=
  match projectee with | Tag _0 -> _0
type assumption =
  {
  assumption_term: term ;
  assumption_caption: caption ;
  assumption_name: Prims.string ;
  assumption_fact_ids: fact_db_id Prims.list ;
  assumption_free_names: Prims.string FStarC_RBSet.t }
let __proj__Mkassumption__item__assumption_term (projectee : assumption) :
  term=
  match projectee with
  | { assumption_term; assumption_caption; assumption_name;
      assumption_fact_ids; assumption_free_names;_} -> assumption_term
let __proj__Mkassumption__item__assumption_caption (projectee : assumption) :
  caption=
  match projectee with
  | { assumption_term; assumption_caption; assumption_name;
      assumption_fact_ids; assumption_free_names;_} -> assumption_caption
let __proj__Mkassumption__item__assumption_name (projectee : assumption) :
  Prims.string=
  match projectee with
  | { assumption_term; assumption_caption; assumption_name;
      assumption_fact_ids; assumption_free_names;_} -> assumption_name
let __proj__Mkassumption__item__assumption_fact_ids (projectee : assumption)
  : fact_db_id Prims.list=
  match projectee with
  | { assumption_term; assumption_caption; assumption_name;
      assumption_fact_ids; assumption_free_names;_} -> assumption_fact_ids
let __proj__Mkassumption__item__assumption_free_names
  (projectee : assumption) : Prims.string FStarC_RBSet.t=
  match projectee with
  | { assumption_term; assumption_caption; assumption_name;
      assumption_fact_ids; assumption_free_names;_} -> assumption_free_names
type decl =
  | DefPrelude 
  | DeclFun of (Prims.string * sort Prims.list * sort * caption) 
  | DefineFun of (Prims.string * sort Prims.list * sort * term * caption) 
  | Assume of assumption 
  | Caption of Prims.string 
  | Module of (Prims.string * decl Prims.list) 
  | Eval of term 
  | Echo of Prims.string 
  | RetainAssumptions of Prims.string Prims.list 
  | Push of Prims.int 
  | Pop of Prims.int 
  | CheckSat 
  | GetUnsatCore 
  | SetOption of (Prims.string * Prims.string) 
  | GetStatistics 
  | GetReasonUnknown 
  | EmptyLine 
let uu___is_DefPrelude (projectee : decl) : Prims.bool=
  match projectee with | DefPrelude -> true | uu___ -> false
let uu___is_DeclFun (projectee : decl) : Prims.bool=
  match projectee with | DeclFun _0 -> true | uu___ -> false
let __proj__DeclFun__item___0 (projectee : decl) :
  (Prims.string * sort Prims.list * sort * caption)=
  match projectee with | DeclFun _0 -> _0
let uu___is_DefineFun (projectee : decl) : Prims.bool=
  match projectee with | DefineFun _0 -> true | uu___ -> false
let __proj__DefineFun__item___0 (projectee : decl) :
  (Prims.string * sort Prims.list * sort * term * caption)=
  match projectee with | DefineFun _0 -> _0
let uu___is_Assume (projectee : decl) : Prims.bool=
  match projectee with | Assume _0 -> true | uu___ -> false
let __proj__Assume__item___0 (projectee : decl) : assumption=
  match projectee with | Assume _0 -> _0
let uu___is_Caption (projectee : decl) : Prims.bool=
  match projectee with | Caption _0 -> true | uu___ -> false
let __proj__Caption__item___0 (projectee : decl) : Prims.string=
  match projectee with | Caption _0 -> _0
let uu___is_Module (projectee : decl) : Prims.bool=
  match projectee with | Module _0 -> true | uu___ -> false
let __proj__Module__item___0 (projectee : decl) :
  (Prims.string * decl Prims.list)= match projectee with | Module _0 -> _0
let uu___is_Eval (projectee : decl) : Prims.bool=
  match projectee with | Eval _0 -> true | uu___ -> false
let __proj__Eval__item___0 (projectee : decl) : term=
  match projectee with | Eval _0 -> _0
let uu___is_Echo (projectee : decl) : Prims.bool=
  match projectee with | Echo _0 -> true | uu___ -> false
let __proj__Echo__item___0 (projectee : decl) : Prims.string=
  match projectee with | Echo _0 -> _0
let uu___is_RetainAssumptions (projectee : decl) : Prims.bool=
  match projectee with | RetainAssumptions _0 -> true | uu___ -> false
let __proj__RetainAssumptions__item___0 (projectee : decl) :
  Prims.string Prims.list= match projectee with | RetainAssumptions _0 -> _0
let uu___is_Push (projectee : decl) : Prims.bool=
  match projectee with | Push _0 -> true | uu___ -> false
let __proj__Push__item___0 (projectee : decl) : Prims.int=
  match projectee with | Push _0 -> _0
let uu___is_Pop (projectee : decl) : Prims.bool=
  match projectee with | Pop _0 -> true | uu___ -> false
let __proj__Pop__item___0 (projectee : decl) : Prims.int=
  match projectee with | Pop _0 -> _0
let uu___is_CheckSat (projectee : decl) : Prims.bool=
  match projectee with | CheckSat -> true | uu___ -> false
let uu___is_GetUnsatCore (projectee : decl) : Prims.bool=
  match projectee with | GetUnsatCore -> true | uu___ -> false
let uu___is_SetOption (projectee : decl) : Prims.bool=
  match projectee with | SetOption _0 -> true | uu___ -> false
let __proj__SetOption__item___0 (projectee : decl) :
  (Prims.string * Prims.string)= match projectee with | SetOption _0 -> _0
let uu___is_GetStatistics (projectee : decl) : Prims.bool=
  match projectee with | GetStatistics -> true | uu___ -> false
let uu___is_GetReasonUnknown (projectee : decl) : Prims.bool=
  match projectee with | GetReasonUnknown -> true | uu___ -> false
let uu___is_EmptyLine (projectee : decl) : Prims.bool=
  match projectee with | EmptyLine -> true | uu___ -> false
type decls_elt =
  {
  sym_name: Prims.string FStar_Pervasives_Native.option ;
  key: Prims.string FStar_Pervasives_Native.option ;
  decls: decl Prims.list ;
  a_names: Prims.string Prims.list }
let __proj__Mkdecls_elt__item__sym_name (projectee : decls_elt) :
  Prims.string FStar_Pervasives_Native.option=
  match projectee with | { sym_name; key; decls; a_names;_} -> sym_name
let __proj__Mkdecls_elt__item__key (projectee : decls_elt) :
  Prims.string FStar_Pervasives_Native.option=
  match projectee with | { sym_name; key; decls; a_names;_} -> key
let __proj__Mkdecls_elt__item__decls (projectee : decls_elt) :
  decl Prims.list=
  match projectee with | { sym_name; key; decls; a_names;_} -> decls
let __proj__Mkdecls_elt__item__a_names (projectee : decls_elt) :
  Prims.string Prims.list=
  match projectee with | { sym_name; key; decls; a_names;_} -> a_names
type decls_t = decls_elt Prims.list
let escape (s : Prims.string) : Prims.string=
  FStarC_Util.replace_char s 39 95
type error_label =
  (fv * FStarC_Errors_Msg.error_message * FStarC_Range_Type.t)
type error_labels = error_label Prims.list
let render : FStar_Pprint.document -> Prims.string=
  FStarC_Pprint.pretty_string (FStarC_Util.float_of_string "1.0")
    (Prims.of_int 100)
let form_core (children : FStar_Pprint.document Prims.list) :
  FStar_Pprint.document=
  FStar_Pprint.parens
    (FStar_Pprint.nest Prims.int_one
       (FStar_Pprint.group
          (FStar_Pprint.separate (FStar_Pprint.break_ Prims.int_one) children)))
let form (fn : Prims.string) (args : FStar_Pprint.document Prims.list) :
  FStar_Pprint.document= form_core ((FStar_Pprint.doc_of_string fn) :: args)
let binder (fn : Prims.string) (b : FStar_Pprint.document)
  (args : FStar_Pprint.document Prims.list) : FStar_Pprint.document=
  form_core
    ((FStar_Pprint.nest Prims.int_one
        (FStar_Pprint.group
           (FStar_Pprint.op_Hat_Slash_Hat (FStar_Pprint.doc_of_string fn) b)))
    :: args)
let mk_qid (id : Prims.string) : FStar_Pprint.document=
  FStar_Pprint.nest Prims.int_one
    (FStar_Pprint.group
       (FStar_Pprint.op_Hat_Slash_Hat (FStar_Pprint.doc_of_string ":qid")
          (FStar_Pprint.doc_of_string id)))
let mk_lblpos (id : Prims.string) : FStar_Pprint.document=
  FStar_Pprint.nest Prims.int_one
    (FStar_Pprint.group
       (FStar_Pprint.op_Hat_Slash_Hat (FStar_Pprint.doc_of_string ":lblpos")
          (FStar_Pprint.doc_of_string id)))
let mk_named (id : Prims.string) : FStar_Pprint.document=
  FStar_Pprint.nest Prims.int_one
    (FStar_Pprint.group
       (FStar_Pprint.op_Hat_Slash_Hat (FStar_Pprint.doc_of_string ":named")
          (FStar_Pprint.doc_of_string id)))
let mk_pattern (pat1 : FStar_Pprint.document) : FStar_Pprint.document=
  FStar_Pprint.nest Prims.int_one
    (FStar_Pprint.group
       (FStar_Pprint.op_Hat_Slash_Hat (FStar_Pprint.doc_of_string ":pattern")
          pat1))
let rec strSort (x : sort) : Prims.string=
  match x with
  | Bool_sort -> "Bool"
  | Int_sort -> "Int"
  | Term_sort -> "Term"
  | String_sort -> "FString"
  | Fuel_sort -> "Fuel"
  | BitVec_sort n ->
      let uu___ = FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
      FStarC_Format.fmt1 "(_ BitVec %s)" uu___
  | Array (s1, s2) ->
      let uu___ = strSort s1 in
      let uu___1 = strSort s2 in
      FStarC_Format.fmt2 "(Array %s %s)" uu___ uu___1
  | Arrow (s1, s2) ->
      let uu___ = strSort s1 in
      let uu___1 = strSort s2 in FStarC_Format.fmt2 "(%s -> %s)" uu___ uu___1
  | Sort s -> s
let rec docSort (x : sort) : FStar_Pprint.document=
  match x with
  | Bool_sort -> FStar_Pprint.doc_of_string "Bool"
  | Int_sort -> FStar_Pprint.doc_of_string "Int"
  | Term_sort -> FStar_Pprint.doc_of_string "Term"
  | String_sort -> FStar_Pprint.doc_of_string "FString"
  | Fuel_sort -> FStar_Pprint.doc_of_string "Fuel"
  | BitVec_sort n ->
      let uu___ =
        let uu___1 =
          let uu___2 =
            let uu___3 =
              FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
            FStar_Pprint.doc_of_string uu___3 in
          [uu___2] in
        (FStar_Pprint.doc_of_string "BitVec") :: uu___1 in
      form "_" uu___
  | Array (s1, s2) ->
      let uu___ =
        let uu___1 = docSort s1 in
        let uu___2 = let uu___3 = docSort s2 in [uu___3] in uu___1 :: uu___2 in
      form "Array" uu___
  | Arrow (s1, s2) ->
      let uu___ =
        let uu___1 =
          let uu___2 =
            let uu___3 = docSort s1 in
            let uu___4 =
              let uu___5 = docSort s2 in
              FStar_Pprint.op_Hat_Slash_Hat
                (FStar_Pprint.doc_of_string " ->") uu___5 in
            FStar_Pprint.op_Hat_Hat uu___3 uu___4 in
          FStar_Pprint.parens uu___2 in
        FStar_Pprint.group uu___1 in
      FStar_Pprint.nest Prims.int_one uu___
  | Sort s -> FStar_Pprint.doc_of_string s
let mk_decls (name : Prims.string) (key : Prims.string)
  (decls : decl Prims.list) (aux_decls : decls_elt Prims.list) : decls_t=
  let uu___ =
    let uu___1 =
      let sm = FStarC_SMap.create (Prims.of_int 20) in
      FStarC_List.iter
        (fun elt ->
           FStarC_List.iter (fun s -> FStarC_SMap.add sm s "0") elt.a_names)
        aux_decls;
      FStarC_List.iter
        (fun d ->
           match d with
           | Assume a -> FStarC_SMap.add sm a.assumption_name "0"
           | uu___4 -> ()) decls;
      FStarC_SMap.keys sm in
    {
      sym_name = (FStar_Pervasives_Native.Some name);
      key = (FStar_Pervasives_Native.Some key);
      decls;
      a_names = uu___1
    } in
  [uu___]
let mk_decls_trivial (decls : decl Prims.list) : decls_t=
  let uu___ =
    let uu___1 =
      FStarC_List.collect
        (fun uu___2 ->
           match uu___2 with | Assume a -> [a.assumption_name] | uu___3 -> [])
        decls in
    {
      sym_name = FStar_Pervasives_Native.None;
      key = FStar_Pervasives_Native.None;
      decls;
      a_names = uu___1
    } in
  [uu___]
let decls_list_of (l : decls_t) : decl Prims.list=
  FStarC_List.collect (fun elt -> elt.decls) l
let mk_fv (uu___ : (Prims.string * sort)) : fv=
  match uu___ with | (x, y) -> FV (x, y, false)
let fv_name (x : fv) : Prims.string=
  let uu___ = x in match uu___ with | FV (nm, uu___1, uu___2) -> nm
let deq_fv : fv FStarC_Class_Deq.deq=
  {
    FStarC_Class_Deq.op_Equals_Question =
      (fun fv1 fv2 -> (fv_name fv1) = (fv_name fv2))
  }
let ord_fv : fv FStarC_Class_Ord.ord=
  {
    FStarC_Class_Ord.super = deq_fv;
    FStarC_Class_Ord.cmp =
      (fun fv1 fv2 ->
         FStarC_Order.order_from_int
           (FStarC_Util.compare (fv_name fv1) (fv_name fv2)))
  }
let fv_sort (x : fv) : sort=
  let uu___ = x in match uu___ with | FV (uu___1, sort1, uu___2) -> sort1
let fv_force (x : fv) : Prims.bool=
  let uu___ = x in match uu___ with | FV (uu___1, uu___2, force) -> force
let fv_eq (x : fv) (y : fv) : Prims.bool= (fv_name x) = (fv_name y)
let fvs_subset_of (x : fvs) (y : fvs) : Prims.bool=
  let uu___ =
    Obj.magic
      (FStarC_Class_Setlike.from_list ()
         (Obj.magic (FStarC_RBSet.setlike_rbset ord_fv)) x) in
  let uu___1 =
    Obj.magic
      (FStarC_Class_Setlike.from_list ()
         (Obj.magic (FStarC_RBSet.setlike_rbset ord_fv)) y) in
  FStarC_Class_Setlike.subset ()
    (Obj.magic (FStarC_RBSet.setlike_rbset ord_fv)) (Obj.magic uu___)
    (Obj.magic uu___1)
let freevar_eq (x : term) (y : term) : Prims.bool=
  match ((x.tm), (y.tm)) with
  | (FreeV x1, FreeV y1) -> fv_eq x1 y1
  | uu___ -> false
let freevar_sort (uu___ : term) : sort=
  match uu___ with
  | { tm = FreeV x; freevars = uu___1; rng = uu___2;_} -> fv_sort x
  | uu___1 -> FStarC_Effect.failwith "impossible"
let fv_of_term (uu___ : term) : fv=
  match uu___ with
  | { tm = FreeV fv1; freevars = uu___1; rng = uu___2;_} -> fv1
  | uu___1 -> FStarC_Effect.failwith "impossible"
let rec freevars (t : term) : fv Prims.list=
  match t.tm with
  | Integer uu___ -> []
  | String uu___ -> []
  | Real uu___ -> []
  | BoundV uu___ -> []
  | FreeV fv1 when fv_force fv1 -> []
  | FreeV fv1 -> [fv1]
  | App (uu___, tms) -> FStarC_List.collect freevars tms
  | Quant (uu___, uu___1, uu___2, uu___3, t1) -> freevars t1
  | Labeled (t1, uu___, uu___1) -> freevars t1
  | Let (es, body) -> FStarC_List.collect freevars (body :: es)
let free_variables (t : term) : fvs=
  let uu___ = FStarC_Effect.op_Bang t.freevars in
  match uu___ with
  | FStar_Pervasives_Native.Some b -> b
  | FStar_Pervasives_Native.None ->
      let fvs1 =
        let uu___1 = freevars t in FStarC_Util.remove_dups fv_eq uu___1 in
      (FStarC_Effect.op_Colon_Equals t.freevars
         (FStar_Pervasives_Native.Some fvs1);
       fvs1)
let free_top_level_names (t : term) : Prims.string FStarC_RBSet.t=
  let rec free_top_level_names1 uu___1 uu___ =
    (fun acc t1 ->
       match t1.tm with
       | FreeV (FV (nm, uu___, uu___1)) ->
           Obj.magic
             (Obj.repr
                (FStarC_Class_Setlike.add ()
                   (Obj.magic
                      (FStarC_RBSet.setlike_rbset FStarC_Class_Ord.ord_string))
                   nm (Obj.magic acc)))
       | App (Var s, args) ->
           Obj.magic
             (Obj.repr
                (let acc1 =
                   Obj.magic
                     (FStarC_Class_Setlike.add ()
                        (Obj.magic
                           (FStarC_RBSet.setlike_rbset
                              FStarC_Class_Ord.ord_string)) s (Obj.magic acc)) in
                 FStarC_List.fold_left free_top_level_names1 acc1 args))
       | App (uu___, args) ->
           Obj.magic
             (Obj.repr (FStarC_List.fold_left free_top_level_names1 acc args))
       | Quant (uu___, pats, uu___1, uu___2, body) ->
           Obj.magic
             (Obj.repr
                (let acc1 =
                   FStarC_List.fold_left
                     (fun acc2 pats1 ->
                        FStarC_List.fold_left free_top_level_names1 acc2
                          pats1) acc pats in
                 free_top_level_names1 acc1 body))
       | Let (tms, t2) ->
           Obj.magic
             (Obj.repr
                (let acc1 =
                   FStarC_List.fold_left free_top_level_names1 acc tms in
                 free_top_level_names1 acc1 t2))
       | Labeled (t2, uu___, uu___1) ->
           Obj.magic (Obj.repr (free_top_level_names1 acc t2))
       | uu___ -> Obj.magic (Obj.repr acc)) uu___1 uu___ in
  let uu___ =
    Obj.magic
      (FStarC_Class_Setlike.empty ()
         (Obj.magic (FStarC_RBSet.setlike_rbset FStarC_Class_Ord.ord_string))
         ()) in
  free_top_level_names1 uu___ t
let qop_to_string (uu___ : qop) : Prims.string=
  match uu___ with | Forall -> "forall" | Exists -> "exists"
let op_to_string (uu___ : op) : Prims.string=
  match uu___ with
  | TrueOp -> "true"
  | FalseOp -> "false"
  | Not -> "not"
  | And -> "and"
  | Or -> "or"
  | Imp -> "implies"
  | Iff -> "iff"
  | Eq -> "="
  | LT -> "<"
  | LTE -> "<="
  | GT -> ">"
  | GTE -> ">="
  | Add -> "+"
  | Sub -> "-"
  | Div -> "div"
  | RealDiv -> "/"
  | Mul -> "*"
  | Minus -> "-"
  | Mod -> "mod"
  | ITE -> "ite"
  | BvAnd -> "bvand"
  | BvXor -> "bvxor"
  | BvOr -> "bvor"
  | BvAdd -> "bvadd"
  | BvSub -> "bvsub"
  | BvShl -> "bvshl"
  | BvShr -> "bvlshr"
  | BvUdiv -> "bvudiv"
  | BvMod -> "bvurem"
  | BvMul -> "bvmul"
  | BvUlt -> "bvult"
  | BvExtRol -> "ext_rotate_left"
  | BvExtRor -> "ext_rotate_right"
  | BvRol n ->
      let uu___1 = FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
      FStarC_Format.fmt1 "(_ rotate_left %s)" uu___1
  | BvRor n ->
      let uu___1 = FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
      FStarC_Format.fmt1 "(_ rotate_right %s)" uu___1
  | BvToNat -> "bv2int"
  | BvUext n ->
      let uu___1 = FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
      FStarC_Format.fmt1 "(_ zero_extend %s)" uu___1
  | BvNot -> "bvnot"
  | NatToBv n ->
      let uu___1 = FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
      FStarC_Format.fmt1 "(_ int2bv %s)" uu___1
  | Var s -> s
let weightToSmtStr (uu___ : Prims.int FStar_Pervasives_Native.option) :
  Prims.string=
  match uu___ with
  | FStar_Pervasives_Native.None -> ""
  | FStar_Pervasives_Native.Some i ->
      let uu___1 = FStarC_Class_Show.show FStarC_Class_Show.showable_int i in
      FStarC_Format.fmt1 ":weight %s\n" uu___1
let weightToSmt (uu___ : Prims.int FStar_Pervasives_Native.option) :
  FStar_Pprint.document Prims.list=
  match uu___ with
  | FStar_Pervasives_Native.None -> []
  | FStar_Pervasives_Native.Some i ->
      let uu___1 =
        let uu___2 =
          let uu___3 =
            let uu___4 =
              let uu___5 =
                FStarC_Class_Show.show FStarC_Class_Show.showable_int i in
              FStar_Pprint.doc_of_string uu___5 in
            FStar_Pprint.op_Hat_Slash_Hat
              (FStar_Pprint.doc_of_string ":weight") uu___4 in
          FStar_Pprint.group uu___3 in
        FStar_Pprint.nest Prims.int_one uu___2 in
      [uu___1]
let rec hash_of_term' (t : term') : Prims.string=
  match t with
  | Integer i -> i
  | String s -> s
  | Real r -> r
  | BoundV i ->
      let uu___ = FStarC_Class_Show.show FStarC_Class_Show.showable_int i in
      Prims.strcat "@" uu___
  | FreeV x ->
      let uu___ = let uu___1 = strSort (fv_sort x) in Prims.strcat ":" uu___1 in
      Prims.strcat (fv_name x) uu___
  | App (op1, tms) ->
      let uu___ =
        let uu___1 = op_to_string op1 in
        let uu___2 =
          let uu___3 =
            let uu___4 = FStarC_List.map hash_of_term tms in
            FStarC_String.concat " " uu___4 in
          Prims.strcat uu___3 ")" in
        Prims.strcat uu___1 uu___2 in
      Prims.strcat "(" uu___
  | Labeled (t1, uu___, uu___1) -> hash_of_term t1
  | Quant (qop1, pats, wopt, sorts, body) ->
      let uu___ =
        let uu___1 =
          let uu___2 =
            let uu___3 =
              let uu___4 = FStarC_List.map strSort sorts in
              FStarC_String.concat " " uu___4 in
            let uu___4 =
              let uu___5 =
                let uu___6 = hash_of_term body in
                let uu___7 =
                  let uu___8 =
                    let uu___9 = weightToSmtStr wopt in
                    let uu___10 =
                      let uu___11 =
                        let uu___12 =
                          let uu___13 =
                            FStarC_List.map
                              (fun pats1 ->
                                 let uu___14 =
                                   FStarC_List.map hash_of_term pats1 in
                                 FStarC_String.concat " " uu___14) pats in
                          FStarC_String.concat "; " uu___13 in
                        Prims.strcat uu___12 "))" in
                      Prims.strcat " " uu___11 in
                    Prims.strcat uu___9 uu___10 in
                  Prims.strcat " " uu___8 in
                Prims.strcat uu___6 uu___7 in
              Prims.strcat ")(! " uu___5 in
            Prims.strcat uu___3 uu___4 in
          Prims.strcat " (" uu___2 in
        Prims.strcat (qop_to_string qop1) uu___1 in
      Prims.strcat "(" uu___
  | Let (es, body) ->
      let uu___ =
        let uu___1 =
          let uu___2 = FStarC_List.map hash_of_term es in
          FStarC_String.concat " " uu___2 in
        let uu___2 =
          let uu___3 =
            let uu___4 = hash_of_term body in Prims.strcat uu___4 ")" in
          Prims.strcat ") " uu___3 in
        Prims.strcat uu___1 uu___2 in
      Prims.strcat "(let (" uu___
and hash_of_term (tm : term) : Prims.string= hash_of_term' tm.tm
let mkBoxFunctions (s : Prims.string) : (Prims.string * Prims.string)=
  (s, (Prims.strcat s "_proj_0"))
let boxIntFun : (Prims.string * Prims.string)= mkBoxFunctions "BoxInt"
let boxBoolFun : (Prims.string * Prims.string)= mkBoxFunctions "BoxBool"
let boxStringFun : (Prims.string * Prims.string)= mkBoxFunctions "BoxString"
let boxBitVecFun (sz : Prims.int) : (Prims.string * Prims.string)=
  let uu___ =
    let uu___1 = FStarC_Class_Show.show FStarC_Class_Show.showable_int sz in
    Prims.strcat "BoxBitVec" uu___1 in
  mkBoxFunctions uu___
let boxRealFun : (Prims.string * Prims.string)= mkBoxFunctions "BoxReal"
let isInjective (s : Prims.string) : Prims.bool=
  if (FStar_String.strlen s) >= (Prims.of_int 3)
  then
    let uu___ =
      let uu___1 = FStarC_String.substring s Prims.int_zero (Prims.of_int 3) in
      uu___1 = "Box" in
    (if uu___
     then
       let uu___1 =
         FStarC_List.existsML (fun c -> c = 46)
           (FStar_String.list_of_string s) in
       Prims.op_Negation uu___1
     else false)
  else false
let mk (t : term') (r : FStarC_Range_Type.t) : term=
  let uu___ = FStarC_Effect.mk_ref FStar_Pervasives_Native.None in
  { tm = t; freevars = uu___; rng = r }
let mkTrue (r : FStarC_Range_Type.t) : term= mk (App (TrueOp, [])) r
let mkFalse (r : FStarC_Range_Type.t) : term= mk (App (FalseOp, [])) r
let mkUnreachable : term=
  mk (App ((Var "Unreachable"), [])) FStarC_Range_Type.dummyRange
let mkInteger (i : Prims.string) (r : FStarC_Range_Type.t) : term=
  mk (Integer (FStarC_Util.ensure_decimal i)) r
let mkInteger' (i : Prims.int) (r : FStarC_Range_Type.t) : term=
  let uu___ = FStarC_Class_Show.show FStarC_Class_Show.showable_int i in
  mkInteger uu___ r
let mkReal (i : Prims.string) (r : FStarC_Range_Type.t) : term= mk (Real i) r
let mkBoundV (i : Prims.int) (r : FStarC_Range_Type.t) : term=
  mk (BoundV i) r
let mkFreeV (x : fv) (r : FStarC_Range_Type.t) : term= mk (FreeV x) r
let mkApp' (f : (op * term Prims.list)) (r : FStarC_Range_Type.t) : term=
  mk (App f) r
let mkApp (uu___ : (Prims.string * term Prims.list))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with | (s, args) -> mk (App ((Var s), args)) r
let mkNot (t : term) (r : FStarC_Range_Type.t) : term=
  match t.tm with
  | App (TrueOp, uu___) -> mkFalse r
  | App (FalseOp, uu___) -> mkTrue r
  | uu___ -> mkApp' (Not, [t]) r
let mkAnd (uu___ : (term * term)) (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      (match ((t1.tm), (t2.tm)) with
       | (App (TrueOp, uu___1), uu___2) -> t2
       | (uu___1, App (TrueOp, uu___2)) -> t1
       | (App (FalseOp, uu___1), uu___2) -> mkFalse r
       | (uu___1, App (FalseOp, uu___2)) -> mkFalse r
       | (App (And, ts1), App (And, ts2)) ->
           mkApp' (And, (FStarC_List.op_At ts1 ts2)) r
       | (uu___1, App (And, ts2)) -> mkApp' (And, (t1 :: ts2)) r
       | (App (And, ts1), uu___1) ->
           mkApp' (And, (FStarC_List.op_At ts1 [t2])) r
       | uu___1 -> mkApp' (And, [t1; t2]) r)
let mkOr (uu___ : (term * term)) (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      (match ((t1.tm), (t2.tm)) with
       | (App (TrueOp, uu___1), uu___2) -> mkTrue r
       | (uu___1, App (TrueOp, uu___2)) -> mkTrue r
       | (App (FalseOp, uu___1), uu___2) -> t2
       | (uu___1, App (FalseOp, uu___2)) -> t1
       | (App (Or, ts1), App (Or, ts2)) ->
           mkApp' (Or, (FStarC_List.op_At ts1 ts2)) r
       | (uu___1, App (Or, ts2)) -> mkApp' (Or, (t1 :: ts2)) r
       | (App (Or, ts1), uu___1) ->
           mkApp' (Or, (FStarC_List.op_At ts1 [t2])) r
       | uu___1 -> mkApp' (Or, [t1; t2]) r)
let mkImp (uu___ : (term * term)) (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      (match ((t1.tm), (t2.tm)) with
       | (uu___1, App (TrueOp, uu___2)) -> mkTrue r
       | (App (FalseOp, uu___1), uu___2) -> mkTrue r
       | (App (TrueOp, uu___1), uu___2) -> t2
       | (uu___1, App (Imp, t1'::t2'::[])) ->
           let uu___2 =
             let uu___3 = let uu___4 = mkAnd (t1, t1') r in [uu___4; t2'] in
             (Imp, uu___3) in
           mkApp' uu___2 r
       | uu___1 -> mkApp' (Imp, [t1; t2]) r)
let mk_bin_op (op1 : op) (uu___ : (term * term)) (r : FStarC_Range_Type.t) :
  term= match uu___ with | (t1, t2) -> mkApp' (op1, [t1; t2]) r
let mkMinus (t : term) (r : FStarC_Range_Type.t) : term=
  mkApp' (Minus, [t]) r
let mkNatToBv (sz : Prims.int) (t : term) (r : FStarC_Range_Type.t) : 
  term= mkApp' ((NatToBv sz), [t]) r
let mkBvUext (sz : Prims.int) (t : term) (r : FStarC_Range_Type.t) : 
  term= mkApp' ((BvUext sz), [t]) r
let mkBvNot (t : term) (r : FStarC_Range_Type.t) : term=
  mkApp' (BvNot, [t]) r
let mkBvToNat (t : term) (r : FStarC_Range_Type.t) : term=
  mkApp' (BvToNat, [t]) r
let mkBvAnd : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op BvAnd
let mkBvXor : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op BvXor
let mkBvOr : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op BvOr
let mkBvAdd : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op BvAdd
let mkBvSub : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op BvSub
let mkBvShl (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      let uu___1 =
        let uu___2 =
          let uu___3 = let uu___4 = mkNatToBv sz t2 r in [uu___4] in t1 ::
            uu___3 in
        (BvShl, uu___2) in
      mkApp' uu___1 r
let mkBvShr (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      let uu___1 =
        let uu___2 =
          let uu___3 = let uu___4 = mkNatToBv sz t2 r in [uu___4] in t1 ::
            uu___3 in
        (BvShr, uu___2) in
      mkApp' uu___1 r
let mkBvRol (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      (match t2.tm with
       | Integer n ->
           let uu___1 =
             let uu___2 =
               let uu___3 = FStarC_Util.int_of_string n in BvRol uu___3 in
             (uu___2, [t1]) in
           mkApp' uu___1 r
       | App
           (Var proj,
            {
              tm = App
                (Var box,
                 { tm = Integer n; freevars = uu___1; rng = uu___2;_}::[]);
              freevars = uu___3; rng = uu___4;_}::[])
           when (proj = "BoxInt_proj_0") && (box = "BoxInt") ->
           let uu___5 =
             let uu___6 =
               let uu___7 = FStarC_Util.int_of_string n in BvRol uu___7 in
             (uu___6, [t1]) in
           mkApp' uu___5 r
       | uu___1 ->
           let uu___2 =
             let uu___3 =
               let uu___4 = let uu___5 = mkNatToBv sz t2 r in [uu___5] in t1
                 :: uu___4 in
             (BvExtRol, uu___3) in
           mkApp' uu___2 r)
let mkBvRor (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      (match t2.tm with
       | Integer n ->
           let uu___1 =
             let uu___2 =
               let uu___3 = FStarC_Util.int_of_string n in BvRor uu___3 in
             (uu___2, [t1]) in
           mkApp' uu___1 r
       | App
           (Var proj,
            {
              tm = App
                (Var box,
                 { tm = Integer n; freevars = uu___1; rng = uu___2;_}::[]);
              freevars = uu___3; rng = uu___4;_}::[])
           when (proj = "BoxInt_proj_0") && (box = "BoxInt") ->
           let uu___5 =
             let uu___6 =
               let uu___7 = FStarC_Util.int_of_string n in BvRor uu___7 in
             (uu___6, [t1]) in
           mkApp' uu___5 r
       | uu___1 ->
           let uu___2 =
             let uu___3 =
               let uu___4 = let uu___5 = mkNatToBv sz t2 r in [uu___5] in t1
                 :: uu___4 in
             (BvExtRor, uu___3) in
           mkApp' uu___2 r)
let mkBvUdiv (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      let uu___1 =
        let uu___2 =
          let uu___3 = let uu___4 = mkNatToBv sz t2 r in [uu___4] in t1 ::
            uu___3 in
        (BvUdiv, uu___2) in
      mkApp' uu___1 r
let mkBvMod (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      let uu___1 =
        let uu___2 =
          let uu___3 = let uu___4 = mkNatToBv sz t2 r in [uu___4] in t1 ::
            uu___3 in
        (BvMod, uu___2) in
      mkApp' uu___1 r
let mkBvMul (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      let uu___1 =
        let uu___2 =
          let uu___3 = let uu___4 = mkNatToBv sz t2 r in [uu___4] in t1 ::
            uu___3 in
        (BvMul, uu___2) in
      mkApp' uu___1 r
let mkBvShl' (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with | (t1, t2) -> mkApp' (BvShl, [t1; t2]) r
let mkBvShr' (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with | (t1, t2) -> mkApp' (BvShr, [t1; t2]) r
let mkBvRol' (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with | (t1, t2) -> mkApp' (BvExtRol, [t1; t2]) r
let mkBvRor' (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with | (t1, t2) -> mkApp' (BvExtRor, [t1; t2]) r
let mkBvMul' (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with | (t1, t2) -> mkApp' (BvMul, [t1; t2]) r
let mkBvUdivUnsafe (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with | (t1, t2) -> mkApp' (BvUdiv, [t1; t2]) r
let mkBvModUnsafe (sz : Prims.int) (uu___ : (term * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with | (t1, t2) -> mkApp' (BvMod, [t1; t2]) r
let mkBvUlt : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op BvUlt
let mkIff : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op Iff
let mkEq (uu___ : (term * term)) (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (t1, t2) ->
      (match ((t1.tm), (t2.tm)) with
       | (App (Var f1, s1::[]), App (Var f2, s2::[])) when
           if f1 = f2 then isInjective f1 else false ->
           mk_bin_op Eq (s1, s2) r
       | uu___1 -> mk_bin_op Eq (t1, t2) r)
let mkLT : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op LT
let mkLTE : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op LTE
let mkGT : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op GT
let mkGTE : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op GTE
let mkAdd : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op Add
let mkSub : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op Sub
let mkDiv : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op Div
let mkRealDiv : (term * term) -> FStarC_Range_Type.t -> term=
  mk_bin_op RealDiv
let mkMul : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op Mul
let mkMod : (term * term) -> FStarC_Range_Type.t -> term= mk_bin_op Mod
let mkRealOfInt (t : term) (r : FStarC_Range_Type.t) : term=
  mkApp ("to_real", [t]) r
let mkITE (uu___ : (term * term * term)) (r : FStarC_Range_Type.t) : 
  term=
  match uu___ with
  | (t1, t2, t3) ->
      (match t1.tm with
       | App (TrueOp, uu___1) -> t2
       | App (FalseOp, uu___1) -> t3
       | uu___1 ->
           (match ((t2.tm), (t3.tm)) with
            | (App (TrueOp, uu___2), App (TrueOp, uu___3)) -> mkTrue r
            | (App (TrueOp, uu___2), uu___3) ->
                let uu___4 = let uu___5 = mkNot t1 t1.rng in (uu___5, t3) in
                mkImp uu___4 r
            | (uu___2, App (TrueOp, uu___3)) -> mkImp (t1, t2) r
            | (uu___2, uu___3) -> mkApp' (ITE, [t1; t2; t3]) r))
let mkCases (t : term Prims.list) (r : FStarC_Range_Type.t) : term=
  match t with
  | [] -> FStarC_Effect.failwith "Impos"
  | hd::tl -> FStarC_List.fold_left (fun out t1 -> mkAnd (out, t1) r) hd tl
let check_pattern_ok (t : term) : term FStar_Pervasives_Native.option=
  let rec aux t1 =
    match t1.tm with
    | Integer uu___ -> FStar_Pervasives_Native.None
    | String uu___ -> FStar_Pervasives_Native.None
    | Real uu___ -> FStar_Pervasives_Native.None
    | BoundV uu___ -> FStar_Pervasives_Native.None
    | FreeV uu___ -> FStar_Pervasives_Native.None
    | Let (tms, tm) -> aux_l (tm :: tms)
    | App (head, terms) ->
        let head_ok =
          match head with
          | Var uu___ -> true
          | TrueOp -> true
          | FalseOp -> true
          | Not -> false
          | And -> false
          | Or -> false
          | Imp -> false
          | Iff -> false
          | Eq -> false
          | LT -> true
          | LTE -> true
          | GT -> true
          | GTE -> true
          | Add -> true
          | Sub -> true
          | Div -> true
          | RealDiv -> true
          | Mul -> true
          | Minus -> true
          | Mod -> true
          | BvAnd -> false
          | BvXor -> false
          | BvOr -> false
          | BvAdd -> false
          | BvSub -> false
          | BvShl -> false
          | BvShr -> false
          | BvRol uu___ -> false
          | BvRor uu___ -> false
          | BvExtRol -> false
          | BvExtRor -> false
          | BvUdiv -> false
          | BvMod -> false
          | BvMul -> false
          | BvUlt -> false
          | BvUext uu___ -> false
          | BvNot -> false
          | NatToBv uu___ -> false
          | BvToNat -> false
          | ITE -> false in
        if Prims.op_Negation head_ok
        then FStar_Pervasives_Native.Some t1
        else aux_l terms
    | Labeled (t2, uu___, uu___1) -> aux t2
    | Quant uu___ -> FStar_Pervasives_Native.Some t1
  and aux_l ts =
    match ts with
    | [] -> FStar_Pervasives_Native.None
    | t1::ts1 ->
        (match aux t1 with
         | FStar_Pervasives_Native.Some t2 -> FStar_Pervasives_Native.Some t2
         | FStar_Pervasives_Native.None -> aux_l ts1) in
  aux t
let rec print_smt_term (t : term) : Prims.string=
  match t.tm with
  | Integer n -> FStarC_Format.fmt1 "(Integer %s)" n
  | String s -> FStarC_Format.fmt1 "(String %s)" s
  | Real r -> FStarC_Format.fmt1 "(Real %s)" r
  | BoundV n ->
      let uu___ = FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
      FStarC_Format.fmt1 "(BoundV %s)" uu___
  | FreeV fv1 -> FStarC_Format.fmt1 "(FreeV %s)" (fv_name fv1)
  | App (op1, l) ->
      let uu___ = op_to_string op1 in
      let uu___1 = print_smt_term_list l in
      FStarC_Format.fmt2 "(%s %s)" uu___ uu___1
  | Labeled (t1, r1, r2) ->
      let uu___ = FStarC_Errors_Msg.rendermsg r1 in
      let uu___1 = print_smt_term t1 in
      FStarC_Format.fmt2 "(Labeled '%s' %s)" uu___ uu___1
  | Quant (qop1, l, uu___, uu___1, t1) ->
      let uu___2 = print_smt_term_list_list l in
      let uu___3 = print_smt_term t1 in
      FStarC_Format.fmt3 "(%s %s %s)" (qop_to_string qop1) uu___2 uu___3
  | Let (es, body) ->
      let uu___ = print_smt_term_list es in
      let uu___1 = print_smt_term body in
      FStarC_Format.fmt2 "(let %s %s)" uu___ uu___1
and print_smt_term_list (l : term Prims.list) : Prims.string=
  let uu___ = FStarC_List.map print_smt_term l in
  FStarC_String.concat " " uu___
and print_smt_term_list_list (l : term Prims.list Prims.list) : Prims.string=
  FStarC_List.fold_left
    (fun s l1 ->
       let uu___ =
         let uu___1 =
           let uu___2 = print_smt_term_list l1 in Prims.strcat uu___2 " ] " in
         Prims.strcat "; [ " uu___1 in
       Prims.strcat s uu___) "" l
let mkQuant (r : FStarC_Range_Type.t) (check_pats : Prims.bool)
  (uu___ :
    (qop * term Prims.list Prims.list * Prims.int
      FStar_Pervasives_Native.option * sort Prims.list * term))
  : term=
  match uu___ with
  | (qop1, pats, wopt, vars, body) ->
      let all_pats_ok pats1 =
        if Prims.op_Negation check_pats
        then pats1
        else
          (let uu___1 =
             FStarC_Util.find_map pats1
               (fun x -> FStarC_Util.find_map x check_pattern_ok) in
           match uu___1 with
           | FStar_Pervasives_Native.None -> pats1
           | FStar_Pervasives_Native.Some p ->
               ((let uu___3 =
                   let uu___4 = print_smt_term p in
                   FStarC_Format.fmt1
                     "Pattern (%s) contains illegal symbols; dropping it"
                     uu___4 in
                 FStarC_Errors.log_issue FStarC_Class_HasRange.hasRange_range
                   r FStarC_Errors_Codes.Warning_SMTPatternIllFormed ()
                   (Obj.magic FStarC_Errors_Msg.is_error_message_string)
                   (Obj.magic uu___3));
                [])) in
      if Prims.uu___is_Nil vars
      then body
      else
        (match body.tm with
         | App (TrueOp, uu___1) -> body
         | uu___1 ->
             let uu___2 =
               let uu___3 =
                 let uu___4 = all_pats_ok pats in
                 (qop1, uu___4, wopt, vars, body) in
               Quant uu___3 in
             mk uu___2 r)
let mkLet (uu___ : (term Prims.list * term)) (r : FStarC_Range_Type.t) :
  term=
  match uu___ with
  | (es, body) ->
      if Prims.uu___is_Nil es then body else mk (Let (es, body)) r
let abstr (fvs1 : fv Prims.list) (t : term) : term=
  let nvars = FStarC_List.length fvs1 in
  let index_of fv1 =
    let uu___ = FStarC_Util.try_find_index (fv_eq fv1) fvs1 in
    match uu___ with
    | FStar_Pervasives_Native.None -> FStar_Pervasives_Native.None
    | FStar_Pervasives_Native.Some i ->
        FStar_Pervasives_Native.Some (nvars - (i + Prims.int_one)) in
  let rec aux ix t1 =
    let uu___ = FStarC_Effect.op_Bang t1.freevars in
    match uu___ with
    | FStar_Pervasives_Native.Some [] -> t1
    | uu___1 ->
        (match t1.tm with
         | Integer uu___2 -> t1
         | String uu___2 -> t1
         | Real uu___2 -> t1
         | BoundV uu___2 -> t1
         | FreeV x ->
             let uu___2 = index_of x in
             (match uu___2 with
              | FStar_Pervasives_Native.None -> t1
              | FStar_Pervasives_Native.Some i -> mkBoundV (i + ix) t1.rng)
         | App (op1, tms) ->
             let uu___2 =
               let uu___3 = FStarC_List.map (aux ix) tms in (op1, uu___3) in
             mkApp' uu___2 t1.rng
         | Labeled (t2, r1, r2) ->
             let uu___2 =
               let uu___3 = let uu___4 = aux ix t2 in (uu___4, r1, r2) in
               Labeled uu___3 in
             mk uu___2 t2.rng
         | Quant (qop1, pats, wopt, vars, body) ->
             let n = FStarC_List.length vars in
             let uu___2 =
               let uu___3 =
                 FStarC_List.map (FStarC_List.map (aux (ix + n))) pats in
               let uu___4 = aux (ix + n) body in
               (qop1, uu___3, wopt, vars, uu___4) in
             mkQuant t1.rng false uu___2
         | Let (es, body) ->
             let uu___2 =
               FStarC_List.fold_left
                 (fun uu___3 e ->
                    match uu___3 with
                    | (ix1, l) ->
                        let uu___4 = let uu___5 = aux ix1 e in uu___5 :: l in
                        ((ix1 + Prims.int_one), uu___4)) (ix, []) es in
             (match uu___2 with
              | (ix1, es_rev) ->
                  let uu___3 =
                    let uu___4 = aux ix1 body in
                    ((FStarC_List.rev es_rev), uu___4) in
                  mkLet uu___3 t1.rng)) in
  aux Prims.int_zero t
let inst (tms : term Prims.list) (t : term) : term=
  let tms1 = FStarC_List.rev tms in
  let n = FStarC_List.length tms1 in
  let rec aux shift t1 =
    match t1.tm with
    | Integer uu___ -> t1
    | String uu___ -> t1
    | Real uu___ -> t1
    | FreeV uu___ -> t1
    | BoundV i ->
        if (Prims.int_zero <= (i - shift)) && ((i - shift) < n)
        then FStarC_List.nth tms1 (i - shift)
        else t1
    | App (op1, tms2) ->
        let uu___ =
          let uu___1 = FStarC_List.map (aux shift) tms2 in (op1, uu___1) in
        mkApp' uu___ t1.rng
    | Labeled (t2, r1, r2) ->
        let uu___ =
          let uu___1 = let uu___2 = aux shift t2 in (uu___2, r1, r2) in
          Labeled uu___1 in
        mk uu___ t2.rng
    | Quant (qop1, pats, wopt, vars, body) ->
        let m = FStarC_List.length vars in
        let shift1 = shift + m in
        let uu___ =
          let uu___1 = FStarC_List.map (FStarC_List.map (aux shift1)) pats in
          let uu___2 = aux shift1 body in (qop1, uu___1, wopt, vars, uu___2) in
        mkQuant t1.rng false uu___
    | Let (es, body) ->
        let uu___ =
          FStarC_List.fold_left
            (fun uu___1 e ->
               match uu___1 with
               | (ix, es1) ->
                   let uu___2 = let uu___3 = aux shift e in uu___3 :: es1 in
                   ((shift + Prims.int_one), uu___2)) (shift, []) es in
        (match uu___ with
         | (shift1, es_rev) ->
             let uu___1 =
               let uu___2 = aux shift1 body in
               ((FStarC_List.rev es_rev), uu___2) in
             mkLet uu___1 t1.rng) in
  aux Prims.int_zero t
let subst (t : term) (fv1 : fv) (s : term) : term=
  let uu___ = abstr [fv1] t in inst [s] uu___
let mkQuant' (r : FStarC_Range_Type.t)
  (uu___ :
    (qop * term Prims.list Prims.list * Prims.int
      FStar_Pervasives_Native.option * fv Prims.list * term))
  : term=
  match uu___ with
  | (qop1, pats, wopt, vars, body) ->
      let uu___1 =
        let uu___2 = FStarC_List.map (FStarC_List.map (abstr vars)) pats in
        let uu___3 = FStarC_List.map fv_sort vars in
        let uu___4 = abstr vars body in (qop1, uu___2, wopt, uu___3, uu___4) in
      mkQuant r true uu___1
let mkForall (r : FStarC_Range_Type.t)
  (uu___ : (pat Prims.list Prims.list * fvs * term)) : term=
  match uu___ with
  | (pats, vars, body) ->
      mkQuant' r (Forall, pats, FStar_Pervasives_Native.None, vars, body)
let mkForall'' (r : FStarC_Range_Type.t)
  (uu___ :
    (pat Prims.list Prims.list * Prims.int FStar_Pervasives_Native.option *
      sort Prims.list * term))
  : term=
  match uu___ with
  | (pats, wopt, sorts, body) ->
      mkQuant r true (Forall, pats, wopt, sorts, body)
let mkForall' (r : FStarC_Range_Type.t)
  (uu___ :
    (pat Prims.list Prims.list * Prims.int FStar_Pervasives_Native.option *
      fvs * term))
  : term=
  match uu___ with
  | (pats, wopt, vars, body) -> mkQuant' r (Forall, pats, wopt, vars, body)
let mkExists (r : FStarC_Range_Type.t)
  (uu___ : (pat Prims.list Prims.list * fvs * term)) : term=
  match uu___ with
  | (pats, vars, body) ->
      mkQuant' r (Exists, pats, FStar_Pervasives_Native.None, vars, body)
let mkForallFlat (uu___ : (fvs * term)) : term=
  match uu___ with
  | (vars, body) ->
      (match body.tm with
       | Quant (Forall, pats, wopt, sorts, body') ->
           let closing =
             let uu___1 =
               FStarC_List.map (fun s -> FV ("ignore", s, true)) sorts in
             FStarC_List.op_At vars uu___1 in
           let uu___1 =
             let uu___2 =
               FStarC_List.map (FStarC_List.map (abstr closing)) pats in
             let uu___3 =
               let uu___4 = FStarC_List.map fv_sort vars in
               FStarC_List.op_At uu___4 sorts in
             let uu___4 = abstr closing body' in
             (Forall, uu___2, wopt, uu___3, uu___4) in
           mkQuant body.rng true uu___1
       | uu___1 -> mkForall body.rng ([], vars, body))
let mkLet' (uu___ : ((fv * term) Prims.list * term))
  (r : FStarC_Range_Type.t) : term=
  match uu___ with
  | (bindings, body) ->
      let uu___1 = FStarC_List.split bindings in
      (match uu___1 with
       | (vars, es) ->
           let uu___2 = let uu___3 = abstr vars body in (es, uu___3) in
           mkLet uu___2 r)
let norng : FStarC_Range_Type.range= FStarC_Range_Type.dummyRange
let mkDefineFun
  (uu___ : (Prims.string * fv Prims.list * sort * term * caption)) : 
  decl=
  match uu___ with
  | (nm, vars, s, tm, c) ->
      let uu___1 =
        let uu___2 = FStarC_List.map fv_sort vars in
        let uu___3 = abstr vars tm in (nm, uu___2, s, uu___3, c) in
      DefineFun uu___1
let constr_id_of_sort (sort1 : sort) : Prims.string=
  let uu___ = strSort sort1 in FStarC_Format.fmt1 "%s_constr_id" uu___
let fresh_token (uu___ : (term * fvs * sort)) (id : Prims.int) : decl=
  match uu___ with
  | (tok, univ_fvs, sort1) ->
      let tok_name =
        match tok.tm with
        | App (Var name, uu___1) -> name
        | uu___1 -> FStarC_Effect.failwith "Unexpected fresh token" in
      let a_name = Prims.strcat "fresh_token_" tok_name in
      let tm =
        let uu___1 =
          let uu___2 = mkInteger' id norng in
          let uu___3 =
            let uu___4 =
              let uu___5 = constr_id_of_sort sort1 in
              let uu___6 =
                let uu___7 =
                  let uu___8 =
                    let uu___9 =
                      FStarC_List.map (fun f -> mkFreeV f norng) univ_fvs in
                    (tok_name, uu___9) in
                  mkApp uu___8 norng in
                [uu___7] in
              (uu___5, uu___6) in
            mkApp uu___4 norng in
          (uu___2, uu___3) in
        mkEq uu___1 norng in
      let tm1 = mkForall norng ([[tok]], univ_fvs, tm) in
      let a =
        let uu___1 = free_top_level_names tm1 in
        {
          assumption_term = tm1;
          assumption_caption = (FStar_Pervasives_Native.Some "fresh token");
          assumption_name = (escape a_name);
          assumption_fact_ids = [];
          assumption_free_names = uu___1
        } in
      Assume a
let fresh_constructor (rng : FStarC_Range_Type.t)
  (uu___ : (Prims.string * sort Prims.list * sort * Prims.int)) : decl=
  match uu___ with
  | (name, arg_sorts, sort1, id) ->
      let id1 = FStarC_Class_Show.show FStarC_Class_Show.showable_int id in
      let bvars =
        FStarC_List.mapi
          (fun i s ->
             let uu___1 =
               let uu___2 =
                 let uu___3 =
                   let uu___4 =
                     FStarC_Class_Show.show FStarC_Class_Show.showable_int i in
                   Prims.strcat "x_" uu___4 in
                 (uu___3, s) in
               mk_fv uu___2 in
             mkFreeV uu___1 norng) arg_sorts in
      let bvar_names = FStarC_List.map fv_of_term bvars in
      let capp = mkApp (name, bvars) norng in
      let cid_app =
        let uu___1 = let uu___2 = constr_id_of_sort sort1 in (uu___2, [capp]) in
        mkApp uu___1 norng in
      let a_name = Prims.strcat "constructor_distinct_" name in
      let tm =
        let uu___1 =
          let uu___2 =
            let uu___3 =
              let uu___4 = mkInteger id1 norng in (uu___4, cid_app) in
            mkEq uu___3 norng in
          ([[capp]], bvar_names, uu___2) in
        mkForall rng uu___1 in
      let a =
        let uu___1 = free_top_level_names tm in
        {
          assumption_term = tm;
          assumption_caption =
            (FStar_Pervasives_Native.Some "Constructor distinct");
          assumption_name = (escape a_name);
          assumption_fact_ids = [];
          assumption_free_names = uu___1
        } in
      Assume a
let injective_constructor (rng : FStarC_Range_Type.t)
  (x : (Prims.string * constructor_field Prims.list * sort)) :
  decl Prims.list=
  let uu___ = x in
  match uu___ with
  | (name, fields, sort1) ->
      let n_bvars = FStarC_List.length fields in
      let bvar_name i =
        let uu___1 = FStarC_Class_Show.show FStarC_Class_Show.showable_int i in
        Prims.strcat "x_" uu___1 in
      let bvar_index i = n_bvars - (i + Prims.int_one) in
      let bvar i s =
        let uu___1 =
          let uu___2 = let uu___3 = bvar_name i in (uu___3, s) in
          mk_fv uu___2 in
        mkFreeV uu___1 in
      let bvars =
        FStarC_List.mapi
          (fun i f -> let uu___1 = bvar i f.field_sort in uu___1 norng)
          fields in
      let bvar_names = FStarC_List.map fv_of_term bvars in
      let capp = mkApp (name, bvars) norng in
      let uu___1 =
        FStarC_List.mapi
          (fun i uu___2 ->
             match uu___2 with
             | { field_name = name1; field_sort = s;
                 field_projectible = projectible;_} ->
                 if projectible
                 then
                   let cproj_app = mkApp (name1, [capp]) norng in
                   let proj_name =
                     DeclFun
                       (name1, [sort1], s,
                         (FStar_Pervasives_Native.Some "Projector")) in
                   let tm =
                     let uu___3 =
                       let uu___4 =
                         let uu___5 =
                           let uu___6 = let uu___7 = bvar i s in uu___7 norng in
                           (cproj_app, uu___6) in
                         mkEq uu___5 norng in
                       ([[capp]], bvar_names, uu___4) in
                     mkForall rng uu___3 in
                   let a =
                     let uu___3 = free_top_level_names tm in
                     {
                       assumption_term = tm;
                       assumption_caption =
                         (FStar_Pervasives_Native.Some "Projection inverse");
                       assumption_name =
                         (escape (Prims.strcat "projection_inverse_" name1));
                       assumption_fact_ids = [];
                       assumption_free_names = uu___3
                     } in
                   [proj_name; Assume a]
                 else []) fields in
      FStarC_List.flatten uu___1
let discriminator_name (constr : constructor_t) : Prims.string=
  Prims.strcat "is-" constr.constr_name
let constructor_to_decl (rng : FStarC_Range_Type.t) (constr : constructor_t)
  : decl Prims.list=
  let sort1 = constr.constr_sort in
  let field_sorts =
    FStarC_List.map (fun f -> f.field_sort) constr.constr_fields in
  let cdecl =
    DeclFun
      ((constr.constr_name), field_sorts, (constr.constr_sort),
        (FStar_Pervasives_Native.Some "Constructor")) in
  let cid =
    match constr.constr_id with
    | FStar_Pervasives_Native.None -> []
    | FStar_Pervasives_Native.Some id ->
        let uu___ =
          fresh_constructor rng
            ((constr.constr_name), field_sorts, sort1, id) in
        [uu___] in
  let disc =
    let disc_name = discriminator_name constr in
    let xfv = mk_fv ("x", sort1) in
    let xx = mkFreeV xfv norng in
    let uu___ =
      let uu___1 =
        FStarC_List.mapi
          (fun i uu___2 ->
             match uu___2 with
             | { field_name = proj; field_sort = s;
                 field_projectible = projectible;_} ->
                 if projectible
                 then let uu___3 = mkApp (proj, [xx]) norng in (uu___3, [])
                 else
                   (let fi =
                      let uu___3 =
                        let uu___4 =
                          let uu___5 =
                            FStarC_Class_Show.show
                              FStarC_Class_Show.showable_int i in
                          Prims.strcat "f_" uu___5 in
                        (uu___4, s) in
                      mk_fv uu___3 in
                    let uu___3 = mkFreeV fi norng in (uu___3, [fi])))
          constr.constr_fields in
      FStarC_List.split uu___1 in
    match uu___ with
    | (proj_terms, ex_vars) ->
        let ex_vars1 = FStarC_List.flatten ex_vars in
        let disc_inv_body =
          let uu___1 =
            let uu___2 = mkApp ((constr.constr_name), proj_terms) norng in
            (xx, uu___2) in
          mkEq uu___1 norng in
        let disc_inv_body1 =
          match ex_vars1 with
          | [] -> disc_inv_body
          | uu___1 -> mkExists norng ([], ex_vars1, disc_inv_body) in
        let disc_ax =
          match constr.constr_id with
          | FStar_Pervasives_Native.None -> disc_inv_body1
          | FStar_Pervasives_Native.Some id ->
              let disc_eq =
                let uu___1 =
                  let uu___2 =
                    let uu___3 =
                      let uu___4 = constr_id_of_sort constr.constr_sort in
                      (uu___4, [xx]) in
                    mkApp uu___3 norng in
                  let uu___3 =
                    let uu___4 =
                      FStarC_Class_Show.show FStarC_Class_Show.showable_int
                        id in
                    mkInteger uu___4 norng in
                  (uu___2, uu___3) in
                mkEq uu___1 norng in
              mkAnd (disc_eq, disc_inv_body1) norng in
        let def =
          mkDefineFun
            (disc_name, [xfv], Bool_sort, disc_ax,
              (FStar_Pervasives_Native.Some "Discriminator definition")) in
        def in
  let projs =
    injective_constructor rng
      ((constr.constr_name), (constr.constr_fields), sort1) in
  let base =
    if Prims.op_Negation constr.constr_base
    then []
    else
      (let arg_sorts =
         let uu___ =
           FStarC_List.filter (fun f -> f.field_projectible)
             constr.constr_fields in
         FStarC_List.map (fun f -> f.field_sort) uu___ in
       let base_name = Prims.strcat constr.constr_name "@base" in
       let decl1 =
         DeclFun
           (base_name, arg_sorts, Term_sort,
             (FStar_Pervasives_Native.Some "Constructor base")) in
       let formals =
         FStarC_List.mapi
           (fun i f ->
              let uu___ =
                let uu___1 =
                  let uu___2 =
                    FStarC_Class_Show.show FStarC_Class_Show.showable_int i in
                  Prims.strcat "x" uu___2 in
                (uu___1, (f.field_sort)) in
              mk_fv uu___) constr.constr_fields in
       let constructed_term =
         let uu___ =
           let uu___1 =
             FStarC_List.map (fun fv1 -> mkFreeV fv1 norng) formals in
           ((constr.constr_name), uu___1) in
         mkApp uu___ norng in
       let inj_formals =
         let uu___ =
           FStarC_List.map2
             (fun f fld -> if fld.field_projectible then [f] else []) formals
             constr.constr_fields in
         FStarC_List.flatten uu___ in
       let base_term =
         let uu___ =
           let uu___1 =
             FStarC_List.map (fun fv1 -> mkFreeV fv1 norng) inj_formals in
           (base_name, uu___1) in
         mkApp uu___ norng in
       let eq = mkEq (constructed_term, base_term) norng in
       let guard =
         mkApp ((discriminator_name constr), [constructed_term]) norng in
       let q =
         let uu___ =
           let uu___1 = mkImp (guard, eq) norng in
           ([[constructed_term]], formals, uu___1) in
         mkForall rng uu___ in
       let a =
         let uu___ = free_top_level_names q in
         {
           assumption_term = q;
           assumption_caption =
             (FStar_Pervasives_Native.Some "Constructor base");
           assumption_name =
             (escape (Prims.strcat "constructor_base_" constr.constr_name));
           assumption_fact_ids = [];
           assumption_free_names = uu___
         } in
       [decl1; Assume a]) in
  FStarC_List.op_At
    [Caption (FStarC_Format.fmt1 "<start constructor %s>" constr.constr_name);
    cdecl]
    (FStarC_List.op_At cid
       (FStarC_List.op_At projs
          (FStarC_List.op_At [disc]
             (FStarC_List.op_At base
                [Caption
                   (FStarC_Format.fmt1 "</end constructor %s>"
                      constr.constr_name)]))))
let name_binders_inner
  (prefix_opt : Prims.string FStar_Pervasives_Native.option)
  (outer_names : fv Prims.list) (start : Prims.int) (sorts : sort Prims.list)
  : (fv Prims.list * FStar_Pprint.document Prims.list * Prims.int)=
  let uu___ =
    FStarC_List.fold_left
      (fun uu___1 s ->
         match uu___1 with
         | (names, binders1, n) ->
             let prefix = match s with | Term_sort -> "@x" | uu___2 -> "@u" in
             let prefix1 =
               match prefix_opt with
               | FStar_Pervasives_Native.None -> prefix
               | FStar_Pervasives_Native.Some p -> Prims.strcat p prefix in
             let nm =
               let uu___2 =
                 FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
               Prims.strcat prefix1 uu___2 in
             let names1 = (mk_fv (nm, s)) :: names in
             let b =
               let uu___2 = let uu___3 = docSort s in [uu___3] in
               form nm uu___2 in
             (names1, (b :: binders1), (n + Prims.int_one)))
      (outer_names, [], start) sorts in
  match uu___ with
  | (names, binders1, n) -> (names, (FStarC_List.rev binders1), n)
let name_macro_binders (sorts : sort Prims.list) :
  (fv Prims.list * FStar_Pprint.document Prims.list)=
  let uu___ =
    name_binders_inner (FStar_Pervasives_Native.Some "__") [] Prims.int_zero
      sorts in
  match uu___ with
  | (names, binders1, n) -> ((FStarC_List.rev names), binders1)
let mk_tag (f : FStar_Pprint.document)
  (attrs : FStar_Pprint.document Prims.list) : FStar_Pprint.document=
  form_core ((FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string "! ") f) ::
    attrs)
let termToSmt : Prims.bool -> Prims.string -> term -> FStar_Pprint.document=
  let string_id_counter = FStarC_Effect.mk_ref Prims.int_zero in
  let string_cache = FStarC_SMap.create (Prims.of_int 20) in
  fun print_ranges enclosing_name t ->
    let next_qid =
      let ctr = FStarC_Effect.mk_ref Prims.int_zero in
      fun depth ->
        let n = FStarC_Effect.op_Bang ctr in
        FStarC_Util.incr ctr;
        if n = Prims.int_zero
        then enclosing_name
        else
          (let uu___1 =
             FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
           FStarC_Format.fmt2 "%s.%s" enclosing_name uu___1) in
    let remove_guard_free pats =
      FStarC_List.map
        (fun ps ->
           FStarC_List.map
             (fun tm ->
                match tm.tm with
                | App
                    (Var "Prims.guard_free",
                     { tm = BoundV uu___; freevars = uu___1; rng = uu___2;_}::[])
                    -> tm
                | App (Var "Prims.guard_free", p::[]) -> p
                | uu___ -> tm) ps) pats in
    let rec aux' depth n names t1 =
      let aux1 = aux (depth + Prims.int_one) in
      match t1.tm with
      | Integer i -> FStar_Pprint.doc_of_string i
      | Real r -> FStar_Pprint.doc_of_string r
      | String s ->
          let id_opt = FStarC_SMap.try_find string_cache s in
          let uu___ =
            match id_opt with
            | FStar_Pervasives_Native.Some id -> id
            | FStar_Pervasives_Native.None ->
                let id =
                  let uu___1 = FStarC_Effect.op_Bang string_id_counter in
                  FStarC_Class_Show.show FStarC_Class_Show.showable_int
                    uu___1 in
                (FStarC_Util.incr string_id_counter;
                 FStarC_SMap.add string_cache s id;
                 id) in
          FStar_Pprint.doc_of_string uu___
      | BoundV i ->
          FStar_Pprint.doc_of_string (fv_name (FStarC_List.nth names i))
      | FreeV x when fv_force x ->
          form (fv_name x) [FStar_Pprint.doc_of_string "Dummy_value"]
      | FreeV x -> FStar_Pprint.doc_of_string (fv_name x)
      | App (op1, []) ->
          let uu___ = op_to_string op1 in FStar_Pprint.doc_of_string uu___
      | App (op1, tms) ->
          let uu___ = op_to_string op1 in
          let uu___1 = FStarC_List.map (aux1 n names) tms in
          form uu___ uu___1
      | Labeled (t2, uu___, uu___1) -> aux1 n names t2
      | Quant (qop1, pats, wopt, sorts, body) ->
          let qid = next_qid () in
          let uu___ =
            name_binders_inner FStar_Pervasives_Native.None names n sorts in
          (match uu___ with
           | (names1, binders1, n1) ->
               let pats1 = remove_guard_free pats in
               let pats_str =
                 match pats1 with
                 | []::[] -> []
                 | [] -> []
                 | uu___1 ->
                     FStarC_List.map
                       (fun pats2 ->
                          let uu___2 =
                            let uu___3 =
                              FStarC_List.map (aux1 n1 names1) pats2 in
                            form_core uu___3 in
                          mk_pattern uu___2) pats1 in
               let uu___1 =
                 let uu___2 =
                   let uu___3 = aux1 n1 names1 body in
                   let uu___4 =
                     let uu___5 = weightToSmt wopt in
                     FStarC_List.op_At uu___5
                       (FStarC_List.op_At pats_str [mk_qid qid]) in
                   mk_tag uu___3 uu___4 in
                 [uu___2] in
               binder (qop_to_string qop1) (form_core binders1) uu___1)
      | Let (es, body) ->
          let uu___ =
            FStarC_List.fold_left
              (fun uu___1 e ->
                 match uu___1 with
                 | (names0, binders1, n0) ->
                     let nm =
                       let uu___2 =
                         FStarC_Class_Show.show
                           FStarC_Class_Show.showable_int n0 in
                       Prims.strcat "@lb" uu___2 in
                     let names01 = (mk_fv (nm, Term_sort)) :: names0 in
                     let b =
                       let uu___2 = let uu___3 = aux1 n names e in [uu___3] in
                       form nm uu___2 in
                     (names01, (b :: binders1), (n0 + Prims.int_one)))
              (names, [], n) es in
          (match uu___ with
           | (names1, binders1, n1) ->
               let uu___1 = let uu___2 = aux1 n1 names1 body in [uu___2] in
               binder "let" (form_core binders1) uu___1)
    and aux depth n names t1 =
      let s = aux' depth n names t1 in
      if print_ranges && (t1.rng <> norng)
      then
        let uu___ =
          let uu___1 =
            let uu___2 = FStarC_Range_Ops.string_of_range t1.rng in
            FStar_Pprint.doc_of_string uu___2 in
          let uu___2 =
            let uu___3 =
              let uu___4 =
                let uu___5 = FStarC_Range_Ops.string_of_use_range t1.rng in
                FStar_Pprint.doc_of_string uu___5 in
              FStar_Pprint.op_Hat_Hat uu___4
                (FStar_Pprint.op_Hat_Hat FStar_Pprint.hardline s) in
            FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string "; use=")
              uu___3 in
          FStar_Pprint.op_Hat_Hat uu___1 uu___2 in
        FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string ";; def=") uu___
      else s in
    aux Prims.int_zero Prims.int_zero [] t
let rec declToSmt' (print_captions : Prims.bool) (z3options : Prims.string)
  (decl1 : decl) : FStar_Pprint.document=
  let with_caption c body =
    match c with
    | FStar_Pervasives_Native.Some c1 when print_captions ->
        let c2 =
          let uu___ =
            FStarC_List.map FStarC_Util.trim_string
              (FStarC_String.split [10] c1) in
          FStarC_String.concat " " uu___ in
        FStar_Pprint.op_Hat_Hat
          (FStar_Pprint.doc_of_string (Prims.strcat "; " c2))
          (FStar_Pprint.op_Hat_Hat FStar_Pprint.hardline body)
    | uu___ -> body in
  match decl1 with
  | DefPrelude ->
      let uu___ = mkPrelude z3options in FStar_Pprint.doc_of_string uu___
  | Module (s, decls) ->
      let res =
        FStarC_Pprint.separate_map FStar_Pprint.hardline
          (declToSmt' print_captions z3options) decls in
      let uu___ = FStarC_Options.keep_query_captions () in
      if uu___
      then
        let uu___1 =
          let uu___2 =
            let uu___3 =
              let uu___4 =
                let uu___5 =
                  let uu___6 =
                    let uu___7 =
                      let uu___8 =
                        let uu___9 =
                          let uu___10 =
                            let uu___11 =
                              FStarC_Class_Show.show
                                FStarC_Class_Show.showable_nat
                                (FStarC_List.length decls) in
                            FStar_Pprint.doc_of_string uu___11 in
                          FStar_Pprint.op_Hat_Hat uu___10
                            (FStar_Pprint.doc_of_string " decls") in
                        FStar_Pprint.parens uu___9 in
                      FStar_Pprint.op_Hat_Hat uu___8 FStar_Pprint.hardline in
                    FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string s)
                      uu___7 in
                  FStar_Pprint.op_Hat_Hat
                    (FStar_Pprint.doc_of_string ";;; End ") uu___6 in
                FStar_Pprint.op_Hat_Hat FStar_Pprint.hardline uu___5 in
              FStar_Pprint.op_Hat_Hat res uu___4 in
            FStar_Pprint.op_Hat_Hat FStar_Pprint.hardline uu___3 in
          FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string s) uu___2 in
        FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string ";;; Start ")
          uu___1
      else res
  | Caption c ->
      if print_captions
      then
        FStarC_Pprint.separate_map FStar_Pprint.hardline
          (fun s -> FStar_Pprint.doc_of_string (Prims.strcat "; " s))
          (FStarC_Util.splitlines c)
      else FStar_Pprint.empty
  | DeclFun (f, argsorts, retsort, c) ->
      let uu___ =
        let uu___1 =
          let uu___2 =
            let uu___3 =
              let uu___4 = FStarC_List.map docSort argsorts in
              form_core uu___4 in
            let uu___4 = let uu___5 = docSort retsort in [uu___5] in uu___3
              :: uu___4 in
          (FStar_Pprint.doc_of_string f) :: uu___2 in
        form "declare-fun" uu___1 in
      with_caption c uu___
  | DefineFun (f, arg_sorts, retsort, body, c) ->
      let uu___ = name_macro_binders arg_sorts in
      (match uu___ with
       | (names, binders1) ->
           let body1 =
             let uu___1 = FStarC_List.map (fun x -> mkFreeV x norng) names in
             inst uu___1 body in
           let uu___1 =
             let uu___2 =
               let uu___3 =
                 let uu___4 =
                   let uu___5 =
                     let uu___6 =
                       let uu___7 =
                         let uu___8 =
                           let uu___9 =
                             let uu___10 = docSort retsort in [uu___10] in
                           (form_core binders1) :: uu___9 in
                         (FStar_Pprint.doc_of_string f) :: uu___8 in
                       (FStar_Pprint.doc_of_string "define-fun") :: uu___7 in
                     FStar_Pprint.separate
                       (FStar_Pprint.break_ Prims.int_one) uu___6 in
                   FStar_Pprint.nest Prims.int_one uu___5 in
                 FStar_Pprint.group uu___4 in
               let uu___4 =
                 let uu___5 = termToSmt print_captions (escape f) body1 in
                 [uu___5] in
               uu___3 :: uu___4 in
             form_core uu___2 in
           with_caption c uu___1)
  | Assume a ->
      let fact_ids_to_string ids =
        FStarC_List.map
          (fun uu___ ->
             match uu___ with
             | Name n -> Prims.strcat "Name " (FStarC_Ident.string_of_lid n)
             | Namespace ns ->
                 Prims.strcat "Namespace " (FStarC_Ident.string_of_lid ns)
             | Tag t -> Prims.strcat "Tag " t) ids in
      let fids =
        if print_captions
        then
          let uu___ =
            let uu___1 = fact_ids_to_string a.assumption_fact_ids in
            FStarC_String.concat "; " uu___1 in
          FStarC_Format.fmt1 ";;; Fact-ids: %s\n" uu___
        else "" in
      let n = a.assumption_name in
      let uu___ =
        let uu___1 =
          let uu___2 =
            let uu___3 =
              let uu___4 = termToSmt print_captions n a.assumption_term in
              mk_tag uu___4 [mk_named n] in
            [uu___3] in
          form "assert" uu___2 in
        FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string fids) uu___1 in
      with_caption a.assumption_caption uu___
  | Eval t ->
      let uu___ = let uu___1 = termToSmt print_captions "eval" t in [uu___1] in
      form "eval" uu___
  | Echo s ->
      form "echo"
        [FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string "\"")
           (FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string s)
              (FStar_Pprint.doc_of_string "\""))]
  | RetainAssumptions uu___ -> FStar_Pprint.empty
  | CheckSat ->
      FStar_Pprint.doc_of_string
        "(echo \"<result>\")\n(check-sat)\n(echo \"</result>\")"
  | GetUnsatCore ->
      FStar_Pprint.doc_of_string
        "(echo \"<unsat-core>\")\n(get-unsat-core)\n(echo \"</unsat-core>\")"
  | EmptyLine -> FStar_Pprint.empty
  | Push n ->
      let uu___ =
        let uu___1 = FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
        FStar_Pprint.doc_of_string uu___1 in
      FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string "(push) ;; push{")
        uu___
  | Pop n ->
      let uu___ =
        let uu___1 =
          let uu___2 =
            FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
          FStar_Pprint.doc_of_string uu___2 in
        FStar_Pprint.op_Hat_Hat uu___1 (FStar_Pprint.doc_of_string "}pop") in
      FStar_Pprint.op_Hat_Hat (FStar_Pprint.doc_of_string "(pop) ;; ") uu___
  | SetOption (s, v) ->
      form "set-option"
        [FStar_Pprint.doc_of_string (Prims.strcat ":" s);
        FStar_Pprint.doc_of_string v]
  | GetStatistics ->
      FStar_Pprint.doc_of_string
        "(echo \"<statistics>\") (get-info :all-statistics) (echo \"</statistics>\")"
  | GetReasonUnknown ->
      FStar_Pprint.doc_of_string
        "(echo \"<reason-unknown>\") (get-info :reason-unknown) (echo \"</reason-unknown>\")"
and declToSmt (z3options : Prims.string) (decl1 : decl) : Prims.string=
  let uu___ =
    let uu___1 = FStarC_Options.keep_query_captions () in
    declToSmt' uu___1 z3options decl1 in
  render uu___
and mkPrelude (z3options : Prims.string) : Prims.string=
  let basic =
    Prims.strcat z3options
      "(declare-sort FString)\n(declare-fun FString_constr_id (FString) Int)\n\n(declare-sort Term)\n(declare-sort Universe)\n(declare-fun U_zero () Universe)\n(declare-fun U_succ (Universe) Universe)\n(declare-fun ulevel ((Universe)) Int)\n(declare-fun Univ (Int) Universe)\n(assert (= (ulevel U_zero) 0))\n(assert (forall ((u Universe)) (! (= (ulevel (U_succ u)) (+ 1 (ulevel u))) :pattern ((ulevel (U_succ u))))))\n(assert (forall ((u Universe)) (! (>= (ulevel u) 0) :pattern ((ulevel u)))))\n(assert (forall ((u Universe)) (! (= (Univ (ulevel u)) u) :pattern ((ulevel u)))))\n(assert (forall ((i Int)) (! (implies (>= i 0) (= (ulevel (Univ i)) i)) :pattern ((Univ i)))))\n(declare-fun U_max (Universe Universe) Universe)\n(assert (forall ((u1 Universe) (u2 Universe))\n(! (= (U_max u1 u2)\n(ite (<= (ulevel u1) (ulevel u2)) u2 u1))\n:pattern ((U_max u1 u2)))))\n(declare-fun U_unif (Int) Universe)\n(declare-fun U_unknown () Universe)\n(declare-fun Term_constr_id (Term) Int)\n(declare-sort Dummy_sort)\n(declare-fun Dummy_value () Dummy_sort)\n(declare-datatypes () ((Fuel \n(ZFuel) \n(SFuel (prec Fuel)))))\n(declare-fun MaxIFuel () Fuel)\n(declare-fun MaxFuel () Fuel)\n(declare-fun PreType (Term) Term)\n(declare-fun Valid (Term) Bool)\n(declare-fun HasTypeFuel (Fuel Term Term) Bool)\n(define-fun HasTypeZ ((x Term) (t Term)) Bool\n(HasTypeFuel ZFuel x t))\n(define-fun HasType ((x Term) (t Term)) Bool\n(HasTypeFuel MaxIFuel x t))\n(declare-fun IsTotFun (Term) Bool)\n\n                ;;fuel irrelevance\n(assert (forall ((f Fuel) (x Term) (t Term))\n(! (= (HasTypeFuel (SFuel f) x t)\n(HasTypeZ x t))\n:pattern ((HasTypeFuel (SFuel f) x t)))))\n(declare-fun NoHoist (Term Bool) Bool)\n;;no-hoist\n(assert (forall ((dummy Term) (b Bool))\n(! (= (NoHoist dummy b) b)\n:pattern ((NoHoist dummy b)))))\n(define-fun  IsTyped ((x Term)) Bool\n(exists ((t Term)) (HasTypeZ x t)))\n(declare-fun ApplyTF (Term Fuel) Term)\n(declare-fun ApplyTT (Term Term) Term)\n(declare-fun Prec (Term Term) Bool)\n(assert (forall ((x Term) (y Term) (z Term))\n(! (implies (and (Prec x y) (Prec y z)) (Prec x z))\n:pattern ((Prec x z) (Prec x y)))))\n(assert (forall ((x Term) (y Term))\n(implies (Prec x y)\n(not (Prec y x)))))\n(declare-fun Closure (Term) Term)\n(declare-fun ConsTerm (Term Term) Term)\n(declare-fun ConsFuel (Fuel Term) Term)\n(declare-fun Tm_uvar (Int) Term)\n(define-fun Reify ((x Term)) Term x)\n(declare-fun Prims.precedes (Universe Universe Term Term Term Term) Term)\n(declare-fun Range_const (Int) Term)\n(declare-fun _mul (Int Int) Int)\n(declare-fun _div (Int Int) Int)\n(declare-fun _mod (Int Int) Int)\n(declare-fun __uu__PartialApp () Term)\n(assert (forall ((x Int) (y Int)) (! (= (_mul x y) (* x y)) :pattern ((_mul x y)))))\n(assert (forall ((x Int) (y Int)) (! (= (_div x y) (div x y)) :pattern ((_div x y)))))\n(assert (forall ((x Int) (y Int)) (! (= (_mod x y) (mod x y)) :pattern ((_mod x y)))))\n(declare-fun _rmul (Real Real) Real)\n(declare-fun _rdiv (Real Real) Real)\n(assert (forall ((x Real) (y Real)) (! (= (_rmul x y) (* x y)) :pattern ((_rmul x y)))))\n(assert (forall ((x Real) (y Real)) (! (= (_rdiv x y) (/ x y)) :pattern ((_rdiv x y)))))\n(define-fun Unreachable () Bool false)" in
  let as_constr x =
    let uu___ = x in
    match uu___ with
    | (name, fields, sort1, id, _injective) ->
        let uu___1 =
          FStarC_List.map
            (fun uu___2 ->
               match uu___2 with
               | (field_name, field_sort, field_projectible) ->
                   { field_name; field_sort; field_projectible }) fields in
        {
          constr_name = name;
          constr_fields = uu___1;
          constr_sort = sort1;
          constr_id = (FStar_Pervasives_Native.Some id);
          constr_base = false
        } in
  let constrs =
    FStarC_List.map as_constr
      [("FString_const", [("FString_const_proj_0", Int_sort, true)],
         String_sort, Prims.int_zero, true);
      ("Tm_type", [("Tm_type_0", (Sort "Universe"), true)], Term_sort,
        (Prims.of_int 2), true);
      ("Tm_arrow", [("Tm_arrow_id", Int_sort, true)], Term_sort,
        (Prims.of_int 3), false);
      ("Tm_unit", [], Term_sort, (Prims.of_int 6), true);
      ((FStar_Pervasives_Native.fst boxIntFun),
        [((FStar_Pervasives_Native.snd boxIntFun), Int_sort, true)],
        Term_sort, (Prims.of_int 7), true);
      ((FStar_Pervasives_Native.fst boxBoolFun),
        [((FStar_Pervasives_Native.snd boxBoolFun), Bool_sort, true)],
        Term_sort, (Prims.of_int 8), true);
      ((FStar_Pervasives_Native.fst boxStringFun),
        [((FStar_Pervasives_Native.snd boxStringFun), String_sort, true)],
        Term_sort, (Prims.of_int 9), true);
      ((FStar_Pervasives_Native.fst boxRealFun),
        [((FStar_Pervasives_Native.snd boxRealFun), (Sort "Real"), true)],
        Term_sort, (Prims.of_int 10), true);
      ("LexCons",
        [("LexCons_0", Term_sort, true);
        ("LexCons_1", Term_sort, true);
        ("LexCons_2", Term_sort, true)], Term_sort, (Prims.of_int 11), true)] in
  let bcons =
    let uu___ =
      let uu___1 = FStarC_List.collect (constructor_to_decl norng) constrs in
      FStarC_List.map (declToSmt z3options) uu___1 in
    FStarC_String.concat "\n" uu___ in
  let precedes_partial_app =
    "\n(declare-fun Prims.precedes@tok (Universe Universe) Term)\n(assert\n(forall ((u0 Universe) (u1 Universe) (@x0 Term) (@x1 Term) (@x2 Term) (@x3 Term))\n(! (= (ApplyTT (ApplyTT (ApplyTT (ApplyTT (Prims.precedes@tok u0 u1) @x0) @x1) @x2) @x3)\n(Prims.precedes u0 u1 @x0 @x1 @x2 @x3))\n:pattern ((ApplyTT (ApplyTT (ApplyTT (ApplyTT (Prims.precedes@tok u0 u1) @x0) @x1) @x2) @x3)))))\n" in
  let lex_ordering =
    "\n(define-fun is-Prims.LexCons ((t Term)) Bool \n(is-LexCons t))\n(declare-fun Prims.lex_t () Term)\n(declare-fun LexTop () Term)\n(assert (forall ((u0 Universe) (u1 Universe) (t1 Term) (t2 Term) (x1 Term) (x2 Term) (y1 Term) (y2 Term))\n(iff (Valid (Prims.precedes u0 u1 Prims.lex_t Prims.lex_t (LexCons t1 x1 x2) (LexCons t2 y1 y2)))\n(or (Valid (Prims.precedes u0 u1 t1 t2 x1 y1))\n(and (= x1 y1)\n(Valid (Prims.precedes u0 u1 Prims.lex_t Prims.lex_t x2 y2)))))))\n(assert (forall ((u0 Universe) (u1 Universe) (t1 Term) (t2 Term) (e1 Term) (e2 Term))\n(! (iff (Valid (Prims.precedes u0 u1 t1 t2 e1 e2))\n(Valid (Prims.precedes U_zero U_zero Prims.lex_t Prims.lex_t e1 e2)))\n:pattern (Prims.precedes u0 u1 t1 t2 e1 e2))))\n(assert (forall ((u0 Universe) (u1 Universe) (t1 Term) (t2 Term))\n(! (iff (Valid (Prims.precedes u0 u1 Prims.lex_t Prims.lex_t t1 t2)) \n(Prec t1 t2))\n:pattern ((Prims.precedes u0 u1 Prims.lex_t Prims.lex_t t1 t2)))))\n" in
  let tm_type_typing =
    "(assert (forall ((u Universe) (t Term))\n(! (iff (HasType (Tm_type u) t)\n(= t (Tm_type (U_succ u))))\n:pattern ((HasType (Tm_type u) t)))))\n" in
  Prims.strcat basic
    (Prims.strcat bcons
       (Prims.strcat precedes_partial_app
          (Prims.strcat lex_ordering tm_type_typing)))
let declsToSmt (z3options : Prims.string) (decls : decl Prims.list) :
  Prims.string=
  let uu___ = FStarC_List.map (declToSmt z3options) decls in
  FStarC_String.concat "\n" uu___
let declToSmt_no_caps (z3options : Prims.string) (decl1 : decl) :
  Prims.string= let uu___ = declToSmt' false z3options decl1 in render uu___
let mkBvConstructor (sz : Prims.int) :
  (decl Prims.list * Prims.string * Prims.string)=
  let constr =
    let uu___ =
      let uu___1 = boxBitVecFun sz in FStar_Pervasives_Native.fst uu___1 in
    let uu___1 =
      let uu___2 =
        let uu___3 =
          let uu___4 = boxBitVecFun sz in FStar_Pervasives_Native.snd uu___4 in
        {
          field_name = uu___3;
          field_sort = (BitVec_sort sz);
          field_projectible = true
        } in
      [uu___2] in
    {
      constr_name = uu___;
      constr_fields = uu___1;
      constr_sort = Term_sort;
      constr_id = FStar_Pervasives_Native.None;
      constr_base = false
    } in
  let uu___ = constructor_to_decl norng constr in
  (uu___, (constr.constr_name), (discriminator_name constr))
let __range_c : Prims.int FStarC_Effect.ref=
  FStarC_Effect.mk_ref Prims.int_zero
let mk_Range_const (uu___ : unit) : term=
  let i = FStarC_Effect.op_Bang __range_c in
  (let uu___2 =
     let uu___3 = FStarC_Effect.op_Bang __range_c in uu___3 + Prims.int_one in
   FStarC_Effect.op_Colon_Equals __range_c uu___2);
  (let uu___2 =
     let uu___3 = let uu___4 = mkInteger' i norng in [uu___4] in
     ("Range_const", uu___3) in
   mkApp uu___2 norng)
let univ_sort : sort= Sort "Universe"
let mk_U_zero : term= mkApp ("U_zero", []) norng
let mk_U_succ (u : term) : term= mkApp ("U_succ", [u]) norng
let mk_U_max (t0 : term) (t1 : term) : term= mkApp ("U_max", [t0; t1]) norng
let mk_U_name (s : Prims.string) : term= mkFreeV (mk_fv (s, univ_sort)) norng
let mk_U_unif (i : term) : term= mkApp ("U_unif", [i]) norng
let mk_U_unknown : term= mkApp ("U_unknown", []) norng
let mk_Term_type (u : term) : term= mkApp ("Tm_type", [u]) norng
let mk_Term_app (t1 : term) (t2 : term) (r : FStarC_Range_Type.t) : term=
  mkApp ("Tm_app", [t1; t2]) r
let mk_Term_uvar (i : Prims.int) (r : FStarC_Range_Type.t) : term=
  let uu___ =
    let uu___1 = let uu___2 = mkInteger' i norng in [uu___2] in
    ("Tm_uvar", uu___1) in
  mkApp uu___ r
let mk_Term_unit : term= mkApp ("Tm_unit", []) norng
let elim_box (cond : Prims.bool) (u : Prims.string) (v : Prims.string)
  (t : term) : term=
  match t.tm with
  | App (Var v', t1::[]) when (v = v') && cond -> t1
  | uu___ -> mkApp (u, [t]) t.rng
let maybe_elim_box (u : Prims.string) (v : Prims.string) (t : term) : 
  term=
  let uu___ = FStarC_Options.smtencoding_elim_box () in elim_box uu___ u v t
let boxInt (t : term) : term=
  maybe_elim_box (FStar_Pervasives_Native.fst boxIntFun)
    (FStar_Pervasives_Native.snd boxIntFun) t
let unboxInt (t : term) : term=
  maybe_elim_box (FStar_Pervasives_Native.snd boxIntFun)
    (FStar_Pervasives_Native.fst boxIntFun) t
let boxBool (t : term) : term=
  maybe_elim_box (FStar_Pervasives_Native.fst boxBoolFun)
    (FStar_Pervasives_Native.snd boxBoolFun) t
let unboxBool (t : term) : term=
  maybe_elim_box (FStar_Pervasives_Native.snd boxBoolFun)
    (FStar_Pervasives_Native.fst boxBoolFun) t
let boxString (t : term) : term=
  maybe_elim_box (FStar_Pervasives_Native.fst boxStringFun)
    (FStar_Pervasives_Native.snd boxStringFun) t
let unboxString (t : term) : term=
  maybe_elim_box (FStar_Pervasives_Native.snd boxStringFun)
    (FStar_Pervasives_Native.fst boxStringFun) t
let boxReal (t : term) : term=
  maybe_elim_box (FStar_Pervasives_Native.fst boxRealFun)
    (FStar_Pervasives_Native.snd boxRealFun) t
let unboxReal (t : term) : term=
  maybe_elim_box (FStar_Pervasives_Native.snd boxRealFun)
    (FStar_Pervasives_Native.fst boxRealFun) t
let boxBitVec (sz : Prims.int) (t : term) : term=
  let uu___ =
    let uu___1 = boxBitVecFun sz in FStar_Pervasives_Native.fst uu___1 in
  let uu___1 =
    let uu___2 = boxBitVecFun sz in FStar_Pervasives_Native.snd uu___2 in
  elim_box true uu___ uu___1 t
let unboxBitVec (sz : Prims.int) (t : term) : term=
  let uu___ =
    let uu___1 = boxBitVecFun sz in FStar_Pervasives_Native.snd uu___1 in
  let uu___1 =
    let uu___2 = boxBitVecFun sz in FStar_Pervasives_Native.fst uu___2 in
  elim_box true uu___ uu___1 t
let boxTerm (sort1 : sort) (t : term) : term=
  match sort1 with
  | Int_sort -> boxInt t
  | Bool_sort -> boxBool t
  | String_sort -> boxString t
  | BitVec_sort sz -> boxBitVec sz t
  | Sort "Real" -> boxReal t
  | uu___ -> FStarC_Effect.raise FStarC_Util.Impos
let unboxTerm (sort1 : sort) (t : term) : term=
  match sort1 with
  | Int_sort -> unboxInt t
  | Bool_sort -> unboxBool t
  | String_sort -> unboxString t
  | BitVec_sort sz -> unboxBitVec sz t
  | Sort "Real" -> unboxReal t
  | uu___ -> FStarC_Effect.raise FStarC_Util.Impos
let getBoxedInteger (t : term) : Prims.int FStar_Pervasives_Native.option=
  match t.tm with
  | App (Var s, t2::[]) when s = (FStar_Pervasives_Native.fst boxIntFun) ->
      (match t2.tm with
       | Integer n ->
           let uu___ = FStarC_Util.int_of_string n in
           FStar_Pervasives_Native.Some uu___
       | uu___ -> FStar_Pervasives_Native.None)
  | uu___ -> FStar_Pervasives_Native.None
let mk_PreType (t : term) : term= mkApp ("PreType", [t]) t.rng
let mk_Valid (t : term) : term=
  match t.tm with
  | App
      (Var "Prims.b2t",
       { tm = App (Var "Prims.op_Equality", uu___::t1::t2::[]);
         freevars = uu___1; rng = uu___2;_}::[])
      -> mkEq (t1, t2) t.rng
  | App
      (Var "Prims.b2t",
       { tm = App (Var "Prims.op_disEquality", uu___::t1::t2::[]);
         freevars = uu___1; rng = uu___2;_}::[])
      -> let uu___3 = mkEq (t1, t2) norng in mkNot uu___3 t.rng
  | App
      (Var "Prims.b2t",
       { tm = App (Var "Prims.op_LessThanOrEqual", t1::t2::[]);
         freevars = uu___; rng = uu___1;_}::[])
      ->
      let uu___2 =
        let uu___3 = unboxInt t1 in
        let uu___4 = unboxInt t2 in (uu___3, uu___4) in
      mkLTE uu___2 t.rng
  | App
      (Var "Prims.b2t",
       { tm = App (Var "Prims.op_LessThan", t1::t2::[]); freevars = uu___;
         rng = uu___1;_}::[])
      ->
      let uu___2 =
        let uu___3 = unboxInt t1 in
        let uu___4 = unboxInt t2 in (uu___3, uu___4) in
      mkLT uu___2 t.rng
  | App
      (Var "Prims.b2t",
       { tm = App (Var "Prims.op_GreaterThanOrEqual", t1::t2::[]);
         freevars = uu___; rng = uu___1;_}::[])
      ->
      let uu___2 =
        let uu___3 = unboxInt t1 in
        let uu___4 = unboxInt t2 in (uu___3, uu___4) in
      mkGTE uu___2 t.rng
  | App
      (Var "Prims.b2t",
       { tm = App (Var "Prims.op_GreaterThan", t1::t2::[]); freevars = uu___;
         rng = uu___1;_}::[])
      ->
      let uu___2 =
        let uu___3 = unboxInt t1 in
        let uu___4 = unboxInt t2 in (uu___3, uu___4) in
      mkGT uu___2 t.rng
  | App
      (Var "Prims.b2t",
       { tm = App (Var "Prims.op_AmpAmp", t1::t2::[]); freevars = uu___;
         rng = uu___1;_}::[])
      ->
      let uu___2 =
        let uu___3 = unboxBool t1 in
        let uu___4 = unboxBool t2 in (uu___3, uu___4) in
      mkAnd uu___2 t.rng
  | App
      (Var "Prims.b2t",
       { tm = App (Var "Prims.op_BarBar", t1::t2::[]); freevars = uu___;
         rng = uu___1;_}::[])
      ->
      let uu___2 =
        let uu___3 = unboxBool t1 in
        let uu___4 = unboxBool t2 in (uu___3, uu___4) in
      mkOr uu___2 t.rng
  | App
      (Var "Prims.b2t",
       { tm = App (Var "Prims.op_Negation", t1::[]); freevars = uu___;
         rng = uu___1;_}::[])
      -> let uu___2 = unboxBool t1 in mkNot uu___2 t1.rng
  | App
      (Var "Prims.b2t",
       { tm = App (Var "FStar.BV.bvult", t0::t1::t2::[]); freevars = uu___;
         rng = uu___1;_}::[])
      when
      let uu___2 = getBoxedInteger t0 in
      FStar_Pervasives_Native.uu___is_Some uu___2 ->
      let sz =
        let uu___2 = getBoxedInteger t0 in
        match uu___2 with
        | FStar_Pervasives_Native.Some sz1 -> sz1
        | uu___3 -> FStarC_Effect.failwith "impossible" in
      let uu___2 =
        let uu___3 = unboxBitVec sz t1 in
        let uu___4 = unboxBitVec sz t2 in (uu___3, uu___4) in
      mkBvUlt uu___2 t.rng
  | App
      (Var "Prims.equals",
       uu___::{ tm = App (Var "FStar.BV.bvult", t0::t1::t2::[]);
                freevars = uu___1; rng = uu___2;_}::uu___3::[])
      when
      let uu___4 = getBoxedInteger t0 in
      FStar_Pervasives_Native.uu___is_Some uu___4 ->
      let sz =
        let uu___4 = getBoxedInteger t0 in
        match uu___4 with
        | FStar_Pervasives_Native.Some sz1 -> sz1
        | uu___5 -> FStarC_Effect.failwith "impossible" in
      let uu___4 =
        let uu___5 = unboxBitVec sz t1 in
        let uu___6 = unboxBitVec sz t2 in (uu___5, uu___6) in
      mkBvUlt uu___4 t.rng
  | App (Var "Prims.b2t", t1::[]) ->
      let uu___ = unboxBool t1 in
      { tm = (uu___.tm); freevars = (uu___.freevars); rng = (t.rng) }
  | uu___ -> mkApp ("Valid", [t]) t.rng
let mk_unit_type : term= mkApp ("Prims.unit", []) norng
let mk_HasType (v : term) (t : term) : term= mkApp ("HasType", [v; t]) t.rng
let mk_HasTypeZ (v : term) (t : term) : term=
  mkApp ("HasTypeZ", [v; t]) t.rng
let mk_IsTotFun (t : term) : term= mkApp ("IsTotFun", [t]) t.rng
let mk_HasTypeFuel (f : term) (v : term) (t : term) : term=
  let uu___ = FStarC_Options.unthrottle_inductives () in
  if uu___ then mk_HasType v t else mkApp ("HasTypeFuel", [f; v; t]) t.rng
let mk_HasTypeWithFuel (f : term FStar_Pervasives_Native.option) (v : term)
  (t : term) : term=
  match f with
  | FStar_Pervasives_Native.None -> mk_HasType v t
  | FStar_Pervasives_Native.Some f1 -> mk_HasTypeFuel f1 v t
let mk_NoHoist (dummy : term) (b : term) : term=
  mkApp ("NoHoist", [dummy; b]) b.rng
let mk_tester (n : Prims.string) (t : term) : term=
  mkApp ((Prims.strcat "is-" n), [t]) t.rng
let mk_ApplyTF (t : term) (t' : term) : term=
  mkApp ("ApplyTF", [t; t']) t.rng
let mk_ApplyTT (t : term) (t' : term) (r : FStarC_Range_Type.t) : term=
  mkApp ("ApplyTT", [t; t']) r
let mk_String_const (s : Prims.string) (r : FStarC_Range_Type.t) : term=
  let uu___ =
    let uu___1 = let uu___2 = mk (String s) r in [uu___2] in
    ("FString_const", uu___1) in
  mkApp uu___ r
let mk_Precedes_term (u0 : term) (u1 : term) (x1 : term) (x2 : term)
  (x3 : term) (x4 : term) (r : FStarC_Range_Type.t) : term=
  mkApp ("Prims.precedes", [u0; u1; x1; x2; x3; x4]) r
let mk_Precedes (u0 : term) (u1 : term) (x1 : term) (x2 : term) (x3 : term)
  (x4 : term) (r : FStarC_Range_Type.t) : term=
  let uu___ = mk_Precedes_term u0 u1 x1 x2 x3 x4 r in mk_Valid uu___
let mk_lex_t (r : FStarC_Range_Type.t) : term= mkApp ("Prims.lex_t", []) r
let mk_LexCons (x1 : term) (x2 : term) (x3 : term) (r : FStarC_Range_Type.t)
  : term= mkApp ("LexCons", [x1; x2; x3]) r
let mk_LexTop (r : FStarC_Range_Type.t) : term= mkApp ("LexTop", []) r
let rec n_fuel (n : Prims.int) : term=
  if n = Prims.int_zero
  then mkApp ("ZFuel", []) norng
  else
    (let uu___ =
       let uu___1 = let uu___2 = n_fuel (n - Prims.int_one) in [uu___2] in
       ("SFuel", uu___1) in
     mkApp uu___ norng)
let mk_and_l (l : term Prims.list) (r : FStarC_Range_Type.t) : term=
  let uu___ = mkTrue r in
  FStarC_List.fold_right (fun p1 p2 -> mkAnd (p1, p2) r) l uu___
let mk_or_l (l : term Prims.list) (r : FStarC_Range_Type.t) : term=
  let uu___ = mkFalse r in
  FStarC_List.fold_right (fun p1 p2 -> mkOr (p1, p2) r) l uu___
let mk_haseq (u : term) (t : term) : term=
  let uu___ = mkApp ("Prims.hasEq", [u; t]) t.rng in mk_Valid uu___
let dummy_sort : sort= Sort "Dummy_sort"
let showable_sort : sort FStarC_Class_Show.showable=
  { FStarC_Class_Show.show = strSort }
let showable_fv : fv FStarC_Class_Show.showable=
  {
    FStarC_Class_Show.show =
      (fun uu___ -> match uu___ with | FV (n, uu___1, uu___2) -> n)
  }
let showable_smt_term : term FStarC_Class_Show.showable=
  { FStarC_Class_Show.show = print_smt_term }
let showable_decl : decl FStarC_Class_Show.showable=
  { FStarC_Class_Show.show = (declToSmt_no_caps "") }
let showable_decls_elt : decls_elt FStarC_Class_Show.showable=
  {
    FStarC_Class_Show.show =
      (fun d ->
         FStarC_Class_Show.show (FStarC_Class_Show.show_list showable_decl)
           d.decls)
  }
let rec names_of_decl (d : decl) : Prims.string Prims.list=
  match d with
  | Assume a -> [a.assumption_name]
  | Module (uu___, ds) -> FStarC_List.collect names_of_decl ds
  | uu___ -> []
let decl_to_string_short (d : decl) : Prims.string=
  match d with
  | DefPrelude -> "prelude"
  | DeclFun (s, uu___, uu___1, uu___2) -> Prims.strcat "DeclFun " s
  | DefineFun (s, uu___, uu___1, uu___2, uu___3) ->
      Prims.strcat "DefineFun " s
  | Assume a -> Prims.strcat "Assumption " a.assumption_name
  | Caption s -> Prims.strcat "Caption " s
  | Module (s, uu___) -> Prims.strcat "Module " s
  | Eval uu___ -> "Eval"
  | Echo s -> Prims.strcat "Echo " s
  | RetainAssumptions uu___ -> "RetainAssumptions"
  | Push n ->
      let uu___ = FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
      FStarC_Format.fmt1 "push %s" uu___
  | Pop n ->
      let uu___ = FStarC_Class_Show.show FStarC_Class_Show.showable_int n in
      FStarC_Format.fmt1 "pop %s" uu___
  | CheckSat -> "check-sat"
  | GetUnsatCore -> "get-unsat-core"
  | EmptyLine -> "; empty line"
  | SetOption (s, v) ->
      Prims.strcat "SetOption " (Prims.strcat s (Prims.strcat " " v))
  | GetStatistics -> "get-statistics"
  | GetReasonUnknown -> "get-reason-unknown"
