View source with raw 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-2016, 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            permission_error/3,         % +Action, +Type, +Term
  41            instantiation_error/1,      % +Term
  42            uninstantiation_error/1,    % +Term
  43            representation_error/1,     % +Reason
  44            syntax_error/1,             % +Culprit
  45            resource_error/1,           % +Culprit
  46
  47            must_be/2,                  % +Type, +Term
  48            is_of_type/2                % +Type, +Term
  49          ]).
  50:- set_prolog_flag(generate_debug_info, false).
  51
  52/** <module> Error generating support
  53
  54This  module  provides  predicates  to  simplify  error  generation  and
  55checking. It's implementation is based on a discussion on the SWI-Prolog
  56mailinglist on best practices in error   handling. The utility predicate
  57must_be/2  provides  simple  run-time  type    validation.  The  *_error
  58predicates are simple wrappers around throw/1   to simplify throwing the
  59most common ISO error terms.
  60
  61@author Jan Wielemaker
  62@author Richard O'Keefe
  63@author Ulrich Neumerkel
  64@see    library(debug) and library(prolog_stack).
  65@see    print_message/2 is used to print (uncaught) error terms.
  66*/
  67
  68:- multifile
  69    has_type/2.
  70
  71                 /*******************************
  72                 *           ISO ERRORS         *
  73                 *******************************/
  74
  75%!  type_error(+Type, +Term).
  76%
  77%   Tell the user that Term is not  of the expected Type. This error
  78%   is closely related to domain_error/2 because the notion of types
  79%   is  not  really  set  in  stone  in  Prolog.  We  introduce  the
  80%   difference using a simple example.
  81%
  82%   Suppose an argument must  be  a   non-negative  integer.  If the
  83%   actual argument is not an integer, this is a _type_error_. If it
  84%   is a negative integer, it is a _domain_error_.
  85%
  86%   Typical borderline cases are  predicates   accepting  a compound
  87%   term, e.g., point(X,Y). One could argue that the basic type is a
  88%   compound-term and any other compound  term   is  a domain error.
  89%   Most Prolog programmers consider each  compound   as  a type and
  90%   would consider a compoint that is not point(_,_) a _type_error_.
  91
  92type_error(Type, Term) :-
  93    throw(error(type_error(Type, Term), _)).
  94
  95%!  domain_error(+Type, +Term).
  96%
  97%   The argument is of the proper  type,   but  has  a value that is
  98%   outside the supported  values.  See   type_error/2  for  a  more
  99%   elaborate  discussion  of  the  distinction  between  type-  and
 100%   domain-errors.
 101
 102domain_error(Type, Term) :-
 103    throw(error(domain_error(Type, Term), _)).
 104
 105%!  existence_error(+Type, +Term).
 106%
 107%   Term is of the correct type and  correct domain, but there is no
 108%   existing (external) resource that is represented by it.
 109
 110existence_error(Type, Term) :-
 111    throw(error(existence_error(Type, Term), _)).
 112
 113%!  permission_error(+Action, +Type, +Term).
 114%
 115%   It is not allowed to perform Action   on the object Term that is
 116%   of the given Type.
 117
 118permission_error(Action, Type, Term) :-
 119    throw(error(permission_error(Action, Type, Term), _)).
 120
 121%!  instantiation_error(+Term).
 122%
 123%   An argument is under-instantiated. I.e. it  is not acceptable as
 124%   it is, but if some variables are  bound to appropriate values it
 125%   would be acceptable.
 126%
 127%   @param  Term is the term that needs (further) instantiation.
 128%           Unfortunately, the ISO error does not allow for passing
 129%           this term along with the error, but we pass it to this
 130%           predicate for documentation purposes and to allow for
 131%           future enhancement.
 132
 133instantiation_error(_Term) :-
 134    throw(error(instantiation_error, _)).
 135
 136%!  uninstantiation_error(+Term)
 137%
 138%   An argument is over-instantiated. This error  is used for output
 139%   arguments whose value cannot be known  upfront. For example, the
 140%   goal open(File, read, input) cannot   succeed because the system
 141%   will allocate a new unique stream   handle that will never unify
 142%   with `input`.
 143
 144uninstantiation_error(Term) :-
 145    throw(error(uninstantiation_error(Term), _)).
 146
 147%!  representation_error(+Reason).
 148%
 149%   A  representation  error  indicates   a    limitation   of   the
 150%   implementation. SWI-Prolog has  no  such   limits  that  are not
 151%   covered by other errors, but  an   example  of  a representation
 152%   error in another Prolog implementation could   be  an attempt to
 153%   create a term with an arity higher than supported by the system.
 154
 155representation_error(Reason) :-
 156    throw(error(representation_error(Reason), _)).
 157
 158%!  syntax_error(+Culprit)
 159%
 160%   A text has invalid syntax.  The error is described by Culprit.
 161%
 162%   @tbd    Deal with proper description of the location of the
 163%           error.  For short texts, we allow for Type(Text), meaning
 164%           Text is not a valid Type.  E.g. syntax_error(number('1a'))
 165%           means that =1a= is not a valid number.
 166
 167syntax_error(Culprit) :-
 168    throw(error(syntax_error(Culprit), _)).
 169
 170%!  resource_error(+Culprit)
 171%
 172%   A goal cannot be completed due to lack of resources.
 173
 174resource_error(Culprit) :-
 175    throw(error(resource_error(Culprit), _)).
 176
 177
 178                 /*******************************
 179                 *            MUST-BE           *
 180                 *******************************/
 181
 182%!  must_be(+Type, @Term) is det.
 183%
 184%   True if Term satisfies the type constraints for Type. Defined
 185%   types are =atom=, =atomic=, =between=, =boolean=, =callable=,
 186%   =chars=, =codes=, =text=, =compound=, =constant=, =float=,
 187%   =integer=, =nonneg=, =positive_integer=, =negative_integer=,
 188%   =nonvar=, =number=, =oneof=, =list=, =list_or_partial_list=,
 189%   =symbol=, =var=, =rational=, =encoding=, =dict= and =string=.
 190%
 191%   Most of these types are defined by an arity-1 built-in predicate
 192%   of the same name. Below  is  a   brief  definition  of the other
 193%   types.
 194%
 195%   | boolean | one of =true= or =false= |
 196%   | char | Atom of length 1 |
 197%   | code | Representation Unicode code point |
 198%   | chars | Proper list of 1-character atoms |
 199%   | codes | Proper list of Unicode character codes |
 200%   | text | One of =atom=, =string=, =chars= or =codes= |
 201%   | between(IntL,IntU) | Integer [IntL..IntU] |
 202%   | between(FloatL,FloatU) | Number [FloatL..FloatU] |
 203%   | nonneg | Integer >= 0 |
 204%   | positive_integer | Integer > 0 |
 205%   | negative_integer | Integer < 0 |
 206%   | oneof(L) | Ground term that is member of L |
 207%   | encoding | Valid name for a character encoding |
 208%   | cyclic | Cyclic term (rational tree) |
 209%   | acyclic | Acyclic term (tree) |
 210%   | list(Type) | Proper list with elements of Type |
 211%   | list_or_partial_list | A list or an open list (ending in a variable |
 212%
 213%   Note: The Windows version can only represent Unicode code points
 214%   up to 2^16-1. Higher values cause a representation error on most
 215%   text handling predicates.
 216%
 217%   @throws instantiation_error if Term is insufficiently
 218%   instantiated and type_error(Type, Term) if Term is not of Type.
 219
 220must_be(Type, X) :-
 221    (   nonvar(Type),
 222        has_type(Type, X)
 223    ->  true
 224    ;   nonvar(Type)
 225    ->  is_not(Type, X)
 226    ;   instantiation_error(Type)
 227    ).
 228
 229%!  is_not(+Type, @Term)
 230%
 231%   Throws appropriate error. It is _known_ that Term is not of type
 232%   Type.
 233%
 234%   @throws type_error(Type, Term)
 235%   @throws instantiation_error
 236
 237is_not(list, X) :-
 238    !,
 239    not_a_list(list, X).
 240is_not(list(Of), X) :-
 241    !,
 242    not_a_list(list(Of), X).
 243is_not(list_or_partial_list, X) :-
 244    !,
 245    type_error(list, X).
 246is_not(chars, X) :-
 247    !,
 248    not_a_list(list(char), X).
 249is_not(codes, X) :-
 250    !,
 251    not_a_list(list(code), X).
 252is_not(var,X) :-
 253    !,
 254    uninstantiation_error(X).
 255is_not(cyclic, X) :-
 256    domain_error(cyclic_term, X).
 257is_not(acyclic, X) :-
 258    domain_error(acyclic_term, X).
 259is_not(Type, X) :-
 260    (   var(X)
 261    ->  instantiation_error(X)
 262    ;   ground_type(Type), \+ ground(X)
 263    ->  instantiation_error(X)
 264    ;   clause(has_type(Type,_), _Body)
 265    ->  type_error(Type, X)
 266    ;   existence_error(type, Type)
 267    ).
 268
 269ground_type(ground).
 270ground_type(oneof(_)).
 271ground_type(stream).
 272ground_type(text).
 273ground_type(string).
 274ground_type(rational).
 275
 276not_a_list(Type, X) :-
 277    '$skip_list'(_, X, Rest),
 278    (   var(Rest)
 279    ->  instantiation_error(X)
 280    ;   Rest == []
 281    ->  Type = list(Of),
 282        (   nonvar(Of)
 283        ->  element_is_not(X, Of)
 284        ;   instantiation_error(Of)
 285        )
 286    ;   type_error(Type, X)
 287    ).
 288
 289
 290element_is_not([H|T], Of) :-
 291    has_type(Of, H),
 292    !,
 293    element_is_not(T, Of).
 294element_is_not([H|_], Of) :-
 295    !,
 296    is_not(Of, H).
 297element_is_not(_List, _Of) :-
 298    assertion(fail).
 299
 300%!  is_of_type(+Type, @Term) is semidet.
 301%
 302%   True if Term satisfies Type.
 303
 304is_of_type(Type, Term) :-
 305    nonvar(Type),
 306    !,
 307    has_type(Type, Term),
 308    !.
 309is_of_type(Type, _) :-
 310    instantiation_error(Type).
 311
 312%!  has_type(+Type, @Term) is semidet.
 313%
 314%   True if Term satisfies Type.
 315
 316has_type(any, _).
 317has_type(atom, X)         :- atom(X).
 318has_type(atomic, X)       :- atomic(X).
 319has_type(between(L,U), X) :- (   integer(L)
 320    ->  integer(X), between(L,U,X)
 321    ;   number(X), X >= L, X =< U
 322    ).
 323has_type(boolean, X)      :- (X==true;X==false), !.
 324has_type(callable, X)     :- callable(X).
 325has_type(char,  X)        :- '$is_char'(X).
 326has_type(code,  X)        :- '$is_char_code'(X).
 327has_type(chars, X)        :- '$is_char_list'(X, _Len).
 328has_type(codes, X)        :- '$is_code_list'(X, _Len).
 329has_type(text, X)         :- text(X).
 330has_type(compound, X)     :- compound(X).
 331has_type(constant, X)     :- atomic(X).
 332has_type(float, X)        :- float(X).
 333has_type(ground, X)       :- ground(X).
 334has_type(cyclic, X)       :- cyclic_term(X).
 335has_type(acyclic, X)      :- acyclic_term(X).
 336has_type(integer, X)      :- integer(X).
 337has_type(nonneg, X)       :- integer(X), X >= 0.
 338has_type(positive_integer, X)     :- integer(X), X > 0.
 339has_type(negative_integer, X)     :- integer(X), X < 0.
 340has_type(nonvar, X)       :- nonvar(X).
 341has_type(number, X)       :- number(X).
 342has_type(oneof(L), X)     :- ground(X), \+ \+ memberchk(X, L).
 343has_type(proper_list, X)  :- is_list(X).
 344has_type(list, X)         :- is_list(X).
 345has_type(list_or_partial_list, X)  :- is_list_or_partial_list(X).
 346has_type(symbol, X)       :- atom(X).
 347has_type(var, X)          :- var(X).
 348has_type(rational, X)     :- rational(X).
 349has_type(string, X)       :- string(X).
 350has_type(stream, X)       :- is_stream(X).
 351has_type(encoding, X)     :- current_encoding(X).
 352has_type(dict, X)         :- is_dict(X).
 353has_type(list(Type), X)   :- is_list(X), element_types(X, Type).
 354
 355text(X) :-
 356    (   atom(X)
 357    ;   string(X)
 358    ;   '$is_char_list'(X, _)
 359    ;   '$is_code_list'(X, _)
 360    ),
 361    !.
 362
 363element_types(List, Type) :-
 364    nonvar(Type),
 365    !,
 366    element_types_(List, Type).
 367element_types(_List, Type) :-
 368    instantiation_error(Type).
 369
 370element_types_([], _).
 371element_types_([H|T], Type) :-
 372    has_type(Type, H),
 373    !,
 374    element_types_(T, Type).
 375
 376is_list_or_partial_list(L0) :-
 377    '$skip_list'(_, L0,L),
 378    ( var(L) -> true ; L == [] ).
 379
 380%!  current_encoding(?Name) is nondet.
 381%
 382%   True if Name is the name of   a supported encoding. See encoding
 383%   option of e.g., open/4.
 384
 385current_encoding(octet).
 386current_encoding(ascii).
 387current_encoding(iso_latin_1).
 388current_encoding(text).
 389current_encoding(utf8).
 390current_encoding(unicode_be).
 391current_encoding(unicode_le).
 392current_encoding(wchar_t).