123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644(**************************************************************************)(* *)(* This file is part of WP plug-in of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat a l'energie atomique et aux energies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)(* -------------------------------------------------------------------------- *)(** {1 First Order Logic Definition} *)(* -------------------------------------------------------------------------- *)type'aelement=|E_none|E_true|E_false|E_intofint|E_funof'a*'aelementlist(** Algebraic properties for user operators. *)type'aoperator={invertible:bool;(* x+y = x+z <-> y=z (on both side) *)associative:bool;(* x+(y+z)=(x+y)+z *)commutative:bool;(* x+y=y+x *)idempotent:bool;(* x+x = x *)neutral:'aelement;absorbant:'aelement;}(** Algebraic properties for functions. *)type'acategory=|Function(** logic function *)|Constructor(** [f xs = g ys] iff [f=g && xi=yi] *)|Injection(** [f xs = f ys] iff [xi=yi] *)|Operatorof'aoperator(** Quantifiers and Binders *)typebinder=|Forall|Exists|Lambdatype('f,'a)datatype=|Prop|Bool|Int|Real|Tvarofint(** ranges over [1..arity] *)|Arrayof('f,'a)datatype*('f,'a)datatype|Recordof('f*('f,'a)datatype)list|Dataof'a*('f,'a)datatypelisttypesort=|Sprop|Sbool|Sint|Sreal|Sdata|Sarrayofsorttypemaybe=Yes|No|Maybe(** Ordered, hash-able and pretty-printable symbols *)moduletypeSymbol=sigtypetvalhash:t->intvalequal:t->t->boolvalcompare:t->t->intvalpretty:Format.formatter->t->unitvaldebug:t->string(** for printing during debug *)end(** {2 Abstract Data Types} *)moduletypeData=sigincludeSymbolvalbasename:t->string(** hint for generating fresh names *)end(** {2 Field for Record Types} *)moduletypeField=sigincludeSymbolvalsort:t->sort(** of field *)end(** {2 User Defined Functions} *)moduletypeFunction=sigincludeSymbolvalcategory:t->tcategoryvalparams:t->sortlist(** params ; exceeding params use Sdata *)valsort:t->sort(** result *)end(** {2 Bound Variables} *)moduletypeVariable=sigincludeSymbolvalsort:t->sortvalbasename:t->stringvaldummy:tend(** {2 Representation of Patterns, Functions and Terms} *)type('f,'a)funtype={result:('f,'a)datatype;(** Type of returned value *)params:('f,'a)datatypelist;(** Type of parameters *)}(** representation of terms. type arguments are the following:
- 'z: representation of integral constants
- 'f: representation of fields
- 'a: representation of abstract data types
- 'd: representation of functions
- 'x: representation of free variables
- 'b: representation of bound term (phantom type equal to 'e)
- 'e: sub-expression
*)type('f,'a,'d,'x,'b,'e)term_repr=|True|False|KintofZ.t|KrealofQ.t|TimesofZ.t*'e(** mult: k1 * e2 *)|Addof'elist(** add: e11 + ... + e1n *)|Mulof'elist(** mult: e11 * ... * e1n *)|Divof'e*'e|Modof'e*'e|Eqof'e*'e|Neqof'e*'e|Leqof'e*'e|Ltof'e*'e|Agetof'e*'e(** access: array1[idx2] *)|Asetof'e*'e*'e(** update: array1[idx2 -> elem3] *)|Acstof('f,'a)datatype*'e(** constant array [ type -> value ] *)|Rgetof'e*'f|Rdefof('f*'e)list|Andof'elist(** and: e11 && ... && e1n *)|Orof'elist(** or: e11 || ... || e1n *)|Notof'e|Implyof'elist*'e(** imply: (e11 && ... && e1n) ==> e2 *)|Ifof'e*'e*'e(** ite: if c1 then e2 else e3 *)|Funof'd*'elist(** Complete call (no partial app.) *)|Fvarof'x|Bvarofint*('f,'a)datatype|Applyof'e*'elist(** High-Order application (Cf. binder) *)|Bindofbinder*('f,'a)datatype*'btype'aaffine=Z.t*(Z.t*'a)list(** {2 Formulae} *)moduletypeTerm=sigmoduleADT:DatamoduleField:FieldmoduleFun:FunctionmoduleVar:Variabletypetermtypelc_term(** Loosely closed terms. *)moduleTerm:Symbolwithtypet=term(** Non-structural, machine dependent,
but fast comparison and efficient merges *)moduleTset:Idxset.Swithtypeelt=term(** Non-structural, machine dependent,
but fast comparison and efficient merges *)moduleTmap:Idxmap.Swithtypekey=term(** Structuraly ordered, but less efficient access and non-linear merges *)moduleSTset:Set.Swithtypeelt=term(** Structuraly ordered, but less efficient access and non-linear merges *)moduleSTmap:Map.Swithtypekey=term(** {3 Variables} *)typevar=Var.ttypetau=(Field.t,ADT.t)datatypemoduleTau:Datawithtypet=taumoduleVars:Idxset.Swithtypeelt=varmoduleVmap:Idxmap.Swithtypekey=vartypepoolvalpool:?copy:pool->unit->poolvaladd_var:pool->var->unitvaladd_vars:pool->Vars.t->unitvaladd_term:pool->term->unitvalfresh:pool->?basename:string->tau->varvalalpha:pool->var->varvaltau_of_var:var->tauvalsort_of_var:var->sortvalbase_of_var:var->string(** {3 Terms} *)type'aexpression=(Field.t,ADT.t,Fun.t,var,lc_term,'a)term_reprtyperepr=termexpressiontyperecord=(Field.t*term)listvaldecide:term->bool(** Return [true] if and only the term is [e_true]. Constant time. *)valis_true:term->maybe(** Constant time. *)valis_false:term->maybe(** Constant time. *)valis_prop:term->bool(** Boolean or Property *)valis_int:term->bool(** Integer sort *)valis_real:term->bool(** Real sort *)valis_arith:term->bool(** Integer or Real sort *)valare_equal:term->term->maybe(** Computes equality *)valeval_eq:term->term->bool(** Same as [are_equal] is [Yes] *)valeval_neq:term->term->bool(** Same as [are_equal] is [No] *)valeval_lt:term->term->bool(** Same as [e_lt] is [e_true] *)valeval_leq:term->term->bool(** Same as [e_leq] is [e_true] *)valrepr:term->repr(** Constant time *)valsort:term->sort(** Constant time *)valvars:term->Vars.t(** Constant time *)(** Path-positioning access
This part of the API is DEPRECATED
*)typepath=intlist(** position of a subterm in a term. *)(** {3 Basic constructors} *)vale_true:termvale_false:termvale_bool:bool->termvale_literal:bool->term->termvale_int:int->termvale_float:float->termvale_zint:Z.t->termvale_real:Q.t->termvale_var:var->termvale_opp:term->termvale_times:Z.t->term->termvale_sum:termlist->termvale_prod:termlist->termvale_add:term->term->termvale_sub:term->term->termvale_mul:term->term->termvale_div:term->term->termvale_mod:term->term->termvale_eq:term->term->termvale_neq:term->term->termvale_leq:term->term->termvale_lt:term->term->termvale_imply:termlist->term->termvale_equiv:term->term->termvale_and:termlist->termvale_or:termlist->termvale_not:term->termvale_if:term->term->term->termvale_const:tau->term->termvale_get:term->term->termvale_set:term->term->term->termvale_getfield:term->Field.t->termvale_record:record->termvale_fun:?result:tau->Fun.t->termlist->termvale_repr:?result:tau->repr->term(** @raise Invalid_argument on [Bvar] and [Bind] *)(** {3 Quantifiers and Binding} *)vale_forall:varlist->term->termvale_exists:varlist->term->termvale_lambda:varlist->term->termvale_close_forall:term->termvale_close_exists:term->termvale_close_lambda:term->termvale_apply:term->termlist->termvale_bind:binder->var->term->term(** Bind the given variable if it appears free in the term,
or return the term unchanged. *)vale_unbind:var->lc_term->term(** Opens the top-most bound variable with a (fresh) variable.
Can be only applied on top-most lc-term from `Bind(_,_,_)`,
thanks to typing. *)vale_open:pool:pool->?forall:bool->?exists:bool->?lambda:bool->term->(binder*var)list*term(** Open all the specified binders (flags default to `true`, so all
consecutive top most binders are opened by default).
The pool must contain all free variables of the term. *)vale_close:(binder*var)list->term->term(** Closes all specified binders *)(** {3 Generalized Substitutions} *)typesigmavalsigma:?pool:pool->unit->sigmamoduleSubst:sigtypet=sigmavalcreate:?pool:pool->unit->tvalcopy:sigma->sigmavalfresh:t->tau->varvalfind:t->term->termvalfilter:t->term->boolvaladd:t->term->term->unit(** Must bind lc-closed terms, or raise Invalid_argument *)valadd_fun:t->(term->term)->unit(** Must bind lc-closed terms, or raise Invalid_argument *)valadd_filter:t->(term->bool)->unit(** Only modifies terms that {i pass} the filter. *)valadd_var:t->var->unit(** To the pool *)valadd_vars:t->Vars.t->unit(** To the pool *)valadd_term:t->term->unit(** To the pool *)endvale_subst:sigma->term->term(**
The environment sigma must be prepared with the desired substitution.
Its pool of fresh variables must covers the entire domain and co-domain
of the substitution, and the transformed values.
*)vale_subst_var:var->term->term->term(** {3 Locally Nameless Representation}
These functions can be {i unsafe} because they might expose terms
that contains non-bound b-vars. Never use such terms to build
substitutions (sigma).
*)vallc_vars:term->Bvars.tvallc_closed:term->bool(** All bound variables are under their binder *)vallc_repr:lc_term->term(** Calling this function is {i unsafe} unless the term is lc_closed *)vallc_iter:(term->unit)->term->unit(** Similar to [f_iter] but exposes non-closed sub-terms of `Bind`
as regular [term] values instead of [lc_term] ones. *)(** {3 Iteration Scheme} *)valf_map:?pool:pool->?forall:bool->?exists:bool->?lambda:bool->(term->term)->term->term(** Pass and open binders, maps its direct sub-terms
and then close then opened binders
Raises Invalid_argument in case of a bind-term without pool.
The optional pool must contain all free variables of the term. *)valf_iter:?pool:pool->?forall:bool->?exists:bool->?lambda:bool->(term->unit)->term->unit(** Iterates over its direct sub-terms (pass and open binders)
Raises Invalid_argument in case of a bind-term without pool.
The optional pool must contain all free variables of the term. *)(** {3 Partial Typing} *)(** Try to extract a type of term.
Parameterized by optional extractors for field and functions.
Extractors may raise [Not_found] ; however, they are only used when
the provided kinds for fields and functions are not precise enough.
@param field type of a field value
@param record type of the record containing a field
@param call type of the values returned by the function
@raise Not_found if no type is found. *)valtypeof:?field:(Field.t->tau)->?record:(Field.t->tau)->?call:(Fun.t->tauoptionlist->tau)->term->tau(** {3 Support for Builtins} *)valset_builtin:?force:bool->Fun.t->(termlist->term)->unit(** Register a simplifier for function [f]. The computation code
may raise [Not_found], in which case the symbol is not interpreted.
If [f] is an operator with algebraic rules (see type
[operator]), the children are normalized {i before} builtin
call.
Highest priority is [0].
Recursive calls must be performed on strictly smaller terms.
The [force] parameters defaults to [false], when it is [true], if there
exist another builtin, it is replaced with the new one. Use with care.
@before 22.0-Titanium the optional [force] parameter does not exist
*)valset_builtin':?force:bool->Fun.t->(termlist->tauoption->term)->unitvalset_builtin_map:?force:bool->Fun.t->(termlist->termlist)->unit(** Register a builtin for rewriting [f a1..an] into [f b1..bm].
This is short cut for [set_builtin], where the head application of [f] avoids
to run into an infinite loop.
The [force] parameters defaults to [false], when it is [true], if there
exist another builtin, it is replaced with the new one. Use with care.
@before 22.0-Titanium the optional [force] parameter does not exist
*)valset_builtin_get:?force:bool->Fun.t->(termlist->termlist->term)->unit(** [set_builtin_get f rewrite] register a builtin
for rewriting [(f a1..an)[k1]..[km]] into [rewrite (a1..an) (k1..km)].
The [force] parameters defaults to [false], when it is [true], if there
exist another builtin, it is replaced with the new one. Use with care.
@before 22.0-Titanium the optional [force] parameter does not exist
@before 28.0-Nickel one-dimensional access only
*)valset_builtin_field:?force:bool->Fun.t->Field.t->(termlist->term)->unit(** Register a builtin for simplifying [(f e…).fd] expressions.
{b Must} only use recursive comparison for strictly smaller terms.
The [force] parameters defaults to [false], when it is [true], if there
exist another builtin, it is replaced with the new one. Use with care.
@since 28.0-Nickel
*)valset_builtin_eq:?force:bool->Fun.t->(term->term->term)->unit(** Register a builtin equality for comparing any term with head-symbol.
{b Must} only use recursive comparison for strictly smaller terms.
The recognized term with head function symbol is passed first.
Highest priority is [0].
Recursive calls must be performed on strictly smaller terms.
The [force] parameters defaults to [false], when it is [true], if there
exist another builtin, it is replaced with the new one. Use with care.
@before 22.0-Titanium the optional [force] parameter does not exist
*)valset_builtin_leq:?force:bool->Fun.t->(term->term->term)->unit(** Register a builtin for comparing any term with head-symbol.
{b Must} only use recursive comparison for strictly smaller terms.
The recognized term with head function symbol can be on both sides.
Strict comparison is automatically derived from the non-strict one.
Highest priority is [0].
Recursive calls must be performed on strictly smaller terms.
The [force] parameters defaults to [false], when it is [true], if there
exist another builtin, it is replaced with the new one. Use with care.
@before 22.0-Titanium the optional [force] parameter does not exist
*)(** {3 Specific Patterns} *)valconsequence:term->term->term(** Knowing [h], [consequence h a] returns [b] such that [h -> (a<->b)] *)valliteral:term->bool*termvalaffine:term->termaffinevalrecord_with:record->(term*record)option(** {3 Symbol} *)typet=termvalid:t->int(** unique identifier (stored in t) *)valhash:t->int(** constant access (stored in t) *)valequal:t->t->bool(** physical equality *)valcompare:t->t->int(** atoms are lower than complex terms ; otherwise, sorted by id. *)valpretty:Format.formatter->t->unitvalweigth:t->int(** Informal size *)(** {3 Utilities} *)valis_closed:t->bool(** No bound variables *)valis_simple:t->bool(** Constants, variables, functions of arity 0 *)valis_atomic:t->bool(** Constants and variables *)valis_primitive:t->bool(** Constants only *)valis_neutral:Fun.t->t->boolvalis_absorbant:Fun.t->t->boolvalsize:t->intvalbasename:t->stringvaldebug:Format.formatter->t->unitvalpp_id:Format.formatter->t->unit(** internal id *)valpp_rid:Format.formatter->t->unit(** head symbol with children id's *)valpp_repr:Format.formatter->repr->unit(** head symbol with children id's *)(** {2 Shared sub-terms} *)valis_subterm:term->term->bool(** Occurrence check. [is_subterm a b] returns [true] iff [a] is a subterm
of [b]. Optimized {i wrt} shared subterms, term size, and term
variables. *)valshared:?shared:(term->bool)->?shareable:(term->bool)->?subterms:((term->unit)->term->unit)->termlist->termlist(** Computes the sub-terms that appear several times.
[shared marked linked e] returns the shared subterms of [e].
The list of shared subterms is consistent with
order of definition: each trailing terms only depend on heading ones.
The traversal is controlled by two optional arguments:
- [shared] those terms are not traversed (considered as atomic, default to none)
- [shareable] those terms ([is_simple] excepted) that can be shared (default to all)
- [subterms] those sub-terms a term to be considered during
traversal ([lc_iter] by default)
*)(** Low-level shared primitives: [shared] is actually a combination of
building marks, marking terms, and extracting definitions:
{[ let share ?... e =
let m = marks ?... () in
List.iter (mark m) es ;
defs m ]} *)typemarks(** Create a marking accumulator.
Same defaults than [shared]. *)valmarks:?shared:(term->bool)->?shareable:(term->bool)->?subterms:((term->unit)->term->unit)->unit->marks(** Mark a term to be printed *)valmark:marks->term->unit(** Mark a term to be explicitly shared *)valshare:marks->term->unit(** Returns a list of terms to be shared among all {i shared} or {i
marked} subterms. The order of terms is consistent with
definition order: head terms might be used in tail ones. *)valdefs:marks->termlistend