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