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).