type 'a expr = { expr_desc : 'a expr_desc; expr_meta : 'a }

and 'a expr_desc =
  | Ret of 'a cexpr
  | Let of 'a binding * 'a expr
  | Letrec of 'a binding list * 'a expr
  | Seq of 'a expr list

and 'a cexpr = { cexpr_desc : 'a cexpr_desc; cexpr_meta : 'a }

and 'a cexpr_desc =
  | Atom of 'a atom
  | App of 'a atom * 'a atom list
  | Lam of string list * 'a expr
  | Prim1 of Prim.op1 * 'a cexpr
  | Prim2 of Prim.op2 * 'a atom * 'a atom
  | If of 'a atom * 'a expr * 'a expr
  | Match of 'a atom * 'a pattern list * Type.t
  | Tuple of 'a atom list
  | Get of 'a cexpr * int
  | Vect of 'a atom * 'a atom
  | VectGet of 'a atom * 'a atom
  | VectSet of 'a atom * 'a atom * 'a atom
  | VectLength of 'a cexpr
  | Ascribe of 'a cexpr * Type.t
  | AscribeDyn of 'a cexpr * 'a atom * Inversion.t
  | For of string * 'a atom * 'a atom * 'a expr
  | Variant of string * 'a atom list * Type.t

and 'a atom = { atom_desc : 'a atom_desc; atom_meta : 'a }
and 'a atom_desc = Const of Const.t | Var of string
and 'a binding = { name : string; cexpr : 'a cexpr }
and 'a pattern = { casename : string; args : string list; body : 'a expr }

val expr_of_desc : 'a expr_desc -> 'a -> 'a expr
val cexpr_of_desc : 'a cexpr_desc -> 'a -> 'a cexpr
val atom_of_desc : 'a atom_desc -> 'a -> 'a atom
val bind : 'a binding -> 'a expr -> 'a expr
val bind_rec : 'a binding list -> 'a expr -> 'a expr
val ret : 'a cexpr -> 'a -> 'a expr
val of_ast : 'a Ast.t -> 'a expr
val free_vars : 'a expr -> string list
val free_vars_cexpr : 'a cexpr -> string list
val free_vars_atom : 'a atom -> string list

val pp_expr :
  ?show_meta:bool ->
  (Format.formatter -> 'a -> unit) ->
  Format.formatter ->
  'a expr ->
  unit

val pp_cexpr :
  ?show_meta:bool ->
  (Format.formatter -> 'a -> unit) ->
  Format.formatter ->
  'a cexpr ->
  unit

val pp_atom :
  ?show_meta:bool ->
  (Format.formatter -> 'a -> unit) ->
  Format.formatter ->
  'a atom ->
  unit

val pp_binding :
  ?show_meta:bool ->
  (Format.formatter -> 'a -> unit) ->
  Format.formatter ->
  'a binding ->
  unit

val pp_pattern :
  ?show_meta:bool ->
  (Format.formatter -> 'a -> unit) ->
  Format.formatter ->
  'a pattern ->
  unit
