View source with formatted comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2006-2023, University of Amsterdam
    7                              VU University Amsterdam
    8                              SWI-Prolog Solutions b.v.
    9    All rights reserved.
   10
   11    Redistribution and use in source and binary forms, with or without
   12    modification, are permitted provided that the following conditions
   13    are met:
   14
   15    1. Redistributions of source code must retain the above copyright
   16       notice, this list of conditions and the following disclaimer.
   17
   18    2. Redistributions in binary form must reproduce the above copyright
   19       notice, this list of conditions and the following disclaimer in
   20       the documentation and/or other materials provided with the
   21       distribution.
   22
   23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   26    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   27    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   28    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   29    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   30    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   31    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   33    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34    POSSIBILITY OF SUCH DAMAGE.
   35*/
   36
   37:- module(error,
   38          [ instantiation_error/1,      % +FormalSubTerm
   39            uninstantiation_error/1,    % +Culprit
   40            type_error/2,               % +ValidType, +Culprit
   41            domain_error/2,             % +ValidDomain, +Culprit
   42            existence_error/2,          % +ObjectType, +Culprit
   43            existence_error/3,          % +ObjectType, +Culprit, +Set
   44            permission_error/3,         % +Operation, +PermissionType, +Culprit
   45            representation_error/1,     % +Flag
   46            resource_error/1,           % +Resource
   47            syntax_error/1,             % +ImplDepAtom
   48
   49            must_be/2,                  % +Type, +Term
   50            is_of_type/2,               % +Type, +Term
   51            current_type/3              % ?Type, @Var, -Body
   52          ]).   53:- set_prolog_flag(generate_debug_info, false).   54:- use_module(library(debug), [assertion/1]).   55
   56/** <module> Error generating support
   57
   58This  module  provides  predicates  to  simplify  error  generation  and
   59checking. It's implementation is based on a discussion on the SWI-Prolog
   60mailinglist on best practices in error   handling. The utility predicate
   61must_be/2  provides  simple  run-time  type    validation.  The  *_error
   62predicates are simple wrappers around throw/1   to simplify throwing the
   63most common ISO error terms.
   64
   65@author Jan Wielemaker
   66@author Richard O'Keefe
   67@author Ulrich Neumerkel
   68@see    library(debug) and library(prolog_stack).
   69@see    print_message/2 is used to print (uncaught) error terms.
   70*/
   71
   72:- multifile
   73    has_type/2.   74
   75                 /*******************************
   76                 *           ISO ERRORS         *
   77                 *******************************/
   78
   79%!  type_error(+ValidType, +Culprit).
   80%
   81%   Tell the user that Culprit is not   of  the expected ValidType. This
   82%   error is closely related to  domain_error/2   because  the notion of
   83%   types is not really  set  in  stone   in  Prolog.  We  introduce the
   84%   difference using a simple example.
   85%
   86%   Suppose an argument must be a   non-negative  integer. If the actual
   87%   argument is not an integer,  this  is   a  _type_error_.  If it is a
   88%   negative integer, it is a _domain_error_.
   89%
   90%   Typical borderline cases are predicates   accepting a compound term,
   91%   e.g.,  point(X,Y).  One  could  argue  that  the  basic  type  is  a
   92%   compound-term and any other compound term   is  a domain error. Most
   93%   Prolog programmers consider each  compound  as   a  type  and  would
   94%   consider a compound that is not point(_,_) a _type_error_.
   95
   96type_error(ValidType, Culprit) :-
   97    throw(error(type_error(ValidType, Culprit), _)).
   98
   99%!  domain_error(+ValidDomain, +Culprit).
  100%
  101%   The argument is of the proper type, but  has a value that is outside
  102%   the  supported  values.  See  type_error/2   for  a  more  elaborate
  103%   discussion of the distinction between type- and domain-errors.
  104
  105domain_error(ValidDomain, Culprit) :-
  106    throw(error(domain_error(ValidDomain, Culprit), _)).
  107
  108%!  existence_error(+ObjectType, +Culprit).
  109%
  110%   Culprit is of the correct type and   correct domain, but there is no
  111%   existing (external) resource of type  ObjectType that is represented
  112%   by it.
  113
  114existence_error(ObjectType, Culprit) :-
  115    throw(error(existence_error(ObjectType, Culprit), _)).
  116
  117%!  existence_error(+ObjectType, +Culprit, +Set).
  118%
  119%   Culprit is of the correct type and   correct domain, but there is no
  120%   existing (external) resource of type  ObjectType that is represented
  121%   by it in the provided  set.  The   thrown  exception  term carries a
  122%   formal  term  structured  as   follows:  existence_error(ObjectType,
  123%   Culprit, Set)
  124%
  125%   @compat This error is outside the ISO Standard.
  126
  127existence_error(ObjectType, Culprit, Set) :-
  128    throw(error(existence_error(ObjectType, Culprit, Set), _)).
  129
  130%!  permission_error(+Operation, +PermissionType, +Culprit).
  131%
  132%   It is not allowed to perform   Operation on (whatever is represented
  133%   by) Culprit that is of the given   PermissionType  (in fact, the ISO
  134%   Standard is confusing and vague about these terms' meaning).
  135
  136permission_error(Operation, PermissionType, Culprit) :-
  137    throw(error(permission_error(Operation, PermissionType, Culprit), _)).
  138
  139%!  instantiation_error(+FormalSubTerm).
  140%
  141%   An argument is under-instantiated. I.e. it   is not acceptable as it
  142%   is, but if some variables are bound   to appropriate values it would
  143%   be acceptable.
  144%
  145%   @param  FormalSubTerm is the term that needs (further)
  146%           instantiation. Unfortunately, the ISO error does not allow
  147%           for passing this term along with the error, but we pass it
  148%           to this predicate for documentation purposes and to allow
  149%           for future enhancement.
  150
  151instantiation_error(_FormalSubTerm) :-
  152    throw(error(instantiation_error, _)).
  153
  154%!  uninstantiation_error(+Culprit)
  155%
  156%   An argument is over-instantiated. This  error   is  used  for output
  157%   arguments whose value cannot be known upfront. For example, the goal
  158%   open(File, read, input)  cannot  succeed   because  the  system will
  159%   allocate a new unique  stream  handle   that  will  never unify with
  160%   `input`.
  161
  162uninstantiation_error(Culprit) :-
  163    throw(error(uninstantiation_error(Culprit), _)).
  164
  165%!  representation_error(+Flag).
  166%
  167%   A representation error indicates a limitation of the implementation.
  168%   SWI-Prolog has no such limits that are  not covered by other errors,
  169%   but  an  example  of  a  representation   error  in  another  Prolog
  170%   implementation could be an attempt to create   a  term with an arity
  171%   higher than supported by the system.
  172
  173representation_error(Flag) :-
  174    throw(error(representation_error(Flag), _)).
  175
  176%!  syntax_error(+Culprit)
  177%
  178%   A text has invalid  syntax.  The   error  is  described  by Culprit.
  179%   According   to   the   ISO   Standard,    Culprit   should   be   an
  180%   implementation-dependent atom.
  181%
  182%   @tbd    Deal with proper description of the location of the
  183%           error.  For short texts, we allow for Type(Text), meaning
  184%           Text is not a valid Type.  E.g. syntax_error(number('1a'))
  185%           means that =1a= is not a valid number.
  186
  187syntax_error(Culprit) :-
  188    throw(error(syntax_error(Culprit), _)).
  189
  190%!  resource_error(+Resource)
  191%
  192%   A goal cannot be completed due to   lack  of resources. According to
  193%   the ISO Standard, Resource  should   be  an implementation-dependent
  194%   atom.
  195
  196resource_error(Resource) :-
  197    throw(error(resource_error(Resource), _)).
  198
  199
  200                 /*******************************
  201                 *            MUST-BE           *
  202                 *******************************/
  203
  204%!  must_be(+Type, @Term) is det.
  205%
  206%   True if Term satisfies the type constraints for Type. Defined
  207%   types are =atom=, =atomic=, =between=, =boolean=, =callable=,
  208%   =chars=, =codes=, =text=, =compound=, =constant=, =float=,
  209%   =integer=, =nonneg=, =positive_integer=, =negative_integer=,
  210%   =nonvar=, =number=, =oneof=, =list=, =list_or_partial_list=,
  211%   =symbol=, =var=, =rational=, =encoding=, =dict= and =string=.
  212%
  213%   Most of these types are defined by an arity-1 built-in predicate
  214%   of the same name. Below  is  a   brief  definition  of the other
  215%   types.
  216%
  217%   | acyclic | Acyclic term (tree); see acyclic_term/1 |
  218%   | any | any term |
  219%   | between(FloatL,FloatU) | Number [FloatL..FloatU] |
  220%   | between(IntL,IntU) | Integer [IntL..IntU] |
  221%   | boolean | One of =true= or =false= |
  222%   | callable | Atom or compound term |
  223%   | char | Atom of length 1 |
  224%   | chars | Proper list of 1-character atoms |
  225%   | code | Representation Unicode code point (0..0x10ffff) |
  226%   | codes | Proper list of Unicode character codes |
  227%   | compound | compound term |
  228%   | compound(Term) | Compound with same name/arity as term; checks arguments |
  229%   | constant | Same as `atomic` |
  230%   | cyclic | Cyclic term (rational tree); see cyclic_term/1 |
  231%   | dict | A dictionary term; see is_dict/1 |
  232%   | encoding | Valid name for a character encoding; see current_encoding/1 |
  233%   | list | A (non-open) list; see is_list/1 |
  234%   | list(Type) | Proper list with elements of Type |
  235%   | list_or_partial_list | A list or an open list (ending in a variable); see is_list_or_partial_list/1 |
  236%   | negative_integer | Integer < 0 |
  237%   | nonneg | Integer >= 0 |
  238%   | oneof(L) | Ground term that is member of L |
  239%   | pair | Key-Value pair.  Same as compound(any-any) |
  240%   | positive_integer | Integer > 0 |
  241%   | proper_list | Same as list |
  242%   | stream | A stream name or valid stream handle; see is_stream/1 |
  243%   | symbol | Same as `atom` |
  244%   | text | One of =atom=, =string=, =chars= or =codes= |
  245%   | type | Term is a valid type specification |
  246%
  247%   In  addition,  types   may   be    composed   using   `TypeA,TypeB`,
  248%   `TypeA;TypeB` and negated using `\Type`.
  249%
  250%   @throws instantiation_error if Term is insufficiently
  251%   instantiated and type_error(Type, Term) if Term is not of Type.
  252
  253must_be(Type, X) :-
  254    (   nonvar(Type),
  255        has_type(Type, X)
  256    ->  true
  257    ;   nonvar(Type)
  258    ->  is_not(Type, X)
  259    ;   instantiation_error(Type)
  260    ).
  261
  262%!  is_not(+Type, @Term)
  263%
  264%   Throws appropriate error. It is _known_ that Term is not of type
  265%   Type.
  266%
  267%   @throws type_error(Type, Term)
  268%   @throws instantiation_error
  269
  270is_not(list, X) :-
  271    !,
  272    not_a_list(list, X).
  273is_not(list(Of), X) :-
  274    !,
  275    not_a_list(list(Of), X).
  276is_not(list_or_partial_list, X) :-
  277    !,
  278    type_error(list, X).
  279is_not(chars, X) :-
  280    !,
  281    not_a_list(list(char), X).
  282is_not(codes, X) :-
  283    !,
  284    not_a_list(list(code), X).
  285is_not(var,X) :-
  286    !,
  287    uninstantiation_error(X).
  288is_not(cyclic, X) :-
  289    domain_error(cyclic_term, X).
  290is_not(acyclic, X) :-
  291    domain_error(acyclic_term, X).
  292is_not(Type, X) :-
  293    current_type(Type, _Var, _Body),
  294    !,
  295    (   var(X)
  296    ->  instantiation_error(X)
  297    ;   ground_type(Type), \+ ground(X)
  298    ->  instantiation_error(X)
  299    ;   type_error(Type, X)
  300    ).
  301is_not(Type, _) :-
  302    existence_error(type, Type).
  303
  304ground_type(ground).
  305ground_type(oneof(_)).
  306ground_type(stream).
  307ground_type(text).
  308ground_type(string).
  309ground_type(rational).
  310
  311not_a_list(Type, X) :-
  312    '$skip_list'(_, X, Rest),
  313    (   var(Rest)
  314    ->  instantiation_error(X)
  315    ;   Rest == []
  316    ->  Type = list(Of),
  317        (   nonvar(Of)
  318        ->  element_is_not(X, Of)
  319        ;   instantiation_error(Of)
  320        )
  321    ;   type_error(Type, X)
  322    ).
  323
  324
  325element_is_not([H|T], Of) :-
  326    has_type(Of, H),
  327    !,
  328    element_is_not(T, Of).
  329element_is_not([H|_], Of) :-
  330    !,
  331    is_not(Of, H).
  332element_is_not(_List, _Of) :-
  333    assertion(fail).
  334
  335%!  is_of_type(+Type, @Term) is semidet.
  336%
  337%   True if Term satisfies Type.
  338
  339is_of_type(Type, Term) :-
  340    nonvar(Type),
  341    !,
  342    has_type(Type, Term),
  343    !.
  344is_of_type(Type, _) :-
  345    instantiation_error(Type).
  346
  347%!  has_type(+Type, @Term) is semidet.
  348%
  349%   True if Term satisfies Type.
  350
  351:- '$clausable'(has_type/2).            % always allow clause/2
  352:- public                               % May be called through current_type/3
  353    is_list_or_partial_list/1,
  354    current_encoding/1,
  355    element_types/2.  356
  357has_type(any, _).
  358has_type(atom, X)         :- atom(X).
  359has_type(atomic, X)       :- atomic(X).
  360has_type(between(L,U), X) :- (   integer(L)
  361    ->  integer(X), between(L,U,X)
  362    ;   number(X), X >= L, X =< U
  363    ).
  364has_type(boolean, X)      :- (X==true;X==false), !.
  365has_type(callable, X)     :- callable(X).
  366has_type(char,  X)        :- '$is_char'(X).
  367has_type(code,  X)        :- '$is_char_code'(X).
  368has_type(chars, X)        :- '$is_char_list'(X, _Len).
  369has_type(codes, X)        :- '$is_code_list'(X, _Len).
  370has_type(text, X)         :- text(X).
  371has_type(compound, X)     :- compound(X).
  372has_type(compound(Term),X):- compound(X), is_term_of_type(Term,X).
  373has_type(constant, X)     :- atomic(X).
  374has_type(float, X)        :- float(X).
  375has_type(ground, X)       :- ground(X).
  376has_type(cyclic, X)       :- cyclic_term(X).
  377has_type(acyclic, X)      :- acyclic_term(X).
  378has_type(integer, X)      :- integer(X).
  379has_type(nonneg, X)       :- integer(X), X >= 0.
  380has_type(positive_integer, X)     :- integer(X), X > 0.
  381has_type(negative_integer, X)     :- integer(X), X < 0.
  382has_type(nonvar, X)       :- nonvar(X).
  383has_type(number, X)       :- number(X).
  384has_type(oneof(L), X)     :- ground(X), \+ \+ memberchk(X, L).
  385has_type(pair, X)         :- nonvar(X), X = _-_.
  386has_type(proper_list, X)  :- is_list(X).
  387has_type(list, X)         :- is_list(X).
  388has_type(list_or_partial_list, X)  :- is_list_or_partial_list(X).
  389has_type(symbol, X)       :- atom(X).
  390has_type(var, X)          :- var(X).
  391has_type(rational, X)     :- rational(X).
  392has_type(string, X)       :- string(X).
  393has_type(stream, X)       :- is_stream(X).
  394has_type(encoding, X)     :- current_encoding(X).
  395has_type(dict, X)         :- is_dict(X).
  396has_type(list(Type), X)   :- is_list(X), element_types(X, Type).
  397has_type(list_or_partial_list(Type), X)   :- is_list_or_partial_list(X), element_types(X, Type).
  398has_type(type, Type)      :- ground(Type), current_type(Type,_,_).
  399has_type((A,B), X)	  :- (is_of_type(A,X)->is_of_type(B,X)).
  400has_type((A;B), X)	  :- (is_of_type(A,X)->true;is_of_type(B,X)).
  401has_type(\A, X)	          :- \+ is_of_type(A,X).
  402
  403text(X) :-
  404    (   atom(X)
  405    ;   string(X)
  406    ;   '$is_char_list'(X, _)
  407    ;   '$is_code_list'(X, _)
  408    ),
  409    !.
  410
  411element_types(List, Type) :-
  412    nonvar(Type),
  413    !,
  414    element_types_(List, Type).
  415element_types(_List, Type) :-
  416    instantiation_error(Type).
  417
  418element_types_(Var, _) :-
  419    var(Var),
  420    !.
  421element_types_([], _).
  422element_types_([H|T], Type) :-
  423    has_type(Type, H),
  424    !,
  425    element_types_(T, Type).
  426
  427is_list_or_partial_list(L0) :-
  428    '$skip_list'(_, L0,L),
  429    ( var(L) -> true ; L == [] ).
  430
  431%!  current_encoding(?Name) is nondet.
  432%
  433%   True if Name is the name of   a supported encoding. See encoding
  434%   option of e.g., open/4.
  435
  436current_encoding(octet).
  437current_encoding(ascii).
  438current_encoding(iso_latin_1).
  439current_encoding(text).
  440current_encoding(utf8).
  441current_encoding(unicode_be).
  442current_encoding(unicode_le).
  443current_encoding(wchar_t).
  444
  445
  446%!  current_type(?Type, @Var, -Body) is nondet.
  447%
  448%   True when Type is a currently defined type and Var satisfies Type of
  449%   the body term Body succeeds.
  450
  451current_type(Type, Var, Body) :-
  452    clause(has_type(Type, Var), Body0),
  453    qualify(Body0, Body).
  454
  455qualify(Var, VarQ) :-
  456    var(Var),
  457    !,
  458    VarQ = Var.
  459qualify((A0,B0), (A,B)) :-
  460    qualify(A0, A),
  461    qualify(B0, B).
  462qualify(G0, G) :-
  463    predicate_property(system:G0, built_in),
  464    !,
  465    G = G0.
  466qualify(G, error:G).
  467
  468%!  is_term_of_type(Term, X)
  469%
  470%   Supports types as e.g. compound(oneof(list(atom))).
  471
  472is_term_of_type(Term, X) :-
  473    compound_name_arity(Term, N, A),
  474    compound_name_arity(X, N, A),
  475    term_arg_types(1, A, Term, X).
  476
  477term_arg_types(I, A, Type, X) :-
  478    I =< A,
  479    !,
  480    arg(I, Type, AType),
  481    arg(I, X, XArg),
  482    has_type(AType, XArg),
  483    I2 is I+1,
  484    term_arg_types(I2, A, Type, X).
  485term_arg_types(_, _, _, _).
  486
  487
  488		 /*******************************
  489		 *           SANDBOX		*
  490		 *******************************/
  491
  492:- multifile sandbox:safe_primitive/1.  493
  494sandbox:safe_primitive(error:current_type(_,_,_))