(********************************************************************)

(*                                                                  *)
(*  The Why3 Verification Platform   /   The Why3 Development Team  *)
(*  Copyright 2010-2023 --  Inria - CNRS - Paris-Saclay University  *)
(*                                                                  *)
(*  This software is distributed under the terms of the GNU Lesser  *)
(*  General Public License version 2.1, with the special exception  *)
(*  on linking described in file LICENSE.                           *)
(*                                                                  *)
(********************************************************************)


(**

Parse trees

The module provides datatypes for WhyML parse trees. These datatypes are produced by the WhyML parser module Parser. They can be alternatively produced via OCaml code, and processed later on by typing module Typing. See also Section 4.9. "ML Programs" of the documentation. *)


open Mysexplib.Std [@@warning "-33"]

(**

Identifiers and attributes

*)


(** attributes, with a specific case for a source location *)

type attr =
  | ATstr of Ident.attribute
  | ATpos of Loc.position
[@@deriving sexp]

(** identifiers, with attributes and a source location *)

type ident = {
  id_str : string;
  id_ats : attr list;
  id_loc : Loc.position;
}
[@@deriving sexp]

(** qualified identifiers *)

type qualid =
  | Qident of ident
  | Qdot of qualid * ident
[@@deriving sexp]

(**

Types

*)


(** type expressions *)

type pty =
  | PTtyvar of ident
  
  (** type variable *)

  | PTtyapp of qualid * pty list
  
  (** type constructor, possibly with arguments, e.g., int, list bool, etc. *)

  | PTtuple of pty list
  
  (** tuples, e.g., (int,bool) *)

  | PTref   of pty list
  
  (** reference type, e.g., ref int, as used by the "auto-dereference" mechanism (See manual Section 13.1. "Release Notes for version 1.2: new syntax for auto-dereference") *)

  | PTarrow of pty * pty
  
  (** arrow type, e.g., int -> bool *)

  | PTscope of qualid * pty
  
  (** opening scope locally, e.g., M.((list t,u)) *)

  | PTparen of pty
  
  (** parenthesised type *)

  | PTpure  of pty
  
  (** purify a type *)

[@@deriving sexp]


(**

Patterns

*)


(** "ghost" modifier *)

type ghost = bool
[@@deriving sexp]

(** Patterns, equipped with a source location *)

type pattern = {
  pat_desc : pat_desc;
  pat_loc  : Loc.position;
}

and pat_desc =
  | Pwild
  
  (** wildcard, that is "_" *)

  | Pvar of ident
  
  (** variable as a pattern *)

  | Papp of qualid * pattern list
  
  (** constructor pattern, e.g., Cons(x,y) *)

  | Prec of (qualid * pattern) list
  
  (** record pattern *)

  | Ptuple of pattern list
  
  (** tuple pattern *)

  | Pas of pattern * ident * ghost
  
  (** as-pattern, e.g., Cons(x,y) as z *)

  | Por of pattern * pattern
  
  (** or-pattern p1 | p2 *)

  | Pcast of pattern * pty
  
  (** type cast *)

  | Pscope of qualid * pattern
  
  (** open scope locally *)

  | Pparen of pattern
  
  (** parenthesised pattern *)

  | Pghost of pattern
  
  (** explicitly ghost pattern *)

[@@deriving sexp]


(**

Logical terms and formulas

*)


(** binder as 4-uple (loc,id,ghost,type) to represent "ghost? id? : type?". id and type cannot be None at the same time *)

type binder = Loc.position * ident option * ghost * pty option
[@@deriving sexp]

(** parameter as 4-uple (loc,id,ghost,type) to represent "ghost? id? : type". *)

type param  = Loc.position * ident option * ghost * pty
[@@deriving sexp]

(** Terms, equipped with a source location *)

type term = {
  term_desc : term_desc;
  term_loc  : Loc.position;
}

and term_desc =
  | Ttrue
  
  (** the true proposition *)

  | Tfalse
  
  (** the false proposition *)

  | Tconst of Constant.constant
  
  (** constant literals *)

  | Tident of qualid
  
  (** identifiers *)

  | Tasref of qualid
  
  (** identifier as reference, e.g., &x (See manual Section 13.1. "Release Notes for version 1.2: new syntax for auto-dereference") *)

  | Tidapp of qualid * term list
  
  (** (first-order) application of a logic identifier to a list of terms *)

  | Tapply of term * term
  
  (** curried application, of a term to a term *)

  | Tinfix of term * ident * term
  
  (** application of a binary operation in an infix fashion, allowing chaining. For example, Tinfix(t1,"<=",Tinfix(t2,"<",t3)) denotes t1 <= t2 /\ t2 < t3 *)

  | Tinnfix of term * ident * term
  
  (** application of a binary operation in an infix style, but without chaining *)

  | Tbinop of term * Dterm.dbinop * term
  
  (** application of a binary logic connective, in an infix fashion, allowing chaining. For example, Tbinop(p1,"<->",Tbinop(p2,"<->",p3)) denotes (p1 <-> p2) /\ (p2 <-> p3) *)

  | Tbinnop of term * Dterm.dbinop * term
  
  (** application of a binary logic connective, but without chaining *)

  | Tnot of term
  
  (** logic negation *)

  | Tif of term * term * term
  
  (** if-expression *)

  | Tquant of Dterm.dquant * binder list * term list list * term
  
  (** quantified formulas. The third argument is a list of triggers. *)

  | Teps of ident * pty * term
  
  (** Teps(x,ty,f) denotes the epsilon term "any x of type ty that satisfies f". Use with caution since if there is no such x satisfying f, then it acts like introducing an inconsistent axiom. (As a matter of fact, this is the reason why there is no concrete syntax for such epsilon-terms.) *)

  | Tattr of attr * term
  
  (** term annotated with an attribute *)

  | Tlet of ident * term * term
  
  (** let-expression *)

  | Tcase of term * (pattern * term) list
  
  (** pattern-matching *)

  | Tcast of term * pty
  
  (** type casting *)

  | Ttuple of term list
  
  (** tuples *)

  | Trecord of (qualid * term) list
  
  (** record expressions *)

  | Tupdate of term * (qualid * term) list
  
  (** record update expression *)

  | Tscope of qualid * term
  
  (** local scope *)

  | Tat of term * ident
  
  (** "at" modifier. The "old" modifier is a particular case with the identifier Dexpr.old_label *)


[@@deriving sexp]

(**

Program expressions

*)


(** Loop invariant or type invariant *)

type invariant = term list
[@@deriving sexp]

(** Variant for both loops and recursive functions. The option identifier is an optional ordering predicate *)

type variant = (term * qualid option) list
[@@deriving sexp]

(** Precondition *)

type pre = term
[@@deriving sexp]

(** Normal postconditions *)

type post = Loc.position * (pattern * term) list
[@@deriving sexp]

(** Exceptional postconditions *)

type xpost = Loc.position * (qualid * (pattern * term) option) list
[@@deriving sexp]

(** Contract *)

type spec = {
    sp_pre     : pre list; 
            (** preconditions *)

    sp_post    : post list; 
           (** normal postconditions *)

    sp_xpost   : xpost list; 
          (** exceptional postconditions *)

    sp_reads   : qualid list; 
          (** "reads" clause *)

    sp_writes  : term list;   
           (** "writes" clause *)

    sp_alias   : (term * term) list; 
            (** "alias" clause *)

    sp_variant : variant; 
       (** variant for recursive functions *)

    sp_checkrw : bool; 
       (** should the reads and writes clauses be checked against the given body? *)

    sp_diverge : bool; 
       (** may the function diverge? *)

    sp_partial : bool; 
       (** is the function partial? *)

}
[@@deriving sexp]

(** Expressions, equipped with a source location *)

type expr = {
    expr_desc : expr_desc;
    expr_loc  : Loc.position;
  }

(** Expression kinds *)

and expr_desc =
  | Eref
  
  (** built-in operator ref for auto-dereference syntax. (See manual Section 13.1. "Release Notes for version 1.2: new syntax for auto-dereference") *)

  | Etrue
  
  (** Boolean literal True *)

  | Efalse
  
  (** Boolean literal False *)

  | Econst of Constant.constant
  
  (** Constant literals *)

  | Eident of qualid
  
  (** Variable identifier *)

  | Easref of qualid
  
  (** identifier as reference, e.g., &x (See manual Section 13.1. "Release Notes for version 1.2: new syntax for auto-dereference") *)

  | Eidapp of qualid * expr list
  
  (** Uncurried application of a function identifier to a list of arguments *)

  | Eapply of expr * expr
  
  (** Curried application *)

  | Einfix of expr * ident * expr
  
  (** application of a binary function identifier, in an infix fashion, allowing chaining, e.g., Einfix(e1,"<=",Einfix(e2,"<",e3)) denotes e1 <= e2 && e2 < e3 *)

  | Einnfix of expr * ident * expr
  
  (** application of a binary function, but without chaining *)

  | Elet of ident * ghost * Expr.rs_kind * expr * expr
  
  (** let ... in ... expression *)

  | Erec of fundef list * expr
  
  (** Local definition of function(s), possibly mutually recursive *)

  | Efun of binder list * pty option * pattern * Ity.mask * spec * expr
  
  (** Anonymous function *)

  | Eany of param list * Expr.rs_kind * pty option * pattern * Ity.mask * spec
  
  (** "any params : ty <spec>": abstract expression with a specification, generating a VC for existence *)

  | Etuple of expr list
  
  (** Tuple of expressions *)

  | Erecord of (qualid * expr) list
  
  (** Record expression, e.g., {f=e1; g=e2; ...} *)

  | Eupdate of expr * (qualid * expr) list
  
  (** Record update, e.g., {e with f=e1; ...} *)

  | Eassign of (expr * qualid option * expr) list
  
  (** Assignment, of a mutable variable (no qualid given) or of a record field (qualid given). Assignments are possibly in parallel, e.g., x.f, y.g, z <- e1, e2, e3 *)

  | Esequence of expr * expr
  
  (** Sequence of two expressions, the first one being supposed of type unit *)

  | Eif of expr * expr * expr
  
  (** if e1 then e2 else e3 expression *)

  | Ewhile of expr * invariant * variant * expr
  
  (** while loop with annotations *)

  | Eand of expr * expr
  
  (** lazy conjunction *)

  | Eor of expr * expr
  
  (** lazy disjunction *)

  | Enot of expr
  
  (** Boolean negation *)

  | Ematch of expr * reg_branch list * exn_branch list
  
  (** match expression, including both regular patterns and exception patterns (those lists cannot be both empty) *)

  | Eabsurd
  
  (** absurd statement to mark unreachable branches *)

  | Epure of term
  
  (** turns a logical term into a pure expression, e.g., pure { t } *)

  | Eidpur of qualid
  
  (** promotes a logic symbol in programs, e.g., {f} or M.{f} *)

  | Eraise of qualid * expr option
  
  (** raise an exception, possibly with an argument *)

  | Eexn of ident * pty * Ity.mask * expr
  
  (** local declaration of an exception, e.g., let exception E in e *)

  | Eoptexn of ident * Ity.mask * expr
  
  (** local declaration of an exception, implicitly captured. Used by Why3 for handling return, break, and continue *)

  | Efor of ident * expr * Expr.for_direction * expr * invariant * expr
  
  (** "for" loops *)

  | Eassert of Expr.assertion_kind * term
  
  (** assert, assume, and check expressions *)

  | Escope of qualid * expr
  
  (** open scope locally, e.g., M.(e) *)

  | Elabel of ident * expr
  
  (** introduction of a label, e.g., label L in e *)

  | Ecast of expr * pty
  
  (** cast an expression to a given type, e.g., (e:ty) *)

  | Eghost of expr
  
  (** forces an expression to be ghost, e.g., ghost e *)

  | Eattr of attr * expr
  
  (** attach an attribute to an expression *)


(** A regular match branch *)

and reg_branch = pattern * expr

(** An exception match branch *)

and exn_branch = qualid * pattern option * expr

(** Local function definition *)

and fundef = ident * ghost * Expr.rs_kind *
               binder list * pty option * pattern * Ity.mask * spec * expr
[@@deriving sexp]

(**

Declarations

*)


(** record fields *)

type field = {
  f_loc     : Loc.position;
  f_ident   : ident;
  f_pty     : pty;
  f_mutable : bool;
  f_ghost   : bool
}
[@@deriving sexp]

(** Type definition body *)

type type_def =
  | TDalias     of pty
  
  (** alias type *)

  | TDalgebraic of (Loc.position * ident * param list) list
  
  (** algebraic type *)

  | TDrecord    of field list
  
  (** record type *)

  | TDrange     of BigInt.t * BigInt.t
  
  (** integer type in given range *)

  | TDfloat     of int * int
  
  (** floating-point type with given exponent and precision *)

[@@deriving sexp]

(** The different kinds of visibility *)

type visibility = Public | Private | Abstract 
        (** = Private + ghost fields *)

[@@deriving sexp]

(** A type declaration *)

type type_decl = {
  td_loc    : Loc.position;
  td_ident  : ident;
  td_params : ident list;
  td_vis    : visibility; 
        (** visibility, for records only *)

  td_mut    : bool;       
              (** mutability, for records or abstract types *)

  td_inv    : invariant;  
         (** invariant, for records only *)

  td_wit    : expr option;  
          (** witness for the invariant *)

  td_def    : type_def;
}
[@@deriving sexp]

(** A single declaration of a function or predicate *)

type logic_decl = {
  ld_loc    : Loc.position;
  ld_ident  : ident;
  ld_params : param list;
  ld_type   : pty option;
  ld_def    : term option;
}
[@@deriving sexp]

(** A single declaration of an inductive predicate *)

type ind_decl = {
  in_loc    : Loc.position;
  in_ident  : ident;
  in_params : param list;
  in_def    : (Loc.position * ident * term) list;
}
[@@deriving sexp]

(** Arguments of "meta" declarations *)

type metarg =
  | Mty  of pty
  | Mfs  of qualid
  | Mps  of qualid
  | Max  of qualid
  | Mlm  of qualid
  | Mgl  of qualid
  | Mval of qualid
  | Mstr of string
  | Mint of int
[@@deriving sexp]

(** The possible "clone" substitution elements *)

type clone_subst =
  | CStsym  of qualid * ident list * pty
  | CSfsym  of qualid * qualid
  | CSpsym  of qualid * qualid
  | CSvsym  of qualid * qualid
  | CSxsym  of qualid * qualid
  | CSprop  of Decl.prop_kind
  | CSaxiom of qualid
  | CSlemma of qualid
  | CSgoal  of qualid
[@@deriving sexp]

(** top-level declarations *)

type decl =
  | Dtype of type_decl list
  
  (** Type declaration *)

  | Dlogic of logic_decl list
  
  (** Collection of "function"s and "predicate"s, mutually recursively declared *)

  | Dind of Decl.ind_sign * ind_decl list
  
  (** An inductive or co-inductive predicate *)

  | Dprop of Decl.prop_kind * ident * term
  
  (** Propositions: "lemma" or "goal" or "axiom" *)

  | Dlet of ident * ghost * Expr.rs_kind * expr
  
  (** Global program variable *)

  | Drec of fundef list
  
  (** Program functions, mutually recursively defined *)

  | Dexn of ident * pty * Ity.mask
  
  (** Declaration of global exceptions *)

  | Dmeta of ident * metarg list
  
  (** Declaration of a "meta" *)

  | Dcloneexport of Loc.position * qualid * clone_subst list
  
  (** "clone export" *)

  | Duseexport of qualid
  
  (** "use export" *)

  | Dcloneimport of Loc.position * bool * qualid * ident option * clone_subst list
  
  (** "clone import ... as ..." *)

  | Duseimport of Loc.position * bool * (qualid * ident option) list
  
  (** "use import ... as ..." *)

  | Dimport of qualid
  
  (** "import" *)

  | Dscope of Loc.position * bool * ident * decl list
  
  (** "scope" *)

[@@deriving sexp]

let sexp_of_mlw_file _ = assert false [@@warning "-32"]
let mlw_file_of_sexp _ = assert false  [@@warning "-32"]
(* default values if the line below does not produce anything, i.e.,
   when ppx_sexp_conv is not installed *)


type mlw_file =
  | Modules of (ident * decl list) list
  
  (** a list of modules containing lists of declarations *)

  | Decls of decl list
  
  (** a list of declarations outside any module *)

[@@deriving sexp]