mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 09:53:36 +00:00
One option, --warn-non-contiguous-decls, generates warnings if the
mode declarations of a predicate or function aren't in a contiguous block
immediately following the pred or func declaration. Since this is a rare
kind of "style error", this option is enabled by default.
Two options, --warn-inconsistent-pred-order-clauses and
--warn-inconsistent-pred-order-foreign-procs, warn about inconsistencies
between (a) the order in which predicates (and functions) are declared,
and (b) the order in which they are defined. The two options differ in
their scope. The latter applies to all predicates and functions defined
in the module, while the former applies only to those whose definitions
include Mercury clauses.
Since an exported predicate or function may need nonexported auxiliary
predicates and/or functions, imposing a single order the declarations and
definitions of *all* the predicates and functions in a module is not a good
idea. Instead, both options divide the predicates and functions defined
in a module two groups, the exported and the nonexported, and expect
a consistent order only within each group.
The result is output that looks like this:
time.m:021: Warning: the order of the declarations and definitions of the
time.m:021: exported predicates is inconsistent, as shown by this diff:
time.m:021:
time.m:021: --- declaration order
time.m:021: +++ definition order
time.m:021: @@ -1,7 +1,7 @@
time.m:021: predicate `clock'/3
time.m:021: -predicate `time'/3
time.m:021: predicate `times'/4
time.m:021: function `clk_tck'/0
time.m:021: +predicate `time'/3
time.m:021: function `difftime'/2
time.m:021: predicate `localtime'/4
time.m:021: function `localtime'/1
compiler/options.m:
doc/user_guide.texi:
Add the new options.
compiler/style_checks.m:
A new module that generates the new warnings if warranted.
compiler/check_hlds.m:
compiler/notes/compiler_design.html:
Include and document the new module.
compiler/mercury_compile_front_end.m:
Invoke the new module if any of the three new options is set.
compiler/hlds_pred.m:
Record the item number of every predicate, function, and mode declaration
in the module being compiled. We need this for information for the
new warnings.
compiler/hlds_module.m:
Record the context of the module declaration. We use this context
for warnings about inconsistent order, since there isn't a better one.
compiler/hlds_clauses.m:
Add a mechanism to retrieve the item numbers of a set of clauses
even if they are contiguous.
Document some old data types.
compiler/error_util.m:
Add a new phase for style checks.
compiler/accumulator.m:
compiler/add_class.m:
compiler/add_mutable_aux_preds.m:
compiler/add_pragma_tabling.m:
compiler/add_pred.m:
compiler/add_solver.m:
compiler/add_special_pred.m:
compiler/check_typeclass.m:
compiler/clause_to_proc.m:
compiler/from_ground_term_util.m:
compiler/lambda.m:
compiler/make_hlds.m:
compiler/make_hlds_passes.m:
compiler/mercury_compile.m:
compiler/par_loop_control.m:
compiler/polymorphism.m:
compiler/stm_expand.m:
compiler/table_gen.m:
compiler/unify_proc.m:
Conform the changes to the HLDS above.
compiler/typecheck_errors.m:
Fix style of error messages.
library/array2d.m:
library/assoc_list.m:
library/benchmarking.m:
library/bit_buffer.write.m:
library/bool.m:
library/builtin.m:
library/construct.m:
library/cord.m:
library/counter.m:
library/float.m:
library/injection.m:
library/lazy.m:
library/lexer.m:
library/ops.m:
library/private_builtin.m:
library/profiling_builtin.m:
library/prolog.m:
library/queue.m:
library/rational.m:
library/require.m:
library/stack.m:
library/std_util.m:
library/store.m:
library/thread.semaphore.m:
library/tree234.m:
library/univ.m:
library/version_store.m:
Move declarations or definitions around to avoid some of the warnings
that we can now generate. (There are many more left.)
Make some minor style improvements in the process.
tests/warnings/inconsistent_pred_order.{m,exp}:
tests/warnings/non_contiguous_decls.{m,exp}:
New test cases to test the new options. They are both copies of
tests/benchmarks/queens.m, with intentionally-screwed-up style.
tests/warnings/Mmakefile:
Enable the new test cases.
tests/warnings/Mercury.options:
Specify the options being tested for the new test cases.
tests/benchmarks/queens.m:
Bring the style of this module up to date (before copying it).
tests/invalid/mode_decl_in_wrong_section.err_exp:
Expect the warnings we now generate.
277 lines
8.2 KiB
Mathematica
277 lines
8.2 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-1995, 1997-1999, 2003-2006, 2011 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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: queue.m.
|
|
% Main author: fjh.
|
|
% Stability: high.
|
|
%
|
|
% This file contains a `queue' ADT.
|
|
% A queue holds a sequence of values, and provides operations
|
|
% to insert values at the end of the queue (put) and remove them from
|
|
% the front of the queue (get).
|
|
%
|
|
% This implementation is in terms of a pair of lists.
|
|
% The put and get operations are amortized constant-time.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module queue.
|
|
:- interface.
|
|
|
|
:- import_module list.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type queue(T).
|
|
|
|
% `init(Queue)' is true iff `Queue' is an empty queue.
|
|
%
|
|
:- func init = queue(T).
|
|
:- pred init(queue(T)::out) is det.
|
|
|
|
% 'queue_equal(Q1, Q2)' is true iff Q1 and Q2 contain the same
|
|
% elements in the same order.
|
|
%
|
|
:- pred equal(queue(T)::in, queue(T)::in) is semidet.
|
|
|
|
% `is_empty(Queue)' is true iff `Queue' is an empty queue.
|
|
%
|
|
:- pred is_empty(queue(T)::in) is semidet.
|
|
|
|
% `is_full(Queue)' is intended to be true iff `Queue' is a queue
|
|
% whose capacity is exhausted. This implementation allows arbitrary-sized
|
|
% queues, so is_full always fails.
|
|
%
|
|
:- pred is_full(queue(T)::in) is semidet.
|
|
|
|
% `put(Elem, Queue0, Queue)' is true iff `Queue' is the queue
|
|
% which results from appending `Elem' onto the end of `Queue0'.
|
|
%
|
|
:- func put(queue(T), T) = queue(T).
|
|
:- pred put(T::in, queue(T)::in, queue(T)::out) is det.
|
|
|
|
% `put_list(Elems, Queue0, Queue)' is true iff `Queue' is the queue
|
|
% which results from inserting the items in the list `Elems' into `Queue0'.
|
|
%
|
|
:- func put_list(queue(T), list(T)) = queue(T).
|
|
:- pred put_list(list(T)::in, queue(T)::in, queue(T)::out) is det.
|
|
|
|
% `first(Queue, Elem)' is true iff `Queue' is a non-empty queue
|
|
% whose first element is `Elem'.
|
|
%
|
|
:- pred first(queue(T)::in, T::out) is semidet.
|
|
|
|
% `get(Elem, Queue0, Queue)' is true iff `Queue0' is a non-empty
|
|
% queue whose first element is `Elem', and `Queue' the queue which results
|
|
% from removing that element from the front of `Queue0'.
|
|
%
|
|
:- pred get(T::out, queue(T)::in, queue(T)::out) is semidet.
|
|
|
|
% `length(Queue, Length)' is true iff `Queue' is a queue
|
|
% containing `Length' elements.
|
|
%
|
|
:- func length(queue(T)) = int.
|
|
:- pred length(queue(T)::in, int::out) is det.
|
|
|
|
% `list_to_queue(List, Queue)' is true iff `Queue' is a queue
|
|
% containing the elements of List, with the first element of List at
|
|
% the head of the queue.
|
|
%
|
|
:- func list_to_queue(list(T)) = queue(T).
|
|
:- pred list_to_queue(list(T)::in, queue(T)::out) is det.
|
|
|
|
% A synonym for list_to_queue/1.
|
|
%
|
|
:- func from_list(list(T)) = queue(T).
|
|
|
|
% `to_list(Queue) = List' is the inverse of from_list/1.
|
|
%
|
|
:- func to_list(queue(T)) = list(T).
|
|
|
|
% `delete_all(Elem, Queue0, Queue)' is true iff `Queue' is the same
|
|
% queue as `Queue0' with all occurrences of `Elem' removed from it.
|
|
%
|
|
:- func delete_all(queue(T), T) = queue(T).
|
|
:- pred delete_all(T::in, queue(T)::in, queue(T)::out) is det.
|
|
|
|
% `put_on_front(Queue0, Elem) = Queue' pushes `Elem' on to
|
|
% the front of `Queue0', giving `Queue'.
|
|
%
|
|
:- func put_on_front(queue(T), T) = queue(T).
|
|
:- pred put_on_front(T::in, queue(T)::in, queue(T)::out) is det.
|
|
|
|
% `put_list_on_front(Queue0, Elems) = Queue' pushes `Elems'
|
|
% on to the front of `Queue0', giving `Queue' (the N'th member
|
|
% of `Elems' becomes the N'th member from the front of `Queue').
|
|
%
|
|
:- func put_list_on_front(queue(T), list(T)) = queue(T).
|
|
:- pred put_list_on_front(list(T)::in, queue(T)::in, queue(T)::out)
|
|
is det.
|
|
|
|
% `get_from_back(Elem, Queue0, Queue)' removes `Elem' from
|
|
% the back of `Queue0', giving `Queue'.
|
|
%
|
|
:- pred get_from_back(T::out, queue(T)::in, queue(T)::out) is semidet.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module int.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% This implementation is in terms of a pair of lists: the list of items
|
|
% in the queue is given by off_list ++ reverse(on_list). The reason for
|
|
% the names is that we generally get items off the off_list and put them
|
|
% on the on_list. We impose the extra constraint that the off_list field
|
|
% is empty if and only if the queue as a whole is empty.
|
|
%
|
|
:- type queue(T)
|
|
---> queue(
|
|
on_list :: list(T),
|
|
off_list :: list(T)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
init = Q :-
|
|
queue.init(Q).
|
|
|
|
init(queue([], [])).
|
|
|
|
equal(queue(OnA, OffA), queue(OnB, OffB)) :-
|
|
QA = OffA ++ list.reverse(OnA),
|
|
QB = OffB ++ list.reverse(OnB),
|
|
QA = QB.
|
|
|
|
is_empty(queue(_, [])).
|
|
|
|
is_full(_) :-
|
|
semidet_fail.
|
|
|
|
put(!.Q, T) = !:Q :-
|
|
queue.put(T, !Q).
|
|
|
|
put(Elem, queue(On0, Off0), queue(On, Off)) :-
|
|
(
|
|
Off0 = [],
|
|
On = On0,
|
|
Off = [Elem]
|
|
;
|
|
Off0 = [_ | _],
|
|
On = [Elem | On0],
|
|
Off = Off0
|
|
).
|
|
|
|
put_list(!.Q, Xs) = !:Q :-
|
|
queue.put_list(Xs, !Q).
|
|
|
|
put_list(Xs, queue(On0, Off0), queue(On, Off)) :-
|
|
(
|
|
Off0 = [],
|
|
On = On0,
|
|
Off = Xs
|
|
;
|
|
Off0 = [_ | _],
|
|
Off = Off0,
|
|
queue.put_list_2(Xs, On0, On)
|
|
).
|
|
|
|
:- pred queue.put_list_2(list(T)::in, list(T)::in, list(T)::out) is det.
|
|
|
|
put_list_2([], On, On).
|
|
put_list_2([X | Xs], On0, On) :-
|
|
queue.put_list_2(Xs, [X | On0], On).
|
|
|
|
first(queue(_, [Elem | _]), Elem).
|
|
|
|
get(Elem, queue(On0, [Elem | Off0]), queue(On, Off)) :-
|
|
(
|
|
Off0 = [],
|
|
list.reverse(On0, Off),
|
|
On = []
|
|
;
|
|
Off0 = [_ | _],
|
|
On = On0,
|
|
Off = Off0
|
|
).
|
|
|
|
length(Q) = N :-
|
|
queue.length(Q, N).
|
|
|
|
length(queue(On, Off), Length) :-
|
|
list.length(On, LengthOn),
|
|
list.length(Off, LengthOff),
|
|
Length = LengthOn + LengthOff.
|
|
|
|
list_to_queue(Xs) = Q :-
|
|
queue.list_to_queue(Xs, Q).
|
|
|
|
list_to_queue(List, queue([], List)).
|
|
|
|
from_list(List) = queue([], List).
|
|
|
|
to_list(queue(On, Off)) = Off ++ list.reverse(On).
|
|
|
|
delete_all(!.Q, T) = !:Q :-
|
|
queue.delete_all(T, !Q).
|
|
|
|
delete_all(Elem ,queue(On0, Off0), queue(On, Off)) :-
|
|
list.delete_all(On0, Elem, On1),
|
|
list.delete_all(Off0, Elem, Off1),
|
|
(
|
|
Off1 = [],
|
|
list.reverse(On1, Off),
|
|
On = []
|
|
;
|
|
Off1 = [_ | _],
|
|
On = On1,
|
|
Off = Off1
|
|
).
|
|
|
|
put_on_front(!.Queue, Elem) = !:Queue :-
|
|
queue.put_on_front(Elem, !Queue).
|
|
|
|
put_on_front(Elem, queue(On, Off), queue(On, [Elem | Off])).
|
|
|
|
put_list_on_front(!.Queue, Elems) = !:Queue :-
|
|
queue.put_list_on_front(Elems, !Queue).
|
|
|
|
put_list_on_front(Elems, queue(On, Off), queue(On, Elems ++ Off)).
|
|
|
|
get_from_back(Elem, queue(On0, Off0), queue(On, Off)) :-
|
|
(
|
|
% The On list is non-empty and the last element in the queue
|
|
% is the head of the On list.
|
|
On0 = [Elem | On],
|
|
Off = Off0
|
|
;
|
|
% The On list is empty.
|
|
On0 = [],
|
|
(
|
|
% The Off list contains a single element.
|
|
Off0 = [Elem],
|
|
On = [],
|
|
Off = []
|
|
;
|
|
% The Off list contains two or more elements. We split it in two
|
|
% and take the head of the new On list as Elem.
|
|
Off0 = [_, _ | _],
|
|
N = list.length(Off0),
|
|
list.split_list(N / 2, Off0, Off, RevOn),
|
|
[Elem | On] = list.reverse(RevOn)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module queue.
|
|
%---------------------------------------------------------------------------%
|