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(_,_,_))