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