1:- module( pack_errors, [ 2 pack_errors/0, % 3 caught/3, % +Goal, +Error, +Opts 4 ground/2, ground_binary/2, % +Term, -Groundness 5 defined/2, defined/3, % +Pid, +From[, +Opts] 6 throw/2, % +Error,+Opts 7 type/2, % +Type, +Term 8 type/3, % +Type, +Term, +Opts 9 of_same_length/1, % +Lists 10 of_same_length/2, % +List1, +List2; +Lists, +Opts 11 of_same_length/3, % +List1, +List2, +Opts 12 pack_errors_version/2 % +Version, +Date 13 ] ). 14 15:- use_module(library(lists)). % append/3,... 16:- use_module(library(error)). % is_of_type/2. 17:- use_module(library(debug)). % debug/3.
218:- multifile prolog:message//1. 219 220caught_defaults( [on_exit(error),on_true(true)] ).
Opts
?- caught( fail, my_exception(on_data), true ). ERROR: Unhandled exception: pack_error(my_exception(on_data),[on_exit(error),message(error)]) ?- caught( fail, my_exception(on_data), on_exit(true) ). false % it fails because the message writing fails, which is probably best ?- caught( false, os_exists_not(abc), [] ). ERROR: OS entity: abc, does not exist ?- caught( false, os_exists_not(abc), on_exit(error) ). ERROR: OS entity: abc, does not exist ?- caught( false, os_exists_not(abc), on_exit(fail) ). ERROR: OS entity: abc, does not exist false. ?- caught( false, os_exists_not(abc), on_exit(true) ). ERROR: OS entity: abc, does not exist true.
272caught( Goal, Error, Args ) :- 273 pack_errors_options_append( caught, Args, Opts ), 274 caught_opts( Goal, Error, Opts ). 275 276caught_opts( Goal, Error, Opts ) :- 277 catch( Goal, Ball, pack_errors:caught_error(Goal,Ball,Error,Opts) ), 278 memberchk( OnTrue, Opts ), 279 call( OnTrue ), 280 !. 281caught_opts( _Goal, Error, Args ) :- 282 pack_errors_options_append( caught, Args, Opts ), 283 caught_opt_throw( OnThrow, Opts ), 284 throw( Error, on_exit(OnThrow) ). 285 286caught_error( _Goal, Ball, Error, Opts ) :- 287 memberchk( ball(Ball), Opts ), 288 !, 289 caught_opt_throw( OnThrow, Opts ), 290 throw( Error, on_exit(OnThrow) ). 291caught_error( _Goal, _Ball, Error, Opts ) :- 292 caught_opt_throw( OnThrow, Opts ), 293 throw( Error, on_exit(OnThrow) ). 294 295caught_opt_throw( OnThrow, Opts ) :- 296 memberchk( on_exit(Rep), Opts ), 297 caught_opt_report_throw( Rep, OnThrow ). 298 299caught_opt_report_throw( true, true ) :- 300 !. 301caught_opt_report_throw( Rep, Rep ).
partial
and false
are collapsed to false
.
Groundness
?- ground( abc, Abc ), ground( de(F), Def ), ground( GHI, Ghi ). Abc = true, Def = partial, Ghi = false. ?- ground_binary( abc, Abc ), ground_binary( de(F), Def ), ground_binary( GHI, Ghi ). Abc = true, Def = Ghi, Ghi = false.
*/
330ground( Term, Type ) :- 331 var( Term ), 332 !, 333 Type = false. 334ground( Term, Type ) :- 335 ground( Term ), 336 !, 337 Type = true. 338ground( _Term, Type ) :- 339 Type = partial. 340 341ground_binary( Term, Type ) :- 342 ground( Term ), 343 !, 344 Type = true. 345ground_binary( _Term, false ). 346 347throw_defaults([err(error)]). 348 349% fixme: use _known and throw error else 350throw_err_opt_vals( error, error, error ). 351throw_err_opt_vals( test, quiet, false ). 352throw_err_opt_vals( exists, warning, false ).
throw()
decouples type of message printing and execution behaviour.<br>
As of version 0.3 this should be the adviced entry point for message writing and ball throwing for stoics packs.
Opts
Level = error
and OnExit = error
Level=quiet
and OnExit = false
Level=warning
and OnExit = false
[true,false,error]
. if not given the default depends on Err,
foo:bar/1
or bar/2
)?- throw( cast(abc('file.csv'),atom) ). ERROR: Unhandled exception: cast(abc(file.csv),atom) ?- throw( pack_error(cast(abc('file.csv'),atom),true) ). ERROR: Cannot cast: abc(file.csv), to type: atom ?- Opt = os:os_exists/2, throw(pack_error(cast(abc('file.csv'),atom),Opt)), writeln(later). ERROR: os:os_exists/2: Cannot cast: abc(file.csv), to type: atom ?- throw(cast(abc('file.csv'),atom), os:os_exists/2), writeln(later). ERROR: os:os_exists/2: Cannot cast: abc(file.csv), to type: atom ?- throw(cast(abc('file.csv'),atom), err(test)), writeln(later). false. ?- _Opts = [message(quiet),on_exit(true)], throw(cast(abc('file.csv'),atom), _Opts), writeln(later). later true. ?- _Opts = [message(warning),on_exit(true)], throw(cast(abc('file.csv'),atom), _Opts), writeln(later). Warning: Cannot cast: abc(file.csv), to type: atom later true. ?- _Opts = [message(informational),on_exit(true)], throw(cast(abc('file.csv'),atom), _Opts), writeln(later). % Cannot cast: abc(file.csv), to type: atom later true. ?- _Opts = [message(warning),on_exit(false)], throw(cast(abc('file.csv'),atom), _Opts), writeln(later). Warning: Cannot cast: abc(file.csv), to type: atom false. ?- throw(cast(abc('file.csv'),atom), err(exists)), writeln(later). Warning: Cannot cast: abc(file.csv), to type: atom false. ?- throw(cast(abc('file.csv'),atom), on_exit(true)), writeln(later). ERROR: Cannot cast: abc(file.csv), to type: atom later true. ?- throw(cast(abc('file.csv'),atom), on_exit(false)), writeln(later). ERROR: Cannot cast: abc(file.csv), to type: atom false. ?- throw(cast(abc('file.csv'),atom), on_exit(error)), writeln(later). ERROR: Cannot cast: abc(file.csv), to type: atom ?- throw(cast(abc('file.csv'),atom), message(warning)), writeln(later). Warning: Cannot cast: abc(file.csv), to type: atom ?- throw(cast(abc('file.csv'),atom), message(informational)), writeln(later). % Cannot cast: abc(file.csv), to type: atom later true. ?- _Opts = [message(informational),on_exit(false)], throw(cast(abc('file.csv'),atom), _Opts), writeln(later). % Cannot cast: abc(file.csv), to type: atom false. ?- _Opts = [message(informational),on_exit(error)], throw(cast(abc('file.csv'),atom), _Opts), writeln(later). % Cannot cast: abc(file.csv), to type: atom
513throw( Error, Args ) :- 514 pack_errors_options_append( throw, Args, Opts ), 515 memberchk( err(Err), Opts ), 516 throw_err_opt_vals( Err, LvlDef, OnXDef ), 517 ( memberchk(message(Lvl),Opts)-> true; Lvl = LvlDef ), 518 ( memberchk(on_exit(OnExit),Opts) -> true ; OnExit = OnXDef ), 519 throw_on_valid( OnExit ), 520 throw_level( Lvl, Error, OnExit, Opts ). 521 522throw_on_valid( OnThrow ) :- 523 throw_on_known( OnThrow ), 524 !. 525throw_on_valid( OnThrow ) :- 526 % fixme: render it ! 527 throw( unknown_option_value(throw/2,on_exit(OnThrow)) ). 528 529throw_on_known(error). 530throw_on_known(true). 531throw_on_known(fail). 532throw_on_known(false). 533 534% fixme: ask in forum with silent in print_message/2 prints things ... 535% 536throw_level( quiet, _BallMark, OnExit, _Opts ) :- 537 !, 538 throw_level_exit( OnExit ). 539throw_level( Lvl, BallMark, OnExit, Opts ) :- 540 ( BallMark =.. [pack_error,Barg] -> 541 Ball =.. [pack_error,Barg,Opts] 542 ; 543 ( BallMark =.. [pack_error,_Barg,_Opts] -> 544 Ball = BallMark 545 ; 546 Ball = pack_error(BallMark,Opts) 547 ) 548 ), 549 debug( pack_errors, 'Leveled ball: ~w', Ball ), 550 throw_level_on_exit( OnExit, Lvl, Ball ). 551 552throw_level_on_exit( error, error, Ball ) :- 553 !, 554 throw( Ball ). 555throw_level_on_exit( OnExit, Lvl, Ball ) :- 556 debug( pack_errors, 'Explicit layout at level: ~w', [Lvl] ), 557 prolog:message( Ball, Mess, [] ), % i thinks [] is correct 558 print_message_lines( current_output, kind(Lvl), Mess ), 559 throw_level_exit( OnExit ). 560 561throw_level_exit( error ) :- 562 !, 563 throw( true ). 564 % abort. 565throw_level_exit( Goal ) :- 566 call( Goal ), 567 !. 568 569type_defaults( [error(true),pack(false),pred(false),arg(false)] ).
call(Callable)
), which will succeed iff
call( Callable, Term )
succeeds. It also enhances must_be/2 by adding options.
In the case of a call-wrapped type, the call to type/3 will succeed iff
call(Callable,Term)
succeeds.
Opts (unlisted is ok)
?- type( boolean, maybe ). ERROR: Object of type: boolean, expected but found term: maybe ?- type( boolean, maybe, error(false) ). false. ?- type( boolean, maybe, pack(sure) ). ERROR: pack(sure): Object of type: boolean, expected but found term: maybe ?- type( boolean, maybe, [pack(sure),pred(lost/2)] ). ERROR: sure:lost/2: Object of type: boolean, expected but found term: maybe ?- type( boolean, maybe, [pack(sure),pred(lost/2+3)] ). ERROR: sure:lost/2+3: Object of type: boolean, expected but found term: maybe ?- type( boolean, maybe, [pack(sure),pred(1+lost/2)] ). ERROR: sure:1+lost/2: Object of type: boolean, expected but found term: maybe ?- type( boolean, maybe, [pack(sure),pred(lost(arg1)/2)] ). ERROR: sure:lost(arg1)/2: Object of type: boolean, expected but found term: maybe
*/
620type( Type, Term ) :- 621 type( Type, Term, [] ). 622 623type( Type, _Term, _Args ) :- 624 \+ ground( Type ), 625 !, 626 % throw( pack_error(pack_error,type/3,arg_ground(1,Type)) ). 627 throw( arg_ground(1,Type), pack_error:type/3 ). 628type( Type, Term, Args ) :- 629 pack_errors_options_append( type, Args, Opts ), 630 type_optioned( Type, Term, Opts ). 631 632type_optioned( @(GoalPrv), Term, _Opts ) :- 633 ( GoalPrv = _:_ -> Goal = GoalPrv; Goal = user:GoalPrv ), 634 call( Goal, Term ), 635 !. 636type_optioned( call(GoalPrv), Term, _Opts ) :- 637 ( GoalPrv = _:_ -> Goal = GoalPrv; Goal = user:GoalPrv ), 638 call( Goal, Term ), 639 !. 640type_optioned( Type, Term, _Opts ) :- 641 Type \= call(_), 642 is_of_type( Type, Term ), 643 !. 644type_optioned( Type, Term, Opts ) :- 645 memberchk( error(Error), Opts ), 646 type_error( Error, Type, Term, Opts ). 647 648type_error( false, _Type, _Term, _Opts ) :- !, fail. 649type_error( true, Type, Term, Opts ) :- 650 % memberchk( pack(Pack), Opts ), 651 % memberchk( pred(Pred), Opts ), 652 memberchk( arg(Pos), Opts ), 653 type_error_position( Pos, Type, Term, Opts ). 654 655% type_error_position( false, Pack, Pred, Type, Term ) :- 656type_error_position( false, Type, Term, Opts ) :- 657 !, 658 throw( pack_error(type_error(Type,Term)), Opts ). 659type_error_position( Pos, Type, Term, Opts ) :- 660 throw( pack_error(type_error(Pos,Type,Term)), Opts ). 661 662pack_errors_options_append( Pname, ArgS, Opts ) :- 663 ( is_list(ArgS) -> Args = ArgS ; Args = [ArgS] ), 664 atom_concat( Pname, '_defaults', Dname ), 665 Dcall =.. [Dname,Defs], 666 call( Dcall ), 667 append( Args, Defs, Opts ), 668 !. 669 670defined_defaults( [load(false)] ).
load(true)
)pack(lib)
's lib(suggests(Pack))
to, on-demand,
Note that pack(lib)
also provides
lib(suggests(Pid,Load))
which is an alternative and more automatic way to achieve demand driven loading via hot-swapping.
:- lib(suggests(Pack))
silently fails if Pack is not present. This is intendent for dependendencies that do not impact major parts for the importing pack. Thus allow common use without grabbing all dependencies that may not be needed for a particular user.
Opts are passed to throw/2, except for:
load(Load=false)
?- defined( abc/0, pack(b_real) ). ERROR: Predicate: abc/0 is not defined (source apparently available at: pack(b_real); not asked to load) ?- defined( abc/0, false ). ERROR: Predicate: abc/0 is not defined ?- defined( abc/0, false, pack(sourcey) ). ERROR: sourcey:$unknown/0: Predicate: abc/0 is not defined ?- defined( abc/0, pack(b_real), [pack(sourcey),pred(foo/1;2)] ). ERROR: sourcey:foo/1;2: Predicate: abc/0 is not defined (source apparently available at: pack(b_real); not asked to load) ?- defined( b_real/0, pack(b_real), [as_pack_err(true),load(library(b_real))] ). true.
The above only succeeds if b_real is an install library and defines b_real/0.
From or Load can have the special form: lib(CodeLib)
. This assumes pack(lib)
is installed and lib/1
will be used to load the requested CodeLib.
?- defined( b_real/0, lib(b_real), load(true) ).
Will again, only succeed if b_real is installed and defines b_real/0. In this occasion library(lib)
should be also installed.
730defined( Pid, From ) :- 731 defined( Pid, From, [] ). 732defined( Pid, _From, _Opts ) :- 733 current_predicate( Pid ), 734 !. % fixme: need version where From and Into are checked ? 735 % here we don't check as From and Into are assumed as tracers no enforcables 736defined( Pid, From, ArgS ) :- 737 \+ var(ArgS), % fixme: error 738 defined_defaults( Defs ), 739 ( is_list(ArgS) -> Args = ArgS; Args = [ArgS] ), 740 append( Args, Defs, Opts ), 741 memberchk( load(Load), Opts ), 742 defined_if_load( Load, Pid, From, Args ). 743 744defined_if_load( false, Pid, From, Opts ) :- 745 throw( expected_from(false,Pid,From), Opts ). 746defined_if_load( true, Pid, From, Opts ) :- 747 !, 748 defined_load( From, Pid, From, Opts ). 749defined_if_load( Other, Pid, From, Opts ) :- 750 defined_load( Other, Pid, From, Opts ). 751 752defined_load( lib(This), Pid, From, Args ) :- 753 !, 754 lib:lib(This), 755 defined_loaded( Pid, From, Args ). 756defined_load( LoadThis, Pid, From, Args ) :- 757 % fixme: check is not loaded ? 758 user:ensure_loaded( LoadThis ), 759 defined_loaded( Pid, From, Args ). 760 761defined_loaded( Pid, _From, _Opts ) :- 762 current_predicate( user:Pid ), 763 !. % fixme: need version where From and Into are checked ? 764defined_loaded( Pid, From, Opts ) :- 765 throw( expected_from(true,Pid,From), Opts ).
*/
772pack_errors :-
773 write( 'Contextual error handling for packs' ), nl.
In order to disambiguate between the two versions of the arity 2,
in that scenario options should be a term of the form opts(OptsL)
.
Opts are passed to throw/2, the only local one is:
action(Act)
of_same_length(Lng1,Lng2,Tkn1,Tkn2)
token1(Tkn1=1)
name of List1
(used in error throwing to id the list)token2(Tkn2=n)
name of List2 (used in error throwing)
when first argument is Lists, Tkn2 will be the index position of the first list length-mismatch the head list?- of_same_length( [a,b,c], [1,2,3] ). true. ?- of_same_length( [[a,b,c],[1,2,3]] ). true. ?- of_same_length( [1,2,3], [a,b], token1(first) ). ERROR: Lists for first and 2 have mismatching lengths: 3 and 2 respectively
818of_same_length( [List1|Lists] ) :- 819 of_same_length_1( Lists, List1, [] ). 820 821of_same_length( [List1|Lists], opts(Opts) ) :- 822 !, 823 of_same_length_1( Lists, List1, Opts ). 824of_same_length( List1, List2 ) :- 825 of_same_length_1( [List2], List1, [] ). 826of_same_length( List1, List2, Opts ) :- 827 of_same_length_1( [List2], List1, Opts ). 828 829of_same_length_1( Lists, List1, Args ) :- 830 length( List1, Lng1 ), 831 \+ var(Args), 832 ( is_list(Args) -> append(Args,[action(throw)],Opts) ; Opts = [Args,action(throw)] ), 833 memberchk( action(Act), Opts ), 834 of_same_length_1( Lists, 2, Lng1, List1, Act, Opts ). 835 836% currently List1 is not used, but it could be passed to 837% of_same_length_mismatch for reporting of clashing lists... 838of_same_length_1( [], _I, _Lng, _List1, _Act, _Opts ). 839of_same_length_1( [HList|T], I, Lng1, List1, Act, Opts ) :- 840 length( HList, HLng ), 841 ( HLng =:= Lng1 -> 842 true 843 ; 844 % throw( not_of_equal_length(HLng,Lng) ) 845 ( memberchk(token1(Tkn1),Opts) -> true; Tkn1 = 1 ), 846 ( memberchk(token2(Tkn2),Opts) -> true; Tkn2 = I ), 847 of_same_length_mismatch( Act, Lng1, HLng, Tkn1, Tkn2, Opts ) 848 ), 849 J is I + 1, 850 of_same_length_1( T, J, Lng1, List1, Act, Opts ). 851 852of_same_length_mismatch( error, Lng1, Lng2, Tkn1, Tkn2, Opts ) :- 853 throw( lengths_mismatch(Tkn1,Tkn2,Lng1,Lng2), Opts ). 854of_same_length_mismatch( fail, _Lng1, _Lng2, _Tkn1, _Tkn2, _Opts ) :- 855 fail. 856of_same_length_mismatch( false, _Lng1, _Lng2, _Tkn1, _Tkn2, _Opts ) :- 857 fail. 858% throw_lists ? which will also include the offender & base lists ? 859of_same_length_mismatch( throw, Lng1, Lng2, Tkn1, Tkn2, _Opts ) :- 860 throw( of_same_length(Lng1,Lng2,Tkn1,Tkn2) ). 861of_same_length_mismatch( warning, Lng1, Lng2, Tkn1, Tkn2, _Opts ) :- 862 % % Format = 'Lists at:~w and ~w, have differing lengths: ~d and ~d', 863 % % message_report( Format, [Tkn1,Tkn2,Lng1,Lng2], informational ). 864 throw( lengths_mismatch(Tkn1,Tkn2,Lng1,Lng2), message(warning) ). 865 % message( lengths_mismatch(Tkn1,Tkn2,Lng1,Lng2), List, [] ), 866 % print_message_lines(current_output, kind(warning), List ). 867% of_same_length_mismatch( warning, Lng1, Lng2, Tkn1, Tkn2, _Opts ) :- 868 869of_same_length_mismatch( error, Lng1, Lng2, Tkn1, Tkn2, _Opts ) :- 870 Format = 'Lists at:~p, have differing lengths, ~d and ~d', 871 message_report( Format, [Tkn1,Tkn2,Lng1,Lng2], error ), 872 fail. 873of_same_length_mismatch( warning(Tkn), Lng1, Lng2, _L1, _L2, _Opts ) :- 874 Format = 'Lists at:~p, have differing lengths, ~d and ~d', 875 message_report( Format, [Tkn,Lng1,Lng2], informational ). 876of_same_length_mismatch( warn_lists(Tkn), Lng1, Lng2, L1, L2, _Opts ) :- 877 Format = 'Lists at:~p, have differing lengths, ~d and ~d. The lists are as follows', 878 Args = [Tkn,Lng1,Lng2], 879 message_report( Format, Args, informational ), 880 Format1 = 'Length mismatch list1:~p', 881 message_report( Format1, [L1], debug(_) ), 882 Format2 = 'Length mismatch List2:~p', 883 message_report( Format2, [L2], debug(_) ). 884 885pack_message_options_augment( Opts, Apts ) :- 886 nth1( N, Opts, Mod:Pred, Rest ), 887 \+ (nth1(N1,Opts,_Name/_Arity), N1<N), 888 !, 889 pack_message_options_trail( Rest, Trail, Rems ), 890 Apts = [pred(Mod:Pred),trail(Trail)|Rems]. 891pack_message_options_augment( Opts, Apts ) :- 892 nth1( _N1, Opts, Name/Arity, Rest ), 893 !, 894 pack_message_options_trail( Rest, Trail, Rems ), 895 Apts = [pred(Name/Arity),trail(Trail)|Rems]. 896 % fixme: just stick a mod infront of Name/Arity 897pack_message_options_augment( Apts, Apts ). 898 899pack_message_options_trail( [], [], [] ). 900pack_message_options_trail( [Opt|Opts], Trail, Rems ) :- 901 ( (Opt=_Mod:_Name1/_Arity1; Opt=_Name2/_Arity2) -> 902 Trail = [Opt|TellTail], 903 Rems = Tems 904 ; 905 Trail = TellTail, 906 Rems = [Opt|Tems] 907 ), 908 pack_message_options_trail( Opts, TellTail, Tems ). 909 910/* fixme: delete 911pack_message_options_augment( Opts, Apts ) :- 912 nth1( N, Opts, Name/Arity, Rest ), 913 pack_message_options_trail( Rest, Trail, Rems ), 914 ( select(Mod:Pred,Opts,Rem) -> 915 Apts = [pred(Mod:Pred)|Rem] 916 ; 917 ( select(Name/Arity,Opts,Rem) -> 918 Apts = [pred(Name/Arity)|Rem] 919 ; 920 Apts = Opts 921 ) 922 ). 923*/
V = 2:2:0, D = date(2022, 12, 29).
938pack_errors_version( 2:2:0, date(2022,12,29) ). 939 940prologmessage(unhandled_exception(true)) --> []. 941prologmessage(unhandled_exception(pack_error(Message))) --> 942 { debug( pack_errors, 'Unhandled pack_error/1 ~w', [Message] ) }, 943 % pack_errors:message(Message,[]). 944 pack_message(Message,[]). 945prologmessage(unhandled_exception(pack_error(Message,Opts))) --> 946 { debug( pack_errors, 'Unhandled pack_error/2 c ~w, ~w', [Message,Opts] ) }, 947 pack_message(Message,Opts). 948 949prologmessage(pack_error(Message)) --> 950 { debug( pack_errors, 'Pack_error/1: ~w', [Message] ) }, 951 pack_message(Message, []). 952prologmessage(pack_error(Message,Opts)) --> 953 { debug( pack_errors, 'Pack_error/2: ~w, ~w', [Message,Opts] ) }, 954 pack_message(Message, Opts). 955 956pack_message( Mess, OptsPrv ) --> 957 % fixme: check for var(OptsPrv) ? 958 {( is_list(OptsPrv) -> OptsPrv = Opts; Opts = [OptsPrv] )}, 959 {pack_message_options_augment(Opts,Apts)}, 960 message_pack( Apts ), 961 pack_errors:message( Mess ), 962 pack_message_trail( Apts ). 963 964pack_message_trail( Apts ) --> 965 { memberchk(trail(Trail),Apts), 966 Trail \== [], 967 ! 968 }, 969 [ '\nERROR: Trail: ~w' - [Trail] ]. 970pack_message_trail( _Apts ) --> {true}. 971 972message_pack( Opts ) --> 973 { debug( pack_errors, 'message_pack options: ~w', [Opts] ) }, 974 { (memberchk(pred(PredPrv),Opts)->true; PredPrv='_Unk'), 975 (memberchk(pack(Pack),Opts)-> 976 ( PredPrv = PredMod:PredFct -> 977 ( PredMod = Pack -> 978 Pred = PredFct 979 ; 980 Pred = PredPrv % both Pack and Mod will be displayed 981 ) 982 ; 983 Pred = PredPrv 984 ) 985 ; 986 ( PredPrv = Pack:Pred -> 987 true 988 ; 989 PredPrv = Pred, 990 Pack='_Unk' 991 ) 992 ), 993 debug( pack_errors, 'pack:predicate identified as: ~w:~w', [Pack,Pred] ), 994 \+ (Pack=='_Unk', Pred=='_Unk'), 995 ! 996 }, 997 {( memberchk(option(OptNm),Opts) -> atomic_list_concat([' @ option(',OptNm,')'],OptTkn); OptTkn = '' )}, 998 ['~w:~w~w: '-[Pack,Pred,OptTkn] ]. 999message_pack( _ ) --> []. 1000 1001:- multifile( pack_errors:message/3 ). 1002 1003message( true ) --> []. 1004 1005message( arg_enumerate(Pos,Vals,_Arg) ) --> 1006 { current_prolog_flag(pack_errors_arg,false) }, 1007 ['Term at position: ~d, is not one of: ~w'-[Pos,Vals]]. 1008message( arg_enumerate(Pos,Vals,Arg) ) --> 1009 ['Term at position: ~d, is not one of: ~w, (found: ~w)'-[Pos,Vals,Arg]]. 1010message( arg_ground(Pos,_Arg) ) --> 1011 { current_prolog_flag(pack_errors_arg,false) }, 1012 ['Ground argument expected at position: ~d'-[Pos]]. 1013message( arg_ground(Pos,Arg) ) --> 1014 ['Ground argument expected at position: ~d, (found: ~w)'-[Pos,Arg]]. 1015message( args_ground(Pos,_Arg) ) --> 1016 { current_prolog_flag(pack_errors_arg,false) }, 1017 ['Ground arguments expected at position: ~d'-[Pos]]. 1018message( args_ground(Pos,Arg) ) --> 1019 ['Ground argument expected at position: ~d, (found: ~w)'-[Pos,Arg]]. 1020% message( arg_ground_at_either(Pos1,Pos2,_Arg1,_Arg2) ) --> % Pos1 & Pos2 can be lists of positions 1021message( arg_ground_in_one_of(Poss,_Args) ) --> 1022 { current_prolog_flag(pack_errors_arg,false) }, 1023 ['Ground argument expected in one of the positions: ~w'-[Poss]]. 1024message( arg_ground_in_one_of(Poss,Args) ) --> 1025 ['Ground argument expected in one of the positions : ~w, but found: ~w'-[Poss,Args]]. 1026message( arg_ground_pattern(Poss,_Args) ) --> 1027 { current_prolog_flag(pack_errors_arg,false) }, 1028 ['Ground arguments expected in some of the positions: ~w'-[Poss]]. 1029message( arg_ground_pattern(Poss,Args) ) --> 1030 ['Ground arguments expected in some of the positions: ~w, but found:~w'-[Poss,Args]]. 1031 1032message( lengths_mismatch(Tkn1,Tkn2,Len1,Len2) ) --> 1033 ['Lists for ~w and ~w have mismatching lengths: ~d and ~d respectively'-[Tkn1,Tkn2,Len1,Len2]]. 1034message( lengths_mismatch(Tkn1,Tkn2,Op,Len1,Len2) ) --> 1035 ['Terms idied by: ~w and ~w, have mismatching lengths: ~d and ~d respectively (~w expected)'-[Tkn1,Tkn2,Len1,Len2,Op]]. 1036message( cast(Term,From,To) ) --> 1037 ['Cannot cast: ~w, from type: ~w to type: ~w'-[Term,From,To]]. 1038message( cast(Term,To) ) --> 1039 ['Cannot cast: ~w, to type: ~w'-[Term,To]]. 1040message( type_error(false,Type,Term) ) --> 1041 ['Object of type: ~w, expected but found term: ~w'-[Type,Term]]. 1042message( type_error(Pos,Type,Term) ) --> 1043 ['Object of type: ~w, expected at position:~w but found: ~w'-[Type,Pos,Term]]. 1044message( type_error(Type,Term) ) --> 1045 ['Object of type: ~w, expected but found term: ~w'-[Type,Term]]. 1046message( wrong_token(Tkn,Cat) ) --> % was: unknown_token/2 1047 ['Token: ~w, is not a recognisable: ~w'-[Tkn,Cat]]. 1048message( expected_from(_,Pid,false) ) --> 1049 ['Predicate: ~w is not defined'-[Pid]]. 1050message( expected_from(false,Pid,From) ) --> 1051 ['Predicate: ~w is not defined (source apparently available at: ~w; not asked to load)'-[Pid,From]]. 1052message( expected_from(true,Pid,From) ) --> 1053 ['Predicate: ~w is not defined (source apparently available at: ~w; which was loaded).'-[Pid,From]]. 1054message( input_file_missing(Os) ) --> 1055 ['Input file: ~w, is missing.'-[Os]]. 1056message( true ) --> 1057 []
Contextual error handling for packs
This is a stoics.infrastructure pack that
Version 0.3 introduced type errors via type/3 on top of must_be/2.
Version 2.0 has been re-written to be Options centric, fully decoupled and introduced of_same_length/3.
The pack manage mid-level error handling in a uniform way so other packs can use SWI's infracture in a simple way. The user only needs to define the print messages (if the pre-canned ones are not suitable) and then throw the appropriate terms during execution.
Two simple ways to identifying originating caller are provided by allowing options in either the message, or via using an new version of throw, throw/2.
In addition the library includes a number or pre-canned messages and has evolved to provide some error related predicates.
Throwing pack errors
Any term recognised as the first argument of the defined message/3 can be made to spit
a token identifying the originating pack/module and predicate. The main intuition is that this is the
the predicate responsible for the error. You can do this by either wrapping the message or by using
pack_error's own version of throw, throw/2.
Wrapping is via pack_error/2 where the first argument is the message and second is a list of options.
You can also use throw/2, which is defined in the pack, without wrapping the Message,
In both cases, you can drop the list if it contains a single element, thus
Note that in the latter case (throw/2) the options can also contain terms controling the execution of throw/2.
Options in both cases provide the context:
The library is loosely designed around the principle that most packs will define a homonym module. If both Pack and Mod are given and are the same only one is printed, however if they differ, they will both be shown. The order of identification is that of going throough the list above from top to bottom. The first one matching will identify the predicate and stop looking, so alternatives will be ignored.
Prepacked errors
Argument errors.
Poss is a list of (argument) positions and Args a list of arguments.
arg_enumerate(Pos,Vals,Arg)
see also type/3arg_ground(Pos,Arg)
, groundargument(s)
were expected at Posarg_ground_in_one_of(Poss,Args)
at least one ground argument was expected in a list of arguments (Args)arg_ground_pattern(Poss,Args)
Printing of Arg(s) itself can be surpressed with
prolog_flag(pack_errors_arg,false)
- useful for long data.Other errors
cast(Term,From,To)
)lengths_mismatch(Tkn1,Tkn2,Len1,Len2)
lengths_mismatch(Tkn1,Tkn2,Op,Len1,Len2)
type_error(Type,Term)
type_error(Pos,Type,Term)
wrong_token(Tkn,Cat)
Examples
Examples from other packs:
Defining new pack errors
Example file (available at
pack('pack_errors/examples/fold_data_errors.pl')
):Load and try with
Pack info
The library reacts to
debug(pack_errors)
spitting informational message along the execution of library predicates.Pack predicates:
+Error, +Opts
+Goal, +Error, +Opts
+Type, +Term
+Term, -Groundness
+Pid, +From, +Opts
+Lists
+List1, +List2, +Opts
+Version, +Date
Pack defined errors selection: (see
pack('pack_errors/prolog/pack_errors.pl')
for a full list)arg_ground(Pos,Arg)
arg_ground_in_one_of(Poss,Args)
lengths_mismatch(Tkn1,Tkn2,Len1,Len2)
cast(Term,To)
*/