mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-22 21:03:53 +00:00
Estimated hours taken: 3 Add predicates to perform lower-bound and upper-bound searching, in which if a search for a key fails, we return the next lower (or higher) key and its associated value. library/bintree.m: library/rbtree.m: library/tree234.m: library/map.m: Add lower-bound and upper-bound search and lookup predicates. Add plain lookup predicates where missing, or move them next to their corresponding search preds. Make the handling of lookup errors more uniform. library/require.m: Move map__lookup_error here as report_lookup_error, for use by bintree, rbtree and tree234, as well as map.
143 lines
3.7 KiB
Mathematica
143 lines
3.7 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1993-1999 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module require.
|
|
|
|
% Main author: fjh.
|
|
% Stability: medium to high.
|
|
|
|
% This module provides features similar to <assert.h> in C.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- interface.
|
|
|
|
:- pred error(string).
|
|
:- mode error(in) is erroneous.
|
|
|
|
% error(Message).
|
|
% Abort with error message.
|
|
|
|
|
|
:- pred require(pred, string).
|
|
:- mode require((pred) is semidet, in) is det.
|
|
|
|
% require(Goal, Message).
|
|
% Call goal, and abort with error message if Goal fails.
|
|
% This is not as useful as you might imagine, since it requires
|
|
% that the goal not produce any output variables. In
|
|
% most circumstances you should use an explicit if-then-else
|
|
% with a call to error/1 in the "else".
|
|
|
|
:- pred report_lookup_error(string, K, V).
|
|
:- mode report_lookup_error(in, in, unused) is erroneous.
|
|
|
|
% report_lookup_error(Message, Key, Value)
|
|
% Call error/1 with an error message that is appropriate for
|
|
% the failure of a lookup operation involving the specified
|
|
% Key and Value. The error message will include Message
|
|
% and information about Key and Value.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module string, list, std_util.
|
|
|
|
require(Goal, Message) :-
|
|
( call(Goal) ->
|
|
true
|
|
;
|
|
error(Message),
|
|
fail
|
|
).
|
|
|
|
report_lookup_error(Msg, K, V) :-
|
|
KeyType = type_name(type_of(K)),
|
|
ValueType = type_name(type_of(V)),
|
|
functor(K, Functor, Arity),
|
|
( Arity = 0 ->
|
|
FunctorStr = Functor
|
|
;
|
|
string__int_to_string(Arity, ArityStr),
|
|
string__append_list([Functor, "/", ArityStr], FunctorStr)
|
|
),
|
|
string__append_list(
|
|
[Msg,
|
|
"\n\tKey Type: ",
|
|
KeyType,
|
|
"\n\tKey Functor: ",
|
|
FunctorStr,
|
|
"\n\tValue Type: ",
|
|
ValueType
|
|
],
|
|
ErrorString),
|
|
error(ErrorString).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
/* error/1, from require.m */
|
|
|
|
:- pragma c_header_code("
|
|
#include <stdio.h>
|
|
#include ""mercury_trace_base.h""
|
|
#include ""mercury_stack_trace.h""
|
|
").
|
|
|
|
% Hopefully error/1 won't be called often (!), so no point inlining it.
|
|
:- pragma no_inline(error/1).
|
|
|
|
error(Message) :-
|
|
error_internal(Message).
|
|
|
|
:- pred error_internal(string::in) is erroneous.
|
|
|
|
% We define error using handwritten code in error_internal because we
|
|
% need complete control over it if we want to call MR_dump_stack. In
|
|
% particular we don't want to have to explicitly tell MR_dump_stack whether
|
|
% a stack frame was generated by its caller. The easiest way to do
|
|
% this is to make sure it wasn't.
|
|
|
|
:- external(error_internal/1).
|
|
|
|
:- pragma c_code("
|
|
|
|
Define_extern_entry(mercury__require__error_internal_1_0);
|
|
|
|
BEGIN_MODULE(require_internal_module)
|
|
init_entry(mercury__require__error_internal_1_0);
|
|
BEGIN_CODE
|
|
|
|
/* code for predicate 'error_internal'/1 in mode 0 */
|
|
Define_entry(mercury__require__error_internal_1_0);
|
|
{
|
|
String Message;
|
|
Message = (String) r1;
|
|
|
|
fflush(stdout);
|
|
fprintf(stderr, ""Software error: %s\\n"", Message);
|
|
MR_trace_report(stderr);
|
|
MR_dump_stack(MR_succip, MR_sp, MR_curfr, FALSE);
|
|
exit(1);
|
|
}
|
|
END_MODULE
|
|
|
|
/*
|
|
** Ensure that the initialization function for the above module gets run.
|
|
*/
|
|
/*
|
|
INIT sys_init_require_internal_module
|
|
*/
|
|
extern ModuleFunc require_internal_module;
|
|
void sys_init_require_internal_module(void);
|
|
void sys_init_require_internal_module(void) {
|
|
require_internal_module();
|
|
}
|
|
").
|
|
|
|
:- end_module require.
|
|
|
|
%-----------------------------------------------------------------------------%
|