% ---------------------------------------------------------------------------- :- export assertion_body/1, head_pattern/1, % property_conjunction/1, % property_starterm/1, % complex_goal_property/1, % nabody/1, % dictionary/1, % c_assrt_body/1, s_assrt_body/1, g_assrt_body/1, assrt_status/1. % assrt_type/1, % predfunctor/1, % propfunctor/1. % ---------------------------------------------------------------------------- :- comment(title,"The XSB Assertion Library"). :- comment(module,"This module is under development and is subject to change. Assertions in this style will be documented by xsbdoc, but no type checking is done yet by the compiler. The @lib{assertions} module has many of the same goals of the CIAO assertions package, but is much simpler in syntax. Currently all assertions (apart from machine readible comments) are specified via the compiler directive @begin{verbatim} :- pred HeadPattern :: AssertionBody. @end{verbatim} where @tt{head_pattern(HeadPattern)} and @tt{AssertionBody} are both true. The idea is that each such declaration defines a @concept{usage} of a predicate -- a call pattern and an associated success pattern. The exact syntax is described in documentation for the predicates @pred{head_pattern/1} and @pred{assertion_body/1}. Such patterns are certainly useful for documentation, and @apl{xsbdoc} is includes these patterns in the documentation it generates (see @ref{Introduction} for information on how to contol formatting of such documentation). However, such information can also be useful for compilation tools, such as a run-time test generator (under development) or static analysis. "). % ---------------------------------------------------------------------------- :- comment(assertion_body/1,"This predicate succeeds if its argument is true. In XSB, assertion bodies are much simpler than in Ciao. An assertion body is a list of up to 5 terms. These are: @begin{itemize} @item @tt{call_prop(Comma_list)} which contains a comma list of predicates which are true of given arguments when the predicate is called for a given usage of a predicate to be true. @item @tt{success_prop(Comma_list)} which contains a comma list of predicates which must be true of given arguments when the predicate succedes for this usage. @item @tt{global_prop(Comma_list)} which contains a comma list of predicates which must be true of given arguments at any point during an execution. @item @tt{compat_prop(Comma_list)} which contains a comma list of predicates which must be true for this usage that do not fit into one of the other properties, for instance that the this usage of the predicate does not fail. @item @tt{comment(Docstring)} which contains a string of type @pred{docstring/1} which describes this usage. @end{itemize} An example is of an assertion body occurs in the following predicate: @begin{verbatim} :- pred foo(X,Y) :: [call_prop((nonvar(X),var(Y))), success_prop((ground(X),ground(Y)))] @end{verbatim} "). :- comment(head_pattern/1,"A @concept{head pattern} can be a predicate name (functor/arity) (@pred{predname/1}) or a term. Thus, both @tt{p/3} and @tt{p(A,B,C)} are valid head patterns. In the case in which the head pattern is a term, each argument of such a term can be: @begin{itemize} @item A variable. This is useful in order to be able to refer to the corresponding argument positions by name within properties and in comments. Thus, @tt{p(Input,Parameter,Output)} is a valid head pattern. @item A term. In this case, the fact that a given argument unifies with a particular term is a global property of the usage. An example is the pattern @begin{verbatim} comment(module,Docstring) @end{verbatim} which indicates that the first argument is always unifiable with the atom @tt{module}. @end{itemize} @comment{ In this case this term determines a property of the corresponding argument. The actual property referred to is that given by the term but with one more argument added at the beginning, which is a new variable which, in a rewriting of the head pattern, appears at the argument position occupied by the term. Unless otherwise stated (see below), the property built this way is understood to hold for both calls and answers. For example, the head pattern @tt{p(Input,list(integer),Output)} is valid and equivalent for example to having the head pattern @tt{p(Input,A,Output)} and stating that the property @tt{list(A,integer)} holds for the calls and successes of the predicate. @item Finally, it can also be a variable or a ground term, as above, but preceded by a ``@concept{mode}.'' This mode determines in a compact way certain call or answer properties. For example, the head pattern @tt{p(Input,+list(integer),Output)} is valid, as long as @pred{+/1} is declared as a mode. Acceptable modes @cindex{acceptable modes} are documented in @lib{library(modes)}. User defined modes are documented in @pred{modedef/1}. } "). head_pattern(Pr) :- predname(Pr). head_pattern(Pr) :- Pr =.. [P|Args], atom(P), acceptable_args(Args). acceptable_args([]). acceptable_args([A|As]) :- acceptable_arg(A), acceptable_args(As). acceptable_arg(A) :- var(A). acceptable_arg(A) :- ground(A). acceptable_arg(A) :- A =.. [M,V], %%% Needs to be updated for the new mode definitions! mode(M), acceptable_arg(V). % imprecise... mode(_). :- comment(property_conjunction/1,"This type defines the first, unabridged format in which properties can be expressed in the bodies of assertions. It is essentially a conjunction of properties which refer to variables. The following is an example of a complex property in this format: @begin{itemize} @item @tt{(integer(X),list(Y,integer))}: @var{X} has the property @pred{integer/1} and @var{Y} has the property @pred{list/2}, with second argument @tt{integer}. @end{itemize} "). :- prop property_conjunction(Props) + (regtype) # "@var{Props} is either a term or a @em{conjunction} of terms. The main functor and arity of each of those terms corresponds to the definition of a property. The first argument of each such term is a variable which appears as a head argument.". property_conjunction(P) :- property(P). property_conjunction((P1,P2)) :- property(P1), property(P2). :- comment(property_starterm/1,"This type defines a second, compact format in which properties can be expressed in the bodies of assertions. A @pred{property_starterm/1} is a term whose main functor is @op{*/2} and, when it appears in an assertion, the number of terms joined by @op{*/2} is exactly the arity of the predicate it refers to. A similar series of properties as in @pred{property_conjunction/1} appears, but the arity of each property is one less: the argument position to which they refer (first argument) is left out and determined by the position of the property in the @pred{property_starterm/1}. The idea is that each element of the @op{*/2} term corresponds to a head argument position. Several properties can be assigned to each argument position by grouping them in curly brackets. The following is an example of a complex property in this format: @begin{itemize} @item @tt{ integer * list(integer)}: the first argument of the procedure (or function, or ...) has the property @pred{integer/1} and the second one has the property @pred{list/2}, with second argument @tt{integer}. @item @tt{ @{integer,var@} * list(integer)}: the first argument of the procedure (or function, or ...) has the properties @pred{integer/1} and @pred{var/1} and the second one has the property @pred{list/2}, with second argument @tt{integer}. @end{itemize} "). :- prop property_starterm(Props) + (regtype) # "@var{Props} is either a term or several terms separated by @op{*/2}. The main functor of each of those terms corresponds to that of the definition of a property, and the arity should be one less than in the definition of such property. All arguments of each such term are ground.". property_starterm(AP) :- abridged_property(AP). property_starterm(AP1*AP2) :- abridged_property(AP1), abridged_property(AP2). property(P) :- P =.. [_|Args], contains_var(Args). contains_var([A|_As]):- var(A). contains_var([_A|As]):- contains_var(As). abridged_property(P) :- P =.. [_|Args], ground(Args). :- comment(complex_goal_property(Props), "@var{Props} is a (possibly empty) @concept{complex goal property}. Such properties can be either a term or a @em{conjunction} of terms. The main functor and arity of each of those terms corresponds to the definition of a property. Such properties apply to all executions of all goals of the predicate which comply with the assertion in which the @var{Props} appear. The arguments of the terms in @var{Props} are implicitely augmented with a first argument which corresponds to a goal of the predicate of the assertion in which the @var{Props} appear. For example, the assertion @begin{verbatim} :- comp var(A) + not_further_inst(A). @end{verbatim} has property @pred{not_further_inst/1} as goal property, and establishes that in all executions of @tt{var(A)} it should hold that @tt{not_further_inst(var(A),A)}. "). :- prop complex_goal_property(Props) + (regtype) # "@var{Props} is either a term or a @em{conjunction} of terms. The main functor and arity of each of those terms corresponds to the definition of a property. A first implicit argument in such terms identifies goals to which the properties apply.". % imprecise... complex_goal_property(CP) :- property_conjunction(CP). :- prop nabody(ABody) # "@var{ABody} is a normalized assertion body.". nabody((Pred::Compat:Call=>Succ+Comp#Comm)):- head_pattern(Pred), list(Compat,property), list(Call,property), list(Succ,property), list(Comp,property), docstring(Comm). /* :- (regtype) dictionary(D) # "@var{D} is a dictionary of variable names.". */ dictionary([]). dictionary([N=V|D]):- string(N), var(V), dictionary(D). :- prop c_assrt_body(X) + (regtype) # "@var{X} is a call assertion body.". :- comment(c_assrt_body/1," @cindex{assertion body syntax} This predicate defines the different types of syntax admissible in the bodies of @pred{call/1}, @pred{entry/1}, etc. assertions. The following are admissible: @begin{verbatim} Pr : CP [# CO] @end{verbatim} where (fields between [...] are optional): @begin{itemize} @item @var{CP} is a (possibly empty) @concept{complex argument property} (@pred{complex_arg_property/1}) which applies to the @em{calls} to the predicate. @item @var{CO} is a @concept{comment string} (@pred{docstring/1}). This comment only applies if the (possibly empty) properties given for calls in the assertion hold. The usual formatting commands that are applicable in comment strings can be used (see @pred{stringcommand/1}). @end{itemize} The format of the different parts of the assertion body are given by @pred{n_assrt_body/5} and its auxiliary types. "). c_assrt_body((Pr :CP #CO)):- n_assrt_body(nabody(Pr,CP,true,true,CO)). c_assrt_body((Pr :CP)):- n_assrt_body(nabody(Pr,CP,true,true,true)). :- prop s_assrt_body(X) + (regtype) # "@var{X} is a predicate assertion body.". :- comment(s_assrt_body/1," @cindex{assertion body syntax} This predicate defines the different types of syntax admissible in the bodies of @pred{pred/1}, @pred{func/1}, etc. assertions. The following are admissible: @begin{verbatim} Pr : CP => AP # CO Pr : CP => AP Pr => AP # CO Pr => AP @end{verbatim} where: @begin{itemize} @item @var{Pr} is a @concept{head pattern} (@pred{head_pattern/1}) which describes the predicate or property and possibly gives some implicit call/answer information. @item @var{CP} is a (possibly empty) @concept{complex argument property} (@pred{complex_arg_property/1}) which applies to the @em{calls} to the predicate. @item @var{AP} is a (possibly empty) @concept{complex argument property} (@pred{complex_arg_property/1}) which applies to the @em{answers} to the predicate (if the predicate succeeds). These only apply if the (possibly empty) properties given for calls in the assertion hold. @item @var{CO} is a @concept{comment string} (@pred{docstring/1}). This comment only applies if the (possibly empty) properties given for calls in the assertion hold. The usual formatting commands that are applicable in comment strings can be used (see @pred{stringcommand/1}). @end{itemize} The format of the different parts of the assertion body are given by @pred{n_assrt_body/5} and its auxiliary types. "). s_assrt_body((Pr :CP=>AP#CO)):- n_assrt_body(nabody(Pr,CP,AP,true,CO)). s_assrt_body((Pr :CP=>AP)):- n_assrt_body(nabody(Pr,CP,AP,true,true)). s_assrt_body((Pr=>AP #CO)):- n_assrt_body(nabody(Pr,true,AP,true,CO)). s_assrt_body((Pr=>AP )):- n_assrt_body(nabody(Pr,true,AP,true,true)). :- prop g_assrt_body(X) + (regtype) # "@var{X} is a comp assertion body.". :- comment(g_assrt_body/1," @cindex{assertion body syntax} This predicate defines the different types of syntax admissible in the bodies of @pred{comp/1} assertions. The following are admissible: @begin{verbatim} Pr : CP + GP # CO Pr : CP + GP Pr + GP # CO Pr + GP @end{verbatim} where: @begin{itemize} @item @var{Pr} is a @concept{head pattern} (@pred{head_pattern/1}) which describes the predicate or property and possibly gives some implicit call/answer information. @item @var{CP} is a (possibly empty) @concept{complex argument property} (@pred{complex_arg_property/1}) which applies to the @em{calls} to the predicate. @item @var{GP} contains (possibly empty) @concept{complex goal property} (@pred{complex_goal_property/1}) which applies to the @em{whole execution} of a call to the predicate. These only apply if the (possibly empty) properties given for calls in the assertion hold. @item @var{CO} is a @concept{comment string} (@pred{docstring/1}). This comment only applies if the (possibly empty) properties given for calls in the assertion hold. The usual formatting commands that are applicable in comment strings can be used (see @pred{stringcommand/1}). @end{itemize} The format of the different parts of the assertion body are given by @pred{n_assrt_body/5} and its auxiliary types. "). g_assrt_body((Pr :CP +GP#CO)):- n_assrt_body(nabody(Pr,CP,true,GP,CO)). g_assrt_body((Pr :CP +GP)):- n_assrt_body(nabody(Pr,CP,true,GP,true)). g_assrt_body((Pr +GP #CO)):- n_assrt_body(nabody(Pr,true,true,GP,CO)). g_assrt_body((Pr +GP)):- n_assrt_body(nabody(Pr,true,true,GP,true)). %% %% Still too advanced for the automatic documenter... %% :- regtype n_assrt_body(B) : %% ( B = nabody(Pr,CP,AP,GP,CO), %% head_pattern(Pr), %% complex_arg_property(CP), %% complex_arg_property(AP), %% goal_properties(GP), %% string(CO) %% ) %% %% # "This is an auxiliary type definition which defines the types of %% the args that may appear in the bodies of assertions.". %% Left out so that we see the warning... %% :- regtype n_assrt_body(B) # %% # "This is an auxiliary type definition which defines the types of %% the args that may appear in the bodies of assertions.". n_assrt_body(nabody(Pr,CP,AP,GP,CO)) :- head_pattern(Pr), complex_arg_property(CP), complex_arg_property(AP), complex_goal_property(GP), docstring(CO). :- comment(assrt_status/1,"The types of assertion status. They have the same meaning as the program-point assertions, and are as follows: @includedef{assrt_status/1}. TLS No checking is yet implemented in XSB."). /* :- prop assrt_status(X) + (regtype) # "@var{X} is an acceptable status for an assertion.". */ assrt_status(true). assrt_status(false). assrt_status(check). assrt_status(checked). assrt_status(trust). :- comment(assrt_type/1,"The admissible kinds of assertions: @includedef{assrt_type/1}"). :- prop assrt_type(X) + (regtype) # "@var{X} is an admissible kind of assertion.". assrt_type(pred). assrt_type(prop). assrt_type(decl). assrt_type(func). % These are actually quite different: %% assrt_type(compat). %% Not using these any more. assrt_type(calls). assrt_type(success). assrt_type(comp). assrt_type(entry). %% assrt_type(trust). % As well as this one! %% If this is not here then modedefs are not accepted by normalization pass one assrt_type(modedef). :- prop predfunctor(X) + (regtype) # "@var{X} is a type of assertion which defines a predicate.". predfunctor(pred). predfunctor(prop). predfunctor(decl). %% ?? predfunctor(func). %% ?? predfunctor(modedef). :- prop propfunctor(X) + (regtype) # "@var{X} is a type of assertion which defines a @em{property}.". propfunctor(prop). :- prop docstring(String) # "@var{String} is a text comment with admissible documentation commands. The usual formatting commands that are applicable in comment strings are defined by @pred{stringcommand/1}. See the @apl{lpdoc} manual for documentation on comments. ". :- pred check(PropertyConjunction) : property_conjunction # "@cindex{check assertion} This assertion provides information on a clause program point (position in the body of a clause). Calls to a @pred{check/1} assertion can appear in the body of a clause in any place where a literal can normally appear. The property defined by @var{PropertyConjunction} should hold in all the run-time stores corresponding to that program point. See also @ref{Run-time checking of assertions}.". check(_). :- pred trust(PropertyConjunction) : property_conjunction # "@cindex{trust assertion} This assertion also provides information on a clause program point. It is identical syntactically to a @pred{check/1} assertion. However, the properties stated are not taken as something to be checked but are instead @em{trusted} by the compiler. While the compiler may in some cases detect an inconsistency between a @pred{trust/1} assertion and the program, in all other cases the information given in the assertion will be taken to be true. As a result, if these assertions are erroneous they can introduce bugs in programs. Thus, @pred{trust/1} assertions should be written with care. An important use of these assertions is in @concept{providing information to the compiler} which it may not be able to infer from the program (either because the information is not present or because the analyzer being used is not precise enough). In particular, providing information on external predicates which may not be accessible at the time of compiling the module can greatly improve the precision of the analyzer. This can be easily done with trust assertion. ". trust(_). :- pred true(PropertyConjunction) : property_conjunction # "@cindex{true assertion} This assertion is identical syntactically to a @pred{check/1} assertion. However, the properties stated have been proved to hold by the analyzer. Thus, these assertions often represent the @concept{analyzer output}.". true(_). :- pred false(PropertyConjunction) : property_conjunction # "@cindex{false assertion} This assertion is identical syntactically to a @pred{check/1} assertion. However, the properties stated have been proved not to hold by the analyzer. Thus, these assertions often represent the @concept{analyzer output}.". false(_). end_of_file. % ---------------------------------------------------------------------------- :- comment(version_maintenance,dir('../../version')). :- comment(version(1*5+25,1999/12/29,12:46*08+'CET'), "Added properties @tt{nabody/1} and @tt{dictionary/1}. (Francisco Bueno Carrillo)"). :- comment(version(0*9+98,1999/05/25,17:01*28+'MEST'), "Comments for most of the properties here changed according to last changes in semantics. (Francisco Bueno Carrillo)"). :- comment(version(0*8+11,1998/12/01,13:25*39+'MET'), "Updated comment symbol and type decls (but still quite outdated). (Manuel Hermenegildo)"). :- comment(version(0*5+47,1998/07/08,16:48*24+'MET DST'), "Made trust be a status again. (Francisco Bueno Carrillo)"). :- comment(version(0*4+7,1998/1/22), "Added assertions status, etc. (Manuel Hermenegildo)"). :- comment(version(0*4+6,1997/12/16), "Split out properties and types. (Manuel Hermenegildo)"). :- comment(module,"This module is part of the @lib{assertions} library. It defines types and properties related to assertions."). % ---------------------------------------------------------------------------- :- comment(assrt_body/1," @cindex{assertion body syntax} This predicate defines the different types of syntax admissible in the bodies of @pred{pred/1}, @pred{decl/1}, etc. assertions. Such a body is of the form: @begin{verbatim} Pr [:: DP] [: CP] [=> AP] [+ GP] [# CO] @end{verbatim} where (fields between [...] are optional): @begin{itemize} @item @var{Pr} is a @concept{head pattern} (@pred{head_pattern/1}) which describes the predicate or property and possibly gives some implicit call/answer information. @item @var{DP} is a (possibly empty) @concept{complex argument property} (@pred{complex_arg_property/1}) which expresses properties which are @concept{compatible} with the predicate, i.e., instantiations made by the predicate are @em{compatible} with the properties in the sense that applying the property at any point to would not make it fail. @item @var{CP} is a (possibly empty) @concept{complex argument property} (@pred{complex_arg_property/1}) which applies to the @em{calls} to the predicate. @item @var{AP} is a (possibly empty) @concept{complex argument property} (@pred{complex_arg_property/1}) which applies to the @em{answers} to the predicate (if the predicate succeeds). These only apply if the (possibly empty) properties given for calls in the assertion hold. @item @var{GP} is a (possibly empty) @concept{complex goal property} (@pred{complex_goal_property/1}) which applies to the @em{whole execution} of a call to the predicate. These only apply if the (possibly empty) properties given for calls in the assertion hold. @item @var{CO} is a @concept{comment string} (@pred{docstring/1}). This comment only applies if the (possibly empty) properties given for calls in the assertion hold. The usual formatting commands that are applicable in comment strings can be used (see @pred{stringcommand/1}). See the @apl{lpdoc} manual for documentation on assertion comments. @end{itemize} "). assrt_body((Pr :CP=>AP+GP#CO)):- n_assrt_body(nabody(Pr,CP,AP,GP,CO)). assrt_body((Pr :CP=>AP+GP)):- n_assrt_body(nabody(Pr,CP,AP,GP,true)). assrt_body((Pr :CP=>AP#CO)):- n_assrt_body(nabody(Pr,CP,AP,true,CO)). assrt_body((Pr :CP=>AP)):- n_assrt_body(nabody(Pr,CP,AP,true,true)). assrt_body((Pr :CP +GP#CO)):- n_assrt_body(nabody(Pr,CP,true,GP,CO)). assrt_body((Pr :CP +GP)):- n_assrt_body(nabody(Pr,CP,true,GP,true)). assrt_body((Pr :CP #CO)):- n_assrt_body(nabody(Pr,CP,true,true,CO)). assrt_body((Pr :CP)):- n_assrt_body(nabody(Pr,CP,true,true,true)). assrt_body((Pr=>AP +GP#CO)):- n_assrt_body(nabody(Pr,true,AP,GP,CO)). assrt_body((Pr=>AP +GP)):- n_assrt_body(nabody(Pr,true,AP,GP,true)). assrt_body((Pr=>AP #CO)):- n_assrt_body(nabody(Pr,true,AP,true,CO)). assrt_body((Pr=>AP )):- n_assrt_body(nabody(Pr,true,AP,true,true)). assrt_body((Pr +GP #CO)):- n_assrt_body(nabody(Pr,true,true,GP,CO)). assrt_body((Pr +GP)):- n_assrt_body(nabody(Pr,true,true,GP,true)). assrt_body((Pr #CO)):- n_assrt_body(nabody(Pr,true,true,true,CO)). assrt_body((Pr)):- n_assrt_body(nabody(Pr,true,true,true,true)). % imprecise... complex_arg_property(CP) :- property_conjunction(CP). complex_arg_property(CP) :- property_starterm(CP). :- comment(complex_arg_property(Props), "@var{Props} is a (possibly empty) @concept{complex argument property}. Such properties can appear in two formats, which are defined by @pred{property_conjunction/1} and @pred{property_starterm/1} respectively. The two formats can be mixed provided they are not in the same field of an assertion. I.e., the following is a valid assertion: @tt{:- pred foo(X,Y) : nonvar * var => (ground(X),ground(Y)).} "). :- prop complex_arg_property(Props) + (regtype) # "@var{Props} is a (possibly empty) complex argument property".