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-2020, 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 [ instantiation_error/1, % +FormalSubTerm 38 uninstantiation_error/1, % +Culprit 39 type_error/2, % +ValidType, +Culprit 40 domain_error/2, % +ValidDomain, +Culprit 41 existence_error/2, % +ObjectType, +Culprit 42 existence_error/3, % +ObjectType, +Culprit, +Set 43 permission_error/3, % +Operation, +PermissionType, +Culprit 44 representation_error/1, % +Flag 45 resource_error/1, % +Resource 46 syntax_error/1, % +ImplDepAtom 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).
70:- multifile 71 has_type/2. 72 73 /******************************* 74 * ISO ERRORS * 75 *******************************/
Suppose an argument must be a non-negative integer. If the actual argument is not an integer, this is a type_error. If it is a negative integer, it is a domain_error.
Typical borderline cases are predicates accepting a compound term,
e.g., point(X,Y)
. One could argue that the basic type is a
compound-term and any other compound term is a domain error. Most
Prolog programmers consider each compound as a type and would
consider a compound that is not point(_,_)
a type_error.
94type_error(ValidType, Culprit) :-
95 throw(error(type_error(ValidType, Culprit), _)).
103domain_error(ValidDomain, Culprit) :-
104 throw(error(domain_error(ValidDomain, Culprit), _)).
112existence_error(ObjectType, Culprit) :-
113 throw(error(existence_error(ObjectType, Culprit), _)).
existence_error(ObjectType,
Culprit, Set)
125existence_error(ObjectType, Culprit, Set) :-
126 throw(error(existence_error(ObjectType, Culprit, Set), _)).
134permission_error(Operation, PermissionType, Culprit) :-
135 throw(error(permission_error(Operation, PermissionType, Culprit), _)).
149instantiation_error(_FormalSubTerm) :-
150 throw(error(instantiation_error, _)).
open(File, read, input)
cannot succeed because the system will
allocate a new unique stream handle that will never unify with
input
.
160uninstantiation_error(Culprit) :-
161 throw(error(uninstantiation_error(Culprit), _)).
171representation_error(Flag) :-
172 throw(error(representation_error(Flag), _)).
185syntax_error(Culprit) :-
186 throw(error(syntax_error(Culprit), _)).
194resource_error(Resource) :- 195 throw(error(resource_error(Resource), _)). 196 197 198 /******************************* 199 * MUST-BE * 200 *******************************/
atom
, atomic
, between
, boolean
, callable
,
chars
, codes
, text
, compound
, constant
, float
,
integer
, nonneg
, positive_integer
, negative_integer
,
nonvar
, number
, oneof
, list
, list_or_partial_list
,
symbol
, var
, rational
, encoding
, dict
and string
.
Most of these types are defined by an arity-1 built-in predicate of the same name. Below is a brief definition of the other types.
acyclic | Acyclic term (tree); see acyclic_term/1 |
any | any term |
between(FloatL,FloatU) | Number [FloatL..FloatU] |
between(IntL,IntU) | Integer [IntL..IntU] |
boolean | One of true or false |
char | Atom of length 1 |
chars | Proper list of 1-character atoms |
code | Representation Unicode code point |
codes | Proper list of Unicode character codes |
constant | Same as atomic |
cyclic | Cyclic term (rational tree); see cyclic_term/1 |
dict | A dictionary term; see is_dict/1 |
encoding | Valid name for a character encoding; see current_encoding/1 |
list | A (non-open) list; see is_list/1 |
negative_integer | Integer < 0 |
nonneg | Integer >= 0 |
oneof(L) | Ground term that is member of L |
pair | Key-Value pair |
positive_integer | Integer > 0 |
proper_list | Same as list |
list(Type) | Proper list with elements of Type |
list_or_partial_list | A list or an open list (ending in a variable); see is_list_or_partial_list/1 |
stream | A stream name or valid stream handle; see is_stream/1 |
symbol | Same as atom |
text | One of atom , string , chars or codes |
type | Term is a valid type specification |
Note: The Windows version can only represent Unicode code points up to 2^16-1. Higher values cause a representation error on most text handling predicates.
249must_be(Type, X) :-
250 ( nonvar(Type),
251 has_type(Type, X)
252 -> true
253 ; nonvar(Type)
254 -> is_not(Type, X)
255 ; instantiation_error(Type)
256 ).
266is_not(list, X) :- 267 !, 268 not_a_list(list, X). 269is_not(list(Of), X) :- 270 !, 271 not_a_list(list(Of), X). 272is_not(list_or_partial_list, X) :- 273 !, 274 type_error(list, X). 275is_not(chars, X) :- 276 !, 277 not_a_list(list(char), X). 278is_not(codes, X) :- 279 !, 280 not_a_list(list(code), X). 281is_not(var,X) :- 282 !, 283 uninstantiation_error(X). 284is_not(cyclic, X) :- 285 domain_error(cyclic_term, X). 286is_not(acyclic, X) :- 287 domain_error(acyclic_term, X). 288is_not(Type, X) :- 289 current_type(Type, _Var, _Body), 290 !, 291 ( var(X) 292 -> instantiation_error(X) 293 ; ground_type(Type), \+ ground(X) 294 -> instantiation_error(X) 295 ; type_error(Type, X) 296 ). 297is_not(Type, _) :- 298 existence_error(type, Type). 299 300ground_type(ground). 301ground_type(oneof(_)). 302ground_type(stream). 303ground_type(text). 304ground_type(string). 305ground_type(rational). 306 307not_a_list(Type, X) :- 308 '$skip_list'(_, X, Rest), 309 ( var(Rest) 310 -> instantiation_error(X) 311 ; Rest == [] 312 -> Type = list(Of), 313 ( nonvar(Of) 314 -> element_is_not(X, Of) 315 ; instantiation_error(Of) 316 ) 317 ; type_error(Type, X) 318 ). 319 320 321element_is_not([H|T], Of) :- 322 has_type(Of, H), 323 !, 324 element_is_not(T, Of). 325element_is_not([H|_], Of) :- 326 !, 327 is_not(Of, H). 328element_is_not(_List, _Of) :- 329 assertion(fail).
335is_of_type(Type, Term) :- 336 nonvar(Type), 337 !, 338 has_type(Type, Term), 339 !. 340is_of_type(Type, _) :- 341 instantiation_error(Type).
347:- '$clausable'(has_type/2). % always allow clause/2 348:- public % May be called through current_type/3 349 is_list_or_partial_list/1, 350 current_encoding/1, 351 element_types/2. 352 353has_type(any, _). 354has_type(atom, X) :- atom(X). 355has_type(atomic, X) :- atomic(X). 356has_type(between(L,U), X) :- ( integer(L) 357 -> integer(X), between(L,U,X) 358 ; number(X), X >= L, X =< U 359 ). 360has_type(boolean, X) :- (X==true;X==false), !. 361has_type(callable, X) :- callable(X). 362has_type(char, X) :- '$is_char'(X). 363has_type(code, X) :- '$is_char_code'(X). 364has_type(chars, X) :- '$is_char_list'(X, _Len). 365has_type(codes, X) :- '$is_code_list'(X, _Len). 366has_type(text, X) :- text(X). 367has_type(compound, X) :- compound(X). 368has_type(constant, X) :- atomic(X). 369has_type(float, X) :- float(X). 370has_type(ground, X) :- ground(X). 371has_type(cyclic, X) :- cyclic_term(X). 372has_type(acyclic, X) :- acyclic_term(X). 373has_type(integer, X) :- integer(X). 374has_type(nonneg, X) :- integer(X), X >= 0. 375has_type(positive_integer, X) :- integer(X), X > 0. 376has_type(negative_integer, X) :- integer(X), X < 0. 377has_type(nonvar, X) :- nonvar(X). 378has_type(number, X) :- number(X). 379has_type(oneof(L), X) :- ground(X), \+ \+ memberchk(X, L). 380has_type(pair, X) :- nonvar(X), X = _-_. 381has_type(proper_list, X) :- is_list(X). 382has_type(list, X) :- is_list(X). 383has_type(list_or_partial_list, X) :- is_list_or_partial_list(X). 384has_type(symbol, X) :- atom(X). 385has_type(var, X) :- var(X). 386has_type(rational, X) :- rational(X). 387has_type(string, X) :- string(X). 388has_type(stream, X) :- is_stream(X). 389has_type(encoding, X) :- current_encoding(X). 390has_type(dict, X) :- is_dict(X). 391has_type(list(Type), X) :- is_list(X), element_types(X, Type). 392has_type(type, Type) :- ground(Type), current_type(Type,_,_). 393 394text(X) :- 395 ( atom(X) 396 ; string(X) 397 ; '$is_char_list'(X, _) 398 ; '$is_code_list'(X, _) 399 ), 400 !. 401 402element_types(List, Type) :- 403 nonvar(Type), 404 !, 405 element_types_(List, Type). 406element_types(_List, Type) :- 407 instantiation_error(Type). 408 409element_types_([], _). 410element_types_([H|T], Type) :- 411 has_type(Type, H), 412 !, 413 element_types_(T, Type). 414 415is_list_or_partial_list(L0) :- 416 '$skip_list'(_, L0,L), 417 ( var(L) -> true ; L == [] ).
424current_encoding(octet). 425current_encoding(ascii). 426current_encoding(iso_latin_1). 427current_encoding(text). 428current_encoding(utf8). 429current_encoding(unicode_be). 430current_encoding(unicode_le). 431current_encoding(wchar_t).
439current_type(Type, Var, Body) :- 440 clause(has_type(Type, Var), Body0), 441 qualify(Body0, Body). 442 443qualify(Var, VarQ) :- 444 var(Var), 445 !, 446 VarQ = Var. 447qualify((A0,B0), (A,B)) :- 448 qualify(A0, A), 449 qualify(B0, B). 450qualify(G0, G) :- 451 predicate_property(system:G0, built_in), 452 !, 453 G = G0. 454qualify(G, error:G). 455 456 457 /******************************* 458 * SANDBOX * 459 *******************************/ 460 461:- multifile sandbox:safe_primitive/1. 462 463sandbox:safe_primitive(error:current_type(_,_,_))
Error generating support
This module provides predicates to simplify error generation and checking. It's implementation is based on a discussion on the SWI-Prolog mailinglist on best practices in error handling. The utility predicate must_be/2 provides simple run-time type validation. The *_error predicates are simple wrappers around throw/1 to simplify throwing the most common ISO error terms.