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).
69:- multifile 70 has_type/2. 71 72 /******************************* 73 * ISO ERRORS * 74 *******************************/
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 compoint that is not point(_,_)
a type_error.
93type_error(Type, Term) :-
94 throw(error(type_error(Type, Term), _)).
103domain_error(Type, Term) :-
104 throw(error(domain_error(Type, Term), _)).
111existence_error(Type, Term) :-
112 throw(error(existence_error(Type, Term), _)).
119permission_error(Action, Type, Term) :-
120 throw(error(permission_error(Action, Type, Term), _)).
134instantiation_error(_Term) :-
135 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
.
145uninstantiation_error(Term) :-
146 throw(error(uninstantiation_error(Term), _)).
156representation_error(Reason) :-
157 throw(error(representation_error(Reason), _)).
168syntax_error(Culprit) :-
169 throw(error(syntax_error(Culprit), _)).
175resource_error(Culprit) :- 176 throw(error(resource_error(Culprit), _)). 177 178 179 /******************************* 180 * MUST-BE * 181 *******************************/
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.
boolean | one of true or false |
char | Atom of length 1 |
code | Representation Unicode code point |
chars | Proper list of 1-character atoms |
codes | Proper list of Unicode character codes |
text | One of atom , string , chars or codes |
between(IntL,IntU) | Integer [IntL..IntU] |
between(FloatL,FloatU) | Number [FloatL..FloatU] |
nonneg | Integer >= 0 |
positive_integer | Integer > 0 |
negative_integer | Integer < 0 |
oneof(L) | Ground term that is member of L |
encoding | Valid name for a character encoding |
cyclic | Cyclic term (rational tree) |
acyclic | Acyclic term (tree) |
list(Type) | Proper list with elements of Type |
list_or_partial_list | A list or an open list (ending in a variable |
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.
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 ).
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).
305is_of_type(Type, Term) :- 306 nonvar(Type), 307 !, 308 has_type(Type, Term), 309 !. 310is_of_type(Type, _) :- 311 instantiation_error(Type).
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 == [] ).
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).
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(_,_,_))
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.
library(debug)
andlibrary(prolog_stack)
.