mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 18:03:36 +00:00
When a user writes a clause for a predicate (or function) that does not exist
with that arity, but does exist with one or more other arities, report not
just the list of the other arity/arities, but, for each such other arity,
a diff between the declared arg types and the inferred arg types.
After this diff, we generate output like this:
bad_pred_arity.m:027: Error: clause for predicate `bad_pred_arity.p'/4
bad_pred_arity.m:027: without corresponding `:- pred' declaration.
bad_pred_arity.m:027: However, predicates of that name do exist with arities
bad_pred_arity.m:027: 3 and 5.
bad_pred_arity.m:027: Inferred :- pred p(int, string, int, string).
bad_pred_arity.m:027: The argument list difference from the arity 3 version
bad_pred_arity.m:027: is
bad_pred_arity.m:027: pred(
bad_pred_arity.m:027: int,
bad_pred_arity.m:027: + string,
bad_pred_arity.m:027: int,
bad_pred_arity.m:027: string
bad_pred_arity.m:027: )
bad_pred_arity.m:027: The argument list difference from the arity 5 version
bad_pred_arity.m:027: is
bad_pred_arity.m:027: pred(
bad_pred_arity.m:027: int,
bad_pred_arity.m:027: - float,
bad_pred_arity.m:027: string,
bad_pred_arity.m:027: int,
bad_pred_arity.m:027: string
bad_pred_arity.m:027: )
compiler/typecheck_errors.m:
Generate the diff part of the message above.
compiler/typecheck.m:
Invoke typecheck_errors.m when relevant.
compiler/error_util.m:
When comparing two error_specs, switch from a two-level comparison
(first the contexts of error_msgs, then everything else) to three levels
first the contexts of error_msgs, then their error_msg_components,
then everything else). This is needed to allow the error message from
make_hlds_error.m (which reports the error and mentions the arities
with which the named predicate or function does exist) come out before
the informational message from typecheck.m that prints the inferred
arg types and their differences from the other arities. (With the old
comparison, the difference in severity would trump the invisible order
components that this diff includes in both specs to force the desire
order.)
Base the code comparing error_specs on the code for comparing error_msgs.
Move the two previously separate pieces code for those tasks next to each
other.
compiler/make_hlds_error.m:
Add the invisble ordering component.
When we see clauses with two or more wrong arities for a given predicate
or function, don't list the automatically created pred declaration
for an *earlier* wrong-arity clause as a real declaration whose arity
is to be listed in the error messages we generate for *later* wrong-arity
clauses.
Add some documentation.
compiler/add_pred.m:
Factor out some common code.
library/edit_seq.m:
A new module for computing diffs.
library/library.m:
library/MODULES_DOC:
Add the new module to the standard library.
tests/hard_coded/edit_seq_test.{m,exp}:
A new test case for the diff algorithm.
tests/invalid/bad_pred_arity.{m,err_exp}:
A new test case for the new error message.
tests/hard_coded/Mmakefile:
tests/invalid/Mmakefile:
Enable the new test cases.
tests/invalid/bigtest.err_exp:
tests/invalid/bug197.err_exp:
tests/invalid/bug278.err_exp:
tests/invalid/errors2.err_exp:
tests/invalid/invalid_binary_literal.err_exp:
tests/invalid/invalid_float_literal.err_exp:
tests/invalid/invalid_hex_literal.err_exp:
tests/invalid/invalid_main.err_exp:
tests/invalid/invalid_octal_literal.err_exp:
tests/invalid/multimode_dcg.err_exp:
tests/invalid/multisoln_func.err_exp:
tests/invalid/null_char.err_exp:
tests/invalid/state_vars_test3.err_exp:
tests/invalid/try_detism.err_exp2:
tests/invalid/typeclass_test_5.err_exp:
tests/invalid/typeclass_test_8.err_exp:
tests/invalid/unsatisfiable_constraint.err_exp:
tests/invalid_purity/impure_func_t3.err_exp:
Update these files to expect error messages in the new order.
samples/diff/*.m:
Fix comments, mostly by moving them to where our programming style
wants them.
178 lines
5.7 KiB
Mathematica
178 lines
5.7 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1995-1998, 2006 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.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Main authors: bromage, Marnix Klooster <marnix@worldonline.nl>
|
|
%
|
|
% Something very similar to the standard diff utility. Sort of. :-)
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module diff.
|
|
|
|
:- interface.
|
|
:- import_module io.
|
|
|
|
:- pred main(io::di, io::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module diff_out.
|
|
:- import_module file.
|
|
:- import_module filter.
|
|
:- import_module globals.
|
|
:- import_module match.
|
|
:- import_module myers.
|
|
:- import_module options.
|
|
|
|
:- import_module getopt.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
main(!IO) :-
|
|
io.command_line_arguments(Args0, !IO),
|
|
options.get_option_ops(OptionOps),
|
|
getopt.process_options(OptionOps, Args0, Args, Result0),
|
|
postprocess_options(Result0, Result, !IO),
|
|
(
|
|
Result = yes(Msg),
|
|
usage_error(Msg, !IO)
|
|
;
|
|
Result = no,
|
|
globals.io_get_output_style(OutputStyle, !IO),
|
|
( if OutputStyle = help_only then
|
|
usage(!IO)
|
|
else if OutputStyle = version_only then
|
|
version(!IO)
|
|
else
|
|
main_2(Args, !IO)
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred usage_error(string::in, io::di, io::uo) is det.
|
|
|
|
usage_error(Msg, !IO) :-
|
|
io.progname_base("diff", ProgName, !IO),
|
|
io.stderr_stream(StdErr, !IO),
|
|
io.write_strings(StdErr, [ProgName, ": ", Msg, "\n"], !IO),
|
|
io.set_exit_status(1, !IO),
|
|
usage(!IO).
|
|
|
|
:- pred usage_io_error(io.error::in, io::di, io::uo) is det.
|
|
|
|
usage_io_error(Error, !IO) :-
|
|
io.error_message(Error, Msg),
|
|
usage_error(Msg, !IO).
|
|
|
|
:- pred usage(io::di, io::uo) is det.
|
|
|
|
usage(!IO) :-
|
|
io.write_string("Usage: diff [options] from-file to-file\n\n", !IO),
|
|
options_help(!IO).
|
|
|
|
:- pred version(io::di, io::uo) is det.
|
|
|
|
version(!IO) :-
|
|
io.write_string("diff - Mercury diff version 0.4\n", !IO).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% main_2 analyses the command-line arguments which are not options
|
|
% and calls diff.do_diff.
|
|
%
|
|
:- pred main_2(list(string)::in, io::di, io::uo) is det.
|
|
|
|
main_2(Args, !IO) :-
|
|
(
|
|
Args = [],
|
|
usage_error("missing operand", !IO)
|
|
;
|
|
Args = [_],
|
|
usage_error("missing operand", !IO)
|
|
;
|
|
Args = [_, _, _ | _],
|
|
usage_error("too many operands", !IO)
|
|
;
|
|
Args = [Fname1, Fname2],
|
|
( if Fname1 = Fname2 then
|
|
% Not sure why anyone would want to diff two
|
|
% files with the same name, but just in case ...
|
|
( if Fname1 = "-" then
|
|
file.read_input(Fname1, Contents1, !IO),
|
|
Contents1 = Contents2
|
|
else
|
|
file.read_file(Fname1, Contents1, !IO),
|
|
Contents1 = Contents2
|
|
)
|
|
else
|
|
% If either file is "-", simply use standard input.
|
|
% (Note: Both can't be "-" since that was dealt with
|
|
% in the previous case.)
|
|
( if Fname1 = "-" then
|
|
file.read_input(Fname1, Contents1, !IO),
|
|
file.read_file(Fname2, Contents2, !IO)
|
|
else if Fname2 = "-" then
|
|
file.read_file(Fname1, Contents1, !IO),
|
|
file.read_input(Fname2, Contents2, !IO)
|
|
else
|
|
% Otherwise read the files normally.
|
|
file.read_file(Fname1, Contents1, !IO),
|
|
file.read_file(Fname2, Contents2, !IO)
|
|
)
|
|
),
|
|
% Now do the diff.
|
|
(
|
|
Contents1 = ok(File1),
|
|
(
|
|
Contents2 = ok(File2),
|
|
diff.do_diff(File1, File2, !IO)
|
|
;
|
|
Contents2 = error(Msg),
|
|
usage_io_error(Msg, !IO)
|
|
)
|
|
;
|
|
Contents1 = error(Msg),
|
|
usage_io_error(Msg, !IO)
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% do_diff takes the files plus all the command line options
|
|
% and determines what to do with them.
|
|
%
|
|
:- pred do_diff(file::in, file::in, io::di, io::uo) is det.
|
|
|
|
do_diff(File1, File2, !IO) :-
|
|
% There are four passes:
|
|
%
|
|
% - build_matches determines which lines from the input files match
|
|
% (using the appropriate command-line options).
|
|
% - diff_by_myers takes the matches produced and computes a diff between
|
|
% them.
|
|
% - filter_diff analyses the diff, filtering out any edits which the user
|
|
% said that they didn't want to see (using the appropriate command-line
|
|
% options).
|
|
% - display_diff outputs the diff in whatever output format the user chose.
|
|
%
|
|
build_matches(File1, File2, FileX, FileY, !IO),
|
|
diff_by_myers(FileX, FileY, Diff0, !IO),
|
|
filter_diff(File1, File2, Diff0, Diff, !IO),
|
|
display_diff(File1, File2, Diff, !IO).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module diff.
|
|
%-----------------------------------------------------------------------------%
|