123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545(* SPDX-License-Identifier: MIT *)(* Copyright (C) 2023-2025 formalsec *)(* Written by the Smtml programmers *)moduletypeS=sig(** Abstract Syntax Tree (AST) for Expressions. This module defines the
representation of terms and expressions in the AST, along with
constructors, accessors, simplification utilities, and pretty-printing
functions. It also includes submodules for handling Boolean expressions,
sets, bitvectors, and floating-point arithmetic. *)(** {1 Expression Types} *)(** A term in the abstract syntax tree. *)typet=exprHc.hash_consed(** The different types of expressions. *)andexpr=private|ValofValue.t(** A constant value. *)|Ptrof{base:Bitvector.t(** Base address. *);offset:t(** Offset from base. *)}|LocofLoc.t(** Abstract location *)|SymbolofSymbol.t(** A symbolic variable. *)|Listoftlist(** A list of expressions. *)|AppofSymbol.t*tlist(** Function application. *)|UnopofTy.t*Ty.Unop.t*t(** Unary operation. *)|BinopofTy.t*Ty.Binop.t*t*t(** Binary operation. *)|TriopofTy.t*Ty.Triop.t*t*t*t(** Ternary operation. *)|RelopofTy.t*Ty.Relop.t*t*t(** Relational operation. *)|CvtopofTy.t*Ty.Cvtop.t*t(** Conversion operation. *)|NaryopofTy.t*Ty.Naryop.t*tlist(** N-ary operation. *)|Extractoft*int*int(** Extract a bit range from an expression. *)|Concatoft*t(** Concatenate two expressions. *)|BinderofBinder.t*tlist*t(** A binding expression. *)(** {1 Constructors and Accessors} *)(** [view term] extracts the underlying expression from a term. *)valview:t->expr(** [hash term] computes the hash of a term. *)valhash:t->int(** [equal t1 t2] compares two terms for equality. *)valequal:t->t->bool(** [compare t1 t2] compares two terms lexicographically. *)valcompare:t->t->int(** {1 Type and Symbol Handling} *)(** [ty expr] determines the type of an expression. *)valty:t->Ty.t(** [is_symbolic expr] checks if an expression is symbolic (i.e., contains
symbolic variables). *)valis_symbolic:t->bool(** [get_symbols exprs] extracts all symbolic variables from a list of
expressions. *)valget_symbols:tlist->Symbol.tlist(** [negate_relop expr] negates a relational operation, if applicable. Returns
an error if the expression is not a relational operation. *)valnegate_relop:t->t(** {1 Pretty Printing} *)(** [pp fmt term] prints a term in a human-readable format using the formatter
[fmt]. *)valpp:tFmt.t(** [pp_smt fmt terms] prints a list of terms in the smtml format using the
formatter [fmt]. *)valpp_smtml:tlistFmt.t(** [pp_list fmt terms] prints a list of expressions in a human-readable
format using the formatter [fmt]. *)valpp_list:tlistFmt.t(** [to_string term] converts a term to a string representation. *)valto_string:t->string(** {1 Expression Constructors} *)(** [value v] constructs a value expression from the given value. *)valvalue:Value.t->t(** [ptr base offset] constructs a pointer expression with the given base
address and offset. *)valptr:int32->t->t(** [loc l] constructs an abstract location *)valloc:Loc.t->t(** [list l] constructs a list expression with the given list of expressions
*)vallist:tlist->t(** [symbol sym] constructs a symbolic variable expression from the given
symbol. *)valsymbol:Symbol.t->t(** [app sym args] constructs a function application expression with the given
symbol and arguments. *)valapp:Symbol.t->tlist->t(** [binder ty bindings body] constructs a [ty] bidning expression with the
given bindings and body. *)valbinder:Binder.t->tlist->t->t(** [let_in bindings body] constructs a let-binding expression with the given
bindings and body. *)vallet_in:tlist->t->t(** [forall bindings body] constructs a universal quantification expression
with the given bindings and body. *)valforall:tlist->t->t(** [exists bindings body] constructs an existential quantification expression
with the given bindings and body. *)valexists:tlist->t->t(** {1 Smart Constructors for Operations} *)(** These constructors apply simplifications during construction. *)(** [unop ty op expr] applies a unary operation with simplification. *)valunop:Ty.t->Ty.Unop.t->t->t(** [binop ty op expr1 expr2] applies a binary operation with simplification.
*)valbinop:Ty.t->Ty.Binop.t->t->t->t(** [triop ty op expr1 expr2 expr3] applies a ternary operation with
simplification. *)valtriop:Ty.t->Ty.Triop.t->t->t->t->t(** [relop ty op expr1 expr2] applies a relational operation with
simplification. *)valrelop:Ty.t->Ty.Relop.t->t->t->t(** [cvtop ty op expr] applies a conversion operation with simplification. *)valcvtop:Ty.t->Ty.Cvtop.t->t->t(** [naryop ty op exprs] applies an N-ary operation with simplification. *)valnaryop:Ty.t->Ty.Naryop.t->tlist->t(** [extract expr ~high ~low] extracts a bit range with simplification. *)valextract:t->high:int->low:int->t(** [concat expr1 expr2] concatenates two expressions with simplification. *)valconcat:t->t->t(** {1 Raw Constructors for Operations} *)(** [raw_unop ty op expr] applies a unary operation, creating a node without
immediate simplification.
This function constructs the representation of a unary operation with the
specified type [ty], operator [op], and operand [expr]. Unlike a "smart
constructor" like [unop], it does not evaluate the expression if possible,
but rather creates the AST node representing the unevaluated operation.
For example:
{@ocaml[
raw_unop Ty_int Neg (value (Int 1))
]}
returns the AST node:
{@ocaml[
Unop (Ty_int, Neg, Val (Int 1))
]}
rather than the simplified value:
{@ocaml[
Val (Int (-1))
]}
which would typically be the result of the smart constructor [unop]. *)valraw_unop:Ty.t->Ty.Unop.t->t->t(** [raw_binop ty op expr1 expr2] applies a binary operation, creating a node
without immediate simplification.
This function constructs the representation of a binary operation with the
specified type [ty], operator [op], and operands [expr1], [expr2]. Unlike
a "smart constructor" like [binop], it does not evaluate the expression if
possible, but rather creates the AST node representing the unevaluated
operation.
For example:
{@ocaml[
raw_binop Ty_int Add (value (Int 1)) (value (Int 2))
]}
returns the AST node:
{@ocaml[
Binop (Ty_int, Add, Val (Int 1), Val (Int 2))
]}
rather than the simplified value:
{@ocaml[
Val (Int 3)
]}
which would typically be the result of the smart constructor [binop]. *)valraw_binop:Ty.t->Ty.Binop.t->t->t->t(** [raw_triop ty op expr1 expr2 expr3] applies a ternary operation, creating
a node without immediate simplification.
This function constructs the representation of a ternary operation with
the specified type [ty], operator [op], and operands [expr1], [expr2],
[expr3]. Unlike a "smart constructor" like [triop], it does not evaluate
the expression if possible, but rather creates the AST node representing
the unevaluated operation.
For example (using a if-then-else operator):
{@ocaml[
raw_triop Ty_bool Ite (value True) (value (Int 1)) (value (Int 2))
]}
returns the AST node:
{@ocaml[
Triop (Ty_bool, Ite, Val True, Val (Int 1), Val (Int 2))
]}
rather than the simplified value:
{@ocaml[
Val (Int 1)
]}
which would typically be the result of the smart constructor [triop]. *)valraw_triop:Ty.t->Ty.Triop.t->t->t->t->t(** [raw_relop ty op expr1 expr2] applies a relational operation, creating a
node without immediate simplification.
This function constructs the representation of a relational operation with
the specified operand type [ty], operator [op], and operands [expr1],
[expr2]. Unlike a "smart constructor" like [relop], it does not evaluate
the expression if possible, but rather creates the AST node representing
the unevaluated operation (which will have a boolean type).
For example:
{@ocaml[
raw_relop Ty_bool Eq (value (Int 1)) (value (Int 2))
]}
returns the AST node:
{@ocaml[
Relop (Ty_bool, Eq, Val (Int 1), Val (Int 2))
]}
rather than the simplified value:
{@ocaml[
Val False
]}
which would typically be the result of the smart constructor [relop]. *)valraw_relop:Ty.t->Ty.Relop.t->t->t->t(** [raw_cvtop ty op expr] applies a conversion operation, creating a node
without immediate simplification.
This function constructs the representation of a conversion operation with
the specified target type [ty], operator [op], and operand [expr]. Unlike
a "smart constructor" like [cvtop], it does not evaluate the conversion if
possible, but rather creates the AST node representing the unevaluated
operation.
For example:
{@ocaml[
raw_cvtop Ty_real Reinterpret_int (value (Int 5))
]}
returns the AST node:
{@ocaml[
Cvtop (Ty_real, Reinterpret_int, Val (Int 5))
]}
rather than the simplified value:
{@ocaml[
Val (Real 5.0)
]}
which would typically be the result of the smart constructor [cvtop]. *)valraw_cvtop:Ty.t->Ty.Cvtop.t->t->t(** [raw_naryop ty op exprs] applies an N-ary operation without
simplification. *)valraw_naryop:Ty.t->Ty.Naryop.t->tlist->t(** [raw_extract expr ~high ~low] extracts a bit range without simplification.
*)valraw_extract:t->high:int->low:int->t(** [raw_concat expr1 expr2] concatenates two expressions without
simplification. *)valraw_concat:t->t->t(** {1 Expression Simplification} *)(** [simplify expr] simplifies an expression until a fixpoint is reached. *)valsimplify:t->t(** {1 Hash-Consing Module} *)moduleHc:sig(** [clear ()] clears the hash-consing table. *)valclear:unit->unit(** [stats ()] returns statistics about the hash-consing table. *)valstats:unit->Hashtbl.statistics(** [length ()] returns the number of entries in the hash-consing table. *)vallength:unit->intend(** {1 Boolean Expressions} *)moduleBool:sig(** The constant [true] expression. *)valtrue_:t(** The constant [false] expression. *)valfalse_:t(** [v b] constructs a Boolean expression from a boolean value. *)valv:bool->t(** [not expr] constructs the logical negation of an expression. *)valnot:t->t(** [equal expr1 expr2] constructs an equality expression. *)valequal:t->t->t(** [distinct expr1 expr2] constructs a distinctness expression. *)valdistinct:t->t->t(** [and_ expr1 expr2] constructs a logical AND expression. *)valand_:t->t->t(** [or_ expr1 expr2] constructs a logical OR expression. *)valor_:t->t->t(** [ite cond then_ else_] constructs an if-then-else expression. *)valite:t->t->t->tend(** {1 Set Module} *)moduleSet:sig(** The type of elements of the set *)typeelt=t(** Alias for the type of elements, for cross-compatibility with maps *)typekey=elt(** The set type *)typet(** {1 Basic functions} *)(** The empty set *)valempty:t(** [is_empty st] is [true] if [st] contains no elements, [false] otherwise
*)valis_empty:t->bool(** [mem elt set] is [true] if [elt] is contained in [set], O(log(n))
complexity. *)valmem:elt->t->bool(** [add elt set] adds element [elt] to the [set]. Preserves physical
equality if [elt] was already present. O(log(n)) complexity. *)valadd:elt->t->t(** [singleton elt] returns a set containing a single element: [elt] *)valsingleton:elt->t(** [cardinal set] is the size of the set (number of elements), O(n)
complexity. *)valcardinal:t->int(** [is_singleton set] is [Some (Any elt)] if [set] is [singleton elt] and
[None] otherwise. *)valis_singleton:t->eltoption(** [remove elt set] returns a set containing all elements of [set] except
[elt]. Returns a value physically equal to [set] if [elt] is not
present. *)valremove:elt->t->t(** The minimal element (according to the unsigned order on {!to_int}) if
non empty. raises Not_found *)valunsigned_min_elt:t->elt(** The maximal element (according to the unsigned order on {!to_int}) if
non empty. raises Not_found *)valunsigned_max_elt:t->elt(** [pop_unsigned_minimum s] is [Some (elt, s')] where
[elt = unsigned_min_elt s] and [s' = remove elt s] if [s] is non empty.
Uses the unsigned order on {!to_int}. *)valpop_unsigned_minimum:t->(elt*t)option(** [pop_unsigned_maximum s] is [Some (elt, s')] where
[elt = unsigned_max_elt s] and [s' = remove elt s] if [s] is non empty.
Uses the unsigned order on {!to_int}. *)valpop_unsigned_maximum:t->(elt*t)option(** {1 Iterators} *)(** [iter f set] calls [f] on all elements of [set], in the unsigned order
of {!to_int}. *)valiter:(elt->unit)->t->unit(** [filter f set] is the subset of [set] that only contains the elements
that satisfy [f]. [f] is called in the unsigned order of {!to_int}. *)valfilter:(elt->bool)->t->t(** [for_all f set] is [true] if [f] is [true] on all elements of [set].
Short-circuits on first [false]. [f] is called in the unsigned order of
{!to_int}. *)valfor_all:(elt->bool)->t->bool(** [fold f set acc] returns [f elt_n (... (f elt_1 acc) ...)], where
[elt_1, ..., elt_n] are the elements of [set], in increasing unsigned
order of {!to_int} *)valfold:(elt->'acc->'acc)->t->'acc->'acc(** [split elt set] returns [s_lt, present, s_gt] where [s_lt] contains all
elements of [set] smaller than [elt], [s_gt] all those greater than
[elt], and [present] is [true] if [elt] is in [set]. Uses the unsigned
order on {!to_int}.*)valsplit:elt->t->t*bool*t(** Pretty prints the set, *)valpp:tFmt.t(** {1 Functions on pairs of sets} *)(** [union a b] is the set union of [a] and [b], i.e. the set containing all
elements that are either in [a] or [b]. *)valunion:t->t->t(** [inter a b] is the set intersection of [a] and [b], i.e. the set
containing all elements that are in both [a] or [b]. *)valinter:t->t->t(** [disjoint a b] is [true] if [a] and [b] have no elements in common. *)valdisjoint:t->t->bool(** [subset a b] is [true] if all elements of [a] are also in [b]. *)valsubset:t->t->bool(** [diff s1 s2] is the set of all elements of [s1] that aren't in [s2].
@since v0.11.0 *)valdiff:t->t->t(** [min_elt_inter s1 s2] is {!unsigned_min_elt} of {{!inter}[inter s1 s2]},
but faster as it does not require computing the whole intersection.
Returns [None] when the intersection is empty.
@since v0.11.0 *)valmin_elt_inter:t->t->eltoption(** [max_elt_inter s1 s2] is {!unsigned_max_elt} of {{!inter}[inter s1 s2]},
but faster as it does not require computing the whole intersection.
Returns [None] when the intersection is empty.
@since v0.11.0 *)valmax_elt_inter:t->t->eltoption(** {1 Conversion functions} *)(** [to_seq st] iterates the whole set, in increasing unsigned order of
{!to_int} *)valto_seq:t->eltSeq.t(** [to_rev_seq st] iterates the whole set, in decreasing unsigned order of
{!to_int} *)valto_rev_seq:t->eltSeq.t(** [add_seq s st] adds all elements of the sequence [s] to [st] in order.
*)valadd_seq:eltSeq.t->t->t(** [of_seq s] creates a new set from the elements of [s]. *)valof_seq:eltSeq.t->t(** [of_list l] creates a new set from the elements of [l]. *)valof_list:eltlist->t(** [to_list s] returns the elements of [s] as a list, in increasing
unsigned order of {!to_int} *)valto_list:t->eltlist(** {1 Smtml Specific} *)(** [hash set] computes the hash of a set. *)valhash:t->int(** [to_int set] converts a set to an integer. *)valto_int:t->int(** [equal set1 set2] compares two sets for equality. *)valequal:t->t->bool(** [compare set1 set2] compares two sets lexicographically. *)valcompare:t->t->int(** [get_symbols exprs] extracts all symbolic variables from a list of
expressions. *)valget_symbols:t->Symbol.tlistend(** {1 Bitvectors} *)moduleBitv:sig(** Bitvector operations for 8-bit integers. *)moduleI8:Constructors_intf.Infixwithtypeelt:=intandtypet:=t(** Bitvector operations for 32-bit integers. *)moduleI32:Constructors_intf.Infixwithtypeelt:=int32andtypet:=t(** Bitvector operations for 64-bit integers. *)moduleI64:Constructors_intf.Infixwithtypeelt:=int64andtypet:=tend(** {1 Floating-Points} *)moduleFpa:sig(** Floating-point operations for 32-bit floats. *)moduleF32:Constructors_intf.Infixwithtypeelt:=floatandtypet:=t(** Floating-point operations for 64-bit floats. *)moduleF64:Constructors_intf.Infixwithtypeelt:=floatandtypet:=tendend