mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 13:55:07 +00:00
Estimated hours taken: 32
Branches: main
Major improvements to tabling, of two types. The first is the implementation
of the loopcheck and memo forms of tabling for model_non procedures, and the
second is a start on the implementation of a new method of implementing
minimal model tabling, one that has the potential for a proper fix of the
problem that we currently merely detect with the pneg stack (the detection
is followed by a runtime abort). Since this new method relies on giving each
own generator its own stack, the grade component denoting it is "mmos"
(minimal model own stack). The true name of the existing method is changed
from "mm" to "mmsc" (minimal model stack copy). The grade component "mm"
is now a shorthand for "mmsc"; when the new method works, "mm" will be changed
to be a shorthand for "mmos".
configure.in:
scripts/canonical_grade.sh-subr:
scripts/init_grade_options.sh-subr:
scripts/parse_grade_options.sh-subr:
scripts/final_grade_options.sh-subr:
compiler/options.m:
Handle the new way of handling minimal model grades.
scripts/mgnuc.in:
compiler/compile_target_code.m:
Conform to the changes in minimal model grade options.
compiler/table_gen.m:
Implement the transformations required by the loopcheck and memo
tabling of model_non procedures, and the minimal model own stack
transformation.
The new implementation transformations use foreign_procs with extra
args, since there is no point in implementing them both that way and
with separate calls to library predicates. This required making the
choice of which method to use at the top level of each transformation.
Fix an oversight that hasn't caused problems yet but may in the future:
mark goals wrapping the original goals as not impure for determinism
computations.
compiler/handle_options.m:
Handle the new arrangement of the options for minimal model tabling.
Detect simultaneous calls for both forms of minimal model tabling,
and generate an error message. Allow for more than one error message
generated at once; report them all once rather than separately.
compiler/globals.m:
Add a mechanism to allow a fix a problem detected by the changes
to handle_options: the fact that we currently may generate a usage
message more than once for invocations with more than one error.
compiler/mercury_compile.m:
compiler/make.program_target.m:
compiler/make.util.m:
Use the new mechanism in handle_options to avoid generating duplicate
usage messages.
compiler/error_util.m:
Add a utility predicate for use by handle_options.
compiler/hlds_pred.m:
Allow memo tabling for model_non predicates, and handle own stack
tabling.
compiler/hlds_out.m:
Print information about the modes of the arguments of foreign_procs,
since this is useful in debugging transformations such as tabling
that generate them.
compiler/prog_data.m:
compiler/layout_out.m:
compiler/prog_out.m:
runtime/mercury_stack_layout.h:
Mention the new evaluation method.
compiler/goal_util.m:
Change the predicates for creating calls and foreign_procs to allow
more than one goal feature to be attached to the new goal. table_gen.m
now uses this capability.
compiler/add_heap_ops.m:
compiler/add_trail_ops.m:
compiler/polymorphism.m:
compiler/simplify.m:
compiler/size_prof.m:
compiler/typecheck.m:
compiler/unify_proc.m:
Conform to the changes in goal_util.
compiler/code_info.m:
compiler/make_hlds.m:
compiler/modules.m:
compiler/prog_io_pragma.m:
Conform to the new the options controlling minimal model
tabling.
compiler/prog_util.m:
Add a utility predicate for use by table_gen.m.
library/std_util.m:
Conform to the changes in the macros for minimal model tabling grades.
library/table_builtin.m:
Add the types and predicates required by the new transformations.
Delete an obsolete comment.
runtime/mercury_grade.h:
Handle the new minimal model grade component.
runtime/mercury_conf_param.h:
List macros controlling minimal model grades.
runtime/mercury_tabling.[ch]:
Define the types needed by the new transformations,
Implement the performance-critical predicates that need to be
hand-written for memo tabling of model_non predicates.
Add utility predicates for debugging.
runtime/mercury_tabling_preds.h:
Add the implementations of the predicates required by the new
transformations.
runtime/mercury_mm_own_stacks.[ch]:
This new module contains the first draft of the implementation
of the own stack implementation of minimal model tabling.
runtime/mercury_imp.h:
Include the new file if the grade needs it.
runtime/Mmakefile:
Mention the new files, and sort the lists of filenames.
runtime/mercury_tabling_macros.h:
Add a macro for allocating answer blocks without requiring them to be
pointed to directly by trie nodes.
runtime/mercury_minimal_model.[ch]:
The structure type holding answer lists is now in mercury_tabling.h,
since it is now also needed by memo tabling of model_non predicates.
It no longer has a field for an answer num, because while it is ok
to require a separate grade for debugging minimal model tabling,
it is not ok to require a separate grade for debugging memo tabling
of model_non predicates. Instead of printing the answer numbers,
print the answers themselves when we need to identify solutions
for debugging.
Change function names, macro names, error messages etc where this is
useful to distinguish the two kinds of minimal model tabling.
Fix some oversights wrt transient registers.
runtime/mercury_context.[ch]:
runtime/mercury_engine.[ch]:
runtime/mercury_memory.[ch]:
runtime/mercury_wrapper.[ch]:
With own stack tabling, each subgoal has its own context, so record
the identity of the subgoal owning a context in the context itself.
The main computation's context is the exception: it has no owner.
Record not just the main context, but also the contexts of subgoals
in the engine.
Add variables for holding the sizes of the det and nondet stacks
of the contexts of subgoals (which should in general be smaller
than the sizes of the corresponding stacks of the main context),
and initialize them as needed.
Initialize the variables holding the sizes of the gen, cut and pneg
stacks, even in grades where the stacks are not used, for safety.
Fix some out-of-date documentation, and conform to our coding
guidelines.
runtime/mercury_memory_zones.[ch]:
Add a function to test whether a pointer is in a zone, to help
debugging.
runtime/mercury_debug.[ch]:
Add some functions to help debugging in the presence of multiple
contexts, and factor out some common code to help with this.
Delete the obsolete, unused function MR_printdetslot_as_label.
runtime/mercury_context.h:
runtime/mercury_bootstrap.h:
Move a bootstrapping #define from mercury_context.h to
mercury_bootstrap.h.
runtime/mercury_context.h:
runtime/mercury_bootstrap.h:
Move a bootstrapping #define from mercury_context.h to
mercury_bootstrap.h.
runtime/mercury_types.h:
Add some more forward declarations of type names.
runtime/mercury_dlist.[ch]:
Rename a field to avoid assignments that dereference NULL.
runtime/mercury_debug.c:
runtime/mercury_memory.c:
runtime/mercury_ml_expand_body.h:
runtime/mercury_stack_trace.c:
runtime/mercury_stacks.[ch]:
trace/mercury_trace_util.c
Update uses of the macros that control minimal model tabling.
runtime/mercury_stack_trace.c:
Provide a mechanism to allow stack traces to be suppressed entirely.
The intention is that by using this mechanism, by the testing system
won't have to provide separate .exp files for hlc grades, nondebug
LLDS grades and debug LLDS grades, as we do currently. The mechanism
is the environment variable MERCURY_SUPPRESS_STACK_TRACE.
tools/bootcheck:
tools/test_mercury:
Specify MERCURY_SUPPRESS_STACK_TRACE.
trace/mercury_trace.c:
When performing retries across tabled calls, handle memo tabled
model_non predicates, for which the call table tip variable holds
a record with a back pointer to a trie node, instead of the trie node
itself.
trace/mercury_trace_internal.c:
When printing tables, handle memo tabled model_non predicates. Delete
the code now moved to runtime/mercury_tabling.c.
Add functions for printing the data structures for own stack minimal
model tabling.
tests/debugger/print_table.{m,inp,exp}:
Update this test case to also test the printing of tables for
memo tabled model_non predicates.
tests/debugger/retry.{m,inp,exp}:
Update this test case to also test retries across memo tabled
model_non predicates.
tests/tabling/loopcheck_nondet.{m,exp}:
tests/tabling/loopcheck_nondet_non_loop.{m,exp}:
New test cases to test loopcheck tabled model_non predicates.
One test case has a loop to detect, one doesn't.
tests/tabling/memo_non.{m,exp}:
tests/tabling/tc_memo.{m,exp}:
tests/tabling/tc_memo2.{m,exp}:
New test cases to test memo tabled model_non predicates.
One test case has a loop to detect, one has a need for minimal model
tabling to detect, and the third doesn't have either.
tests/tabling/Mmakefile:
Add the new test cases, and reenable the existing tc_loop test case.
Rename some make variables and targets to make them better reflect
their meaning.
tests/tabling/test_mercury:
Conform to the change in the name of the make target.
561 lines
17 KiB
Mathematica
561 lines
17 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-2004 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% error_util.m
|
|
% Main author: zs.
|
|
%
|
|
% This module contains code that can be helpful in the formatting of
|
|
% error messages.
|
|
%
|
|
% Given a context, a starting indentation level and a list of words,
|
|
% print an error message that looks like this:
|
|
%
|
|
% module.m:10: first line of error message blah blah blah
|
|
% module.m:10: second line of error message blah blah blah
|
|
% module.m:10: third line of error message blah blah blah
|
|
%
|
|
% The words will be packed into lines as tightly as possible,
|
|
% with spaces between each pair of words, subject to the constraints
|
|
% that every line starts with a context, followed by Indent+1 spaces
|
|
% on the first line and Indent+3 spaces on later lines, and that every
|
|
% line contains at most 79 characters (unless a long single word
|
|
% forces the line over this limit).
|
|
%
|
|
% The caller supplies the list of words to be printed in the form
|
|
% of a list of error message components. Each component may specify
|
|
% a string to printed exactly as it is, or it may specify a string
|
|
% containing a list of words, which may be broken at white space.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree__error_util.
|
|
|
|
:- interface.
|
|
|
|
:- import_module parse_tree__prog_data.
|
|
|
|
:- import_module bool, char, io, list, std_util.
|
|
|
|
:- type format_component
|
|
---> fixed(string) % This string should appear in the output
|
|
% in one piece, as it is.
|
|
|
|
; words(string) % This string contains words separated by
|
|
% white space. The words should appear in
|
|
% the output in the given order, but the
|
|
% white space may be rearranged and line
|
|
% breaks may be inserted.
|
|
|
|
; sym_name(sym_name)
|
|
% The output should contain the string form of
|
|
% the sym_name, surrounded by `' quotes.
|
|
|
|
; nl. % Insert a line break if there has been text
|
|
% output since the last line break.
|
|
|
|
% Convert a list of strings into a list of format_components,
|
|
% suitable for displaying as an error message.
|
|
:- pred list_to_pieces(list(string)::in,
|
|
list(format_component)::out) is det.
|
|
|
|
% Convert a list of lists of format_components into a list of
|
|
% format_components separated by commas, with the last two
|
|
% elements separated by `and'.
|
|
:- func component_lists_to_pieces(list(list(format_component))) =
|
|
list(format_component).
|
|
|
|
% Display the given error message, without a context and with standard
|
|
% indentation.
|
|
:- pred write_error_pieces_plain(list(format_component)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
% write_error_plain_with_progname(ProgName, Msg):
|
|
% Display Msg as the error string, with ProgName as a context
|
|
% and with standard indentation.
|
|
:- pred write_error_plain_with_progname(string::in, string::in,
|
|
io::di, io::uo) is det.
|
|
|
|
% Display the given error message.
|
|
:- pred write_error_pieces(prog_context::in, int::in,
|
|
list(format_component)::in, io::di, io::uo) is det.
|
|
|
|
% Display the given error message, but indent the first line.
|
|
% This is useful when adding extra lines to an already
|
|
% displayed message.
|
|
:- pred write_error_pieces_not_first_line(prog_context::in, int::in,
|
|
list(format_component)::in, io::di, io::uo) is det.
|
|
|
|
% Display the given error message. The bool is true iff
|
|
% this is the first line.
|
|
:- pred write_error_pieces_maybe_first_line(bool::in, prog_context::in,
|
|
int::in, list(format_component)::in, io::di, io::uo) is det.
|
|
|
|
:- pred write_error_pieces_maybe_with_context(maybe(prog_context)::in, int::in,
|
|
list(format_component)::in, io::di, io::uo) is det.
|
|
|
|
:- func describe_sym_name(sym_name) = string.
|
|
|
|
:- func describe_sym_name_and_arity(sym_name_and_arity) = string.
|
|
|
|
:- func pred_or_func_to_string(pred_or_func) = string.
|
|
|
|
% Append a punctuation character to a message, avoiding unwanted
|
|
% line splitting between the message and the punctuation.
|
|
:- func append_punctuation(list(format_component), char) =
|
|
list(format_component).
|
|
|
|
% report_error_num_args(MaybePredOrFunc, Arity, CorrectArities).
|
|
%
|
|
% Write
|
|
% "wrong number of arguments (<Arity>; should be <CorrectArities>)",
|
|
% adjusting `Arity' and `CorrectArities' if `MaybePredOrFunc' is
|
|
% `yes(function)'.
|
|
:- pred report_error_num_args(maybe(pred_or_func)::in, int::in, list(int)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
% sorry(ModuleName, Message)
|
|
% Call error/1 with a "Sorry, not implemented" message.
|
|
%
|
|
% Use this for features that should be implemented (or at
|
|
% least could be implemented).
|
|
%
|
|
:- pred sorry(string::in, string::in) is erroneous.
|
|
|
|
% unexpected(ModuleName, Message)
|
|
% Call error/1 with an "Unexpected" message.
|
|
%
|
|
% Use this to handle cases which are not expected to arise (i.e.
|
|
% bugs).
|
|
%
|
|
:- pred unexpected(string::in, string::in) is erroneous.
|
|
|
|
% Record the fact that a warning has been issued; set the exit status
|
|
% to error if the --halt-at-warn option is set.
|
|
:- pred record_warning(io::di, io::uo) is det.
|
|
|
|
% Report a warning, and set the exit status to error if the
|
|
% --halt-at-warn option is set.
|
|
:- pred report_warning(string::in, io::di, io::uo) is det.
|
|
|
|
% Report a warning to the specified stream, and set the exit status
|
|
% to error if the --halt-at-warn option is set.
|
|
:- pred report_warning(io__output_stream::in, string::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Report a warning, and set the exit status to error if the
|
|
% --halt-at-warn option is set.
|
|
:- pred report_warning(prog_context::in, int::in, list(format_component)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module parse_tree__prog_out.
|
|
:- import_module parse_tree__prog_util.
|
|
:- import_module libs__globals.
|
|
:- import_module libs__options.
|
|
|
|
:- import_module io, list, term, char, string, int, require.
|
|
|
|
list_to_pieces([], []).
|
|
list_to_pieces([Elem], [words(Elem)]).
|
|
list_to_pieces([Elem1, Elem2],
|
|
[fixed(Elem1), words("and"), fixed(Elem2)]).
|
|
list_to_pieces([Elem1, Elem2, Elem3 | Elems], Pieces) :-
|
|
string__append(Elem1, ",", Piece1),
|
|
list_to_pieces([Elem2, Elem3 | Elems], Pieces1),
|
|
Pieces = [fixed(Piece1) | Pieces1].
|
|
|
|
component_lists_to_pieces([]) = [].
|
|
component_lists_to_pieces([Components]) = Components.
|
|
component_lists_to_pieces([Components1, Components2]) =
|
|
list__condense([Components1, [words("and")], Components2]).
|
|
component_lists_to_pieces(
|
|
[Components1, Components2, Components3 | Components]) =
|
|
list__append(append_punctuation(Components1, ','),
|
|
component_lists_to_pieces(
|
|
[Components2, Components3 | Components])).
|
|
|
|
write_error_pieces_plain(Components, !IO) :-
|
|
write_error_pieces_maybe_with_context(yes, no, 0, Components, !IO).
|
|
|
|
write_error_plain_with_progname(ProgName, Msg, !IO) :-
|
|
write_error_pieces_plain([fixed(ProgName ++ ":"), words(Msg)], !IO).
|
|
|
|
write_error_pieces(Context, Indent, Components, !IO) :-
|
|
write_error_pieces_maybe_with_context(yes, yes(Context),
|
|
Indent, Components, !IO).
|
|
|
|
write_error_pieces_not_first_line(Context, Indent, Components, !IO) :-
|
|
write_error_pieces_maybe_with_context(no, yes(Context),
|
|
Indent, Components, !IO).
|
|
|
|
write_error_pieces_maybe_first_line(IsFirst, Context, Indent, Components,
|
|
!IO) :-
|
|
(
|
|
IsFirst = yes,
|
|
write_error_pieces(Context, Indent, Components, !IO)
|
|
;
|
|
IsFirst = no,
|
|
write_error_pieces_not_first_line(Context, Indent, Components,
|
|
!IO)
|
|
).
|
|
|
|
write_error_pieces_maybe_with_context(MaybeContext, Indent, Components, !IO) :-
|
|
write_error_pieces_maybe_with_context(yes, MaybeContext,
|
|
Indent, Components, !IO).
|
|
|
|
:- pred write_error_pieces_maybe_with_context(bool::in,
|
|
maybe(prog_context)::in, int::in, list(format_component)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
write_error_pieces_maybe_with_context(IsFirst, MaybeContext,
|
|
Indent, Components, !IO) :-
|
|
(
|
|
% The fixed characters at the start of the line are:
|
|
% filename
|
|
% :
|
|
% line number (min 3 chars)
|
|
% :
|
|
% space
|
|
% indent
|
|
(
|
|
MaybeContext = yes(Context),
|
|
term__context_file(Context, FileName),
|
|
term__context_line(Context, LineNumber),
|
|
string__length(FileName, FileNameLength),
|
|
string__int_to_string(LineNumber, LineNumberStr),
|
|
string__length(LineNumberStr, LineNumberStrLength0),
|
|
( LineNumberStrLength0 < 3 ->
|
|
LineNumberStrLength = 3
|
|
;
|
|
LineNumberStrLength = LineNumberStrLength0
|
|
),
|
|
ContextLength = FileNameLength + 1 +
|
|
LineNumberStrLength + 2
|
|
;
|
|
MaybeContext = no,
|
|
ContextLength = 0
|
|
),
|
|
NotFirstIndent = (IsFirst = yes -> 0 ; 2),
|
|
Remain = 79 - (ContextLength + Indent + NotFirstIndent),
|
|
convert_components_to_word_list(Components, [], [], Words),
|
|
group_words(IsFirst, Words, Remain, Lines)
|
|
),
|
|
( IsFirst = yes ->
|
|
write_lines(Lines, MaybeContext, Indent, !IO)
|
|
;
|
|
write_nonfirst_lines(Lines, MaybeContext, Indent + 2, !IO)
|
|
).
|
|
|
|
:- pred write_lines(list(list(string))::in, maybe(prog_context)::in, int::in,
|
|
io::di, io::uo) is det.
|
|
|
|
write_lines([], _, _, !IO).
|
|
write_lines([Line | Lines], MaybeContext, Indent, !IO) :-
|
|
(
|
|
MaybeContext = yes(Context),
|
|
prog_out__write_context(Context, !IO)
|
|
;
|
|
MaybeContext = no
|
|
),
|
|
string__pad_left("", ' ', Indent, IndentStr),
|
|
io__write_string(IndentStr, !IO),
|
|
write_line(Line, !IO),
|
|
Indent2 = Indent + 2,
|
|
write_nonfirst_lines(Lines, MaybeContext, Indent2, !IO).
|
|
|
|
:- pred write_nonfirst_lines(list(list(string))::in, maybe(prog_context)::in,
|
|
int::in, io::di, io::uo) is det.
|
|
|
|
write_nonfirst_lines([], _, _, !IO).
|
|
write_nonfirst_lines([Line | Lines], MaybeContext, Indent, !IO) :-
|
|
(
|
|
MaybeContext = yes(Context),
|
|
prog_out__write_context(Context, !IO)
|
|
;
|
|
MaybeContext = no
|
|
),
|
|
string__pad_left("", ' ', Indent, IndentStr),
|
|
io__write_string(IndentStr, !IO),
|
|
write_line(Line, !IO),
|
|
write_nonfirst_lines(Lines, MaybeContext, Indent, !IO).
|
|
|
|
:- pred write_line(list(string)::in, io::di, io::uo) is det.
|
|
|
|
write_line([], !IO).
|
|
write_line([Word | Words], !IO) :-
|
|
io__write_string(Word, !IO),
|
|
write_line_rest(Words, !IO),
|
|
io__write_char('\n', !IO).
|
|
|
|
:- pred write_line_rest(list(string)::in, io::di, io::uo) is det.
|
|
|
|
write_line_rest([], !IO).
|
|
write_line_rest([Word | Words], !IO) :-
|
|
io__write_char(' ', !IO),
|
|
io__write_string(Word, !IO),
|
|
write_line_rest(Words, !IO).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- pred convert_components_to_word_list(list(format_component)::in,
|
|
list(string)::in, list(list(string))::in, list(list(string))::out)
|
|
is det.
|
|
|
|
convert_components_to_word_list([], Words0, Paras0, Paras) :-
|
|
list__reverse(Words0, Words),
|
|
list__reverse([Words | Paras0], Paras).
|
|
convert_components_to_word_list([Component | Components], Words0,
|
|
Paras0, Paras) :-
|
|
(
|
|
Component = fixed(Word),
|
|
Words1 = [Word | Words0],
|
|
Paras1 = Paras0
|
|
;
|
|
Component = words(WordsStr),
|
|
break_into_words(WordsStr, Words0, Words1),
|
|
Paras1 = Paras0
|
|
;
|
|
Component = sym_name(SymName),
|
|
Words1 = [sym_name_to_word(SymName) | Words0],
|
|
Paras1 = Paras0
|
|
;
|
|
Component = nl,
|
|
list__reverse(Words0, Words),
|
|
Paras1 = [Words | Paras0],
|
|
Words1 = []
|
|
),
|
|
convert_components_to_word_list(Components, Words1, Paras1, Paras).
|
|
|
|
:- func sym_name_to_word(sym_name) = string.
|
|
|
|
sym_name_to_word(SymName) = "`" ++ SymStr ++ "'" :-
|
|
sym_name_to_string(SymName, SymStr).
|
|
|
|
:- pred break_into_words(string::in, list(string)::in, list(string)::out)
|
|
is det.
|
|
|
|
break_into_words(String, Words0, Words) :-
|
|
break_into_words_from(String, 0, Words0, Words).
|
|
|
|
:- pred break_into_words_from(string::in, int::in, list(string)::in,
|
|
list(string)::out) is det.
|
|
|
|
break_into_words_from(String, Cur, Words0, Words) :-
|
|
( find_word_start(String, Cur, Start) ->
|
|
find_word_end(String, Start, End),
|
|
Length = End - Start + 1,
|
|
string__substring(String, Start, Length, Word),
|
|
Next = End + 1,
|
|
break_into_words_from(String, Next, [Word | Words0], Words)
|
|
;
|
|
Words = Words0
|
|
).
|
|
|
|
:- pred find_word_start(string::in, int::in, int::out) is semidet.
|
|
|
|
find_word_start(String, Cur, WordStart) :-
|
|
string__index(String, Cur, Char),
|
|
( char__is_whitespace(Char) ->
|
|
Next = Cur + 1,
|
|
find_word_start(String, Next, WordStart)
|
|
;
|
|
WordStart = Cur
|
|
).
|
|
|
|
:- pred find_word_end(string::in, int::in, int::out) is det.
|
|
|
|
find_word_end(String, Cur, WordEnd) :-
|
|
Next = Cur + 1,
|
|
( string__index(String, Next, Char) ->
|
|
( char__is_whitespace(Char) ->
|
|
WordEnd = Cur
|
|
;
|
|
find_word_end(String, Next, WordEnd)
|
|
)
|
|
;
|
|
WordEnd = Cur
|
|
).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
% Groups the given words into lines. The first line can have up to Max
|
|
% characters on it; the later lines (if any) up to Max-2 characters.
|
|
% The given list of words must be nonempty, since we always return
|
|
% at least one line.
|
|
|
|
:- pred group_words(bool::in, list(list(string))::in, int::in,
|
|
list(list(string))::out) is det.
|
|
|
|
group_words(IsFirst, Paras, Max, Lines) :-
|
|
(
|
|
Paras = [],
|
|
Lines = []
|
|
;
|
|
Paras = [FirstPara | LaterParas],
|
|
(
|
|
FirstPara = [],
|
|
group_words(IsFirst, LaterParas, Max, Lines)
|
|
;
|
|
FirstPara = [FirstWord | LaterWords],
|
|
get_line_of_words(FirstWord, LaterWords,
|
|
Max, Line, RestWords),
|
|
( IsFirst = yes ->
|
|
Max2 = Max - 2
|
|
;
|
|
Max2 = Max
|
|
),
|
|
group_nonfirst_line_words(RestWords, Max2, RestLines1),
|
|
Lines1 = [Line | RestLines1],
|
|
group_words(no, LaterParas, Max2, RestLines),
|
|
list__append(Lines1, RestLines, Lines)
|
|
)
|
|
).
|
|
|
|
:- pred group_nonfirst_line_words(list(string)::in, int::in,
|
|
list(list(string))::out) is det.
|
|
|
|
group_nonfirst_line_words(Words, Max, Lines) :-
|
|
(
|
|
Words = [],
|
|
Lines = []
|
|
;
|
|
Words = [FirstWord | LaterWords],
|
|
get_line_of_words(FirstWord, LaterWords, Max, Line, RestWords),
|
|
group_nonfirst_line_words(RestWords, Max, RestLines),
|
|
Lines = [Line | RestLines]
|
|
).
|
|
|
|
:- pred get_line_of_words(string::in, list(string)::in, int::in,
|
|
list(string)::out, list(string)::out) is det.
|
|
|
|
get_line_of_words(FirstWord, LaterWords, MaxLen, Line, RestWords) :-
|
|
string__length(FirstWord, FirstWordLen),
|
|
get_later_words(LaterWords, FirstWordLen, MaxLen, [FirstWord],
|
|
Line, RestWords).
|
|
|
|
:- pred get_later_words(list(string)::in, int::in, int::in,
|
|
list(string)::in, list(string)::out, list(string)::out) is det.
|
|
|
|
get_later_words([], _, _, Line, Line, []).
|
|
get_later_words([Word | Words], OldLen, MaxLen, Line0, Line, RestWords) :-
|
|
string__length(Word, WordLen),
|
|
NewLen = OldLen + 1 + WordLen,
|
|
( NewLen =< MaxLen ->
|
|
list__append(Line0, [Word], Line1),
|
|
get_later_words(Words, NewLen, MaxLen,
|
|
Line1, Line, RestWords)
|
|
;
|
|
Line = Line0,
|
|
RestWords = [Word | Words]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
describe_sym_name_and_arity(SymName / Arity) =
|
|
string__append_list(["`", SymNameString,
|
|
"/", string__int_to_string(Arity), "'"]) :-
|
|
sym_name_to_string(SymName, SymNameString).
|
|
|
|
describe_sym_name(SymName) =
|
|
string__append_list(["`", SymNameString, "'"]) :-
|
|
sym_name_to_string(SymName, SymNameString).
|
|
|
|
pred_or_func_to_string(predicate) = "predicate".
|
|
pred_or_func_to_string(function) = "function".
|
|
|
|
append_punctuation([], _) = _ :-
|
|
error("append_punctuation: " ++
|
|
"appending punctuation after nothing").
|
|
append_punctuation([Piece0], Punc) = [Piece] :-
|
|
% Avoid unwanted line splitting between the message
|
|
% and the punctuation.
|
|
(
|
|
Piece0 = words(String),
|
|
Piece = words(string__append(String, char_to_string(Punc)))
|
|
;
|
|
Piece0 = fixed(String),
|
|
Piece = fixed(string__append(String, char_to_string(Punc)))
|
|
;
|
|
Piece0 = sym_name(SymName),
|
|
String = sym_name_to_word(SymName),
|
|
Piece = fixed(string__append(String, char_to_string(Punc)))
|
|
;
|
|
Piece0 = nl,
|
|
error("append_punctutation: " ++
|
|
"appending punctuation after newline")
|
|
).
|
|
append_punctuation([Piece1, Piece2 | Pieces], Punc) =
|
|
[Piece1 | append_punctuation([Piece2 | Pieces], Punc)].
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
report_error_num_args(MaybePredOrFunc, Arity0, Arities0, !IO) :-
|
|
% Adjust arities for functions.
|
|
( MaybePredOrFunc = yes(function) ->
|
|
adjust_func_arity(function, Arity, Arity0),
|
|
list__map(
|
|
(pred(OtherArity0::in, OtherArity::out) is det :-
|
|
adjust_func_arity(function,
|
|
OtherArity, OtherArity0)
|
|
),
|
|
Arities0, Arities)
|
|
;
|
|
Arity = Arity0,
|
|
Arities = Arities0
|
|
),
|
|
io__write_string("wrong number of arguments (", !IO),
|
|
io__write_int(Arity, !IO),
|
|
io__write_string("; should be ", !IO),
|
|
report_error_right_num_args(Arities, !IO),
|
|
io__write_string(")", !IO).
|
|
|
|
:- pred report_error_right_num_args(list(int)::in, io::di, io::uo) is det.
|
|
|
|
report_error_right_num_args([], !IO).
|
|
report_error_right_num_args([Arity | Arities], !IO) :-
|
|
io__write_int(Arity, !IO),
|
|
( Arities = [] ->
|
|
true
|
|
; Arities = [_] ->
|
|
io__write_string(" or ", !IO)
|
|
;
|
|
io__write_string(", ", !IO)
|
|
),
|
|
report_error_right_num_args(Arities, !IO).
|
|
|
|
% Call error/1 with a "Sorry, not implemented" message.
|
|
%
|
|
sorry(Module, What) :-
|
|
string__format("%s: Sorry, not implemented: %s",
|
|
[s(Module), s(What)], ErrorMessage),
|
|
error(ErrorMessage).
|
|
|
|
unexpected(Module, What) :-
|
|
string__format("%s: Unexpected: %s",
|
|
[s(Module), s(What)], ErrorMessage),
|
|
error(ErrorMessage).
|
|
|
|
record_warning(!IO) :-
|
|
globals__io_lookup_bool_option(halt_at_warn, HaltAtWarn, !IO),
|
|
( HaltAtWarn = yes ->
|
|
io__set_exit_status(1, !IO)
|
|
;
|
|
true
|
|
).
|
|
|
|
report_warning(Message, !IO) :-
|
|
record_warning(!IO),
|
|
io__write_string(Message, !IO).
|
|
|
|
report_warning(Stream, Message, !IO) :-
|
|
record_warning(!IO),
|
|
io__write_string(Stream, Message, !IO).
|
|
|
|
report_warning(Context, Indent, Components, !IO) :-
|
|
record_warning(!IO),
|
|
write_error_pieces(Context, Indent, Components, !IO).
|