mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-16 06:14:59 +00:00
Estimated hours taken: 2 Branches: main Move the intermodule analysis framework into the `compiler' directory, in preparation for making it specific to the Mercury compiler, rather than having it generic in case some fictional being might want to use it with a .NET compiler one day. This will make it easier to use and modify. compiler/analysis.file.m: compiler/analysis.m: Copy these files from the `analysis' directory. compiler/top_level.m: Include analysis.m as a new package. compiler/Mercury.options: Add a bug workaround line from analysis/Mercury.options. analysis/Mercury.options: analysis/Mmakefile: analysis/analysis.file.m: analysis/analysis.m: analysis/mer_analysis.m: Replace the contents of these files with comments that the analysis framework is now in the `compiler' directory. We don't actually delete them so their histories remain easily accessible. analysis/README: Mention that the code has been moved. compiler/notes/compiler_design.html: compiler/notes/overall_design.html: Update documentation. Mmake.workspace: Mmakefile: configure.in: compiler/.mgnuc_copts: compiler/COMP_FLAGS.in: compiler/Mmakefile: deep_profiler/.mgnuc_copts: scripts/Mmake.vars.in: scripts/c2init.in: scripts/mercury_config.in: scripts/prepare_tmp_dir_fixed_part.in: tools/binary: tools/binary_step: tools/bootcheck: tools/lmc.in: tools/make_arena: compiler/notes/coding_standards.html: Remove references to the `analysis' directory and `libmer_analysis'.
538 lines
14 KiB
HTML
538 lines
14 KiB
HTML
|
|
<html>
|
|
<head>
|
|
<title>
|
|
Mercury Coding Standard for the Mercury Project
|
|
</title>
|
|
</head>
|
|
|
|
<body
|
|
bgcolor="#ffffff"
|
|
text="#000000"
|
|
>
|
|
|
|
<hr>
|
|
<!-------------------------->
|
|
|
|
<h1>
|
|
Mercury Coding Standard for the Mercury Project</h1>
|
|
<hr>
|
|
|
|
<!-------------------------->
|
|
|
|
<h2> Documentation </h2>
|
|
|
|
<p>
|
|
|
|
Each module should contain header comments
|
|
which state the module's name, main author(s), and purpose,
|
|
and give an overview of what the module does,
|
|
what are the major algorithms and data structures it uses, etc.
|
|
|
|
<p>
|
|
|
|
Everything that is exported from a module should have sufficient documentation
|
|
that it can be understood without reference
|
|
to the module's implementation section.
|
|
|
|
<p>
|
|
|
|
Each procedure that is implemented using foreign code
|
|
should have sufficient documentation about its interface
|
|
that it can be implemented just by referring to that documentation,
|
|
without reference to the module's implementation section.
|
|
|
|
<p>
|
|
|
|
Each predicate other than trivial access predicates
|
|
should have a short comment describing what the predicate is supposed to do,
|
|
and what the meaning of the arguments is.
|
|
Ideally this description should also note any conditions
|
|
under which the predicate can fail or throw an exception.
|
|
|
|
<p>
|
|
|
|
There should be a comment for each field of a structure saying
|
|
what the field represents.
|
|
|
|
<p>
|
|
|
|
Any user-visible changes such as new compiler options or new features
|
|
should be documented in appropriate section of the Mercury documentation
|
|
(usually the Mercury User's Guide and/or the Mercury Reference Manual).
|
|
Any major new features should be documented in the NEWS file,
|
|
as should even small changes to the library interface,
|
|
or anything else that might cause anyone's existing code to break.
|
|
|
|
<p>
|
|
|
|
Any new compiler modules or other major design changes
|
|
should be documented in `compiler/notes/compiler_design.html'.
|
|
|
|
<p>
|
|
|
|
Any feature which is incompletely implemented
|
|
should be mentioned in `compiler/notes/work_in_progress.html'.
|
|
|
|
<h2> Naming </h2>
|
|
|
|
<p>
|
|
|
|
Variables should always be given meaningful names,
|
|
unless they are irrelevant to the code in question.
|
|
For example, it is OK to use single-character names
|
|
in an access predicate which just sets a single field of a structure,
|
|
such as
|
|
|
|
<pre>
|
|
|
|
bar_set_foo(Foo, bar(A, B, C, _, E), bar(A, B, C, Foo, E)).
|
|
|
|
</pre>
|
|
|
|
Variables which represent different states or different versions
|
|
of the same entity should be named Foo0, Foo1, Foo2, ..., Foo.
|
|
|
|
<p>
|
|
|
|
Predicates which get or set a field of a structure or ADT
|
|
should be named bar_get_foo and bar_set_foo respectively,
|
|
where bar is the name of the structure or ADT and foo is the name of the field.
|
|
|
|
<h2> Coding </h2>
|
|
|
|
<p>
|
|
|
|
Your code should make as much reuse of existing code as possible.
|
|
"cut-and-paste" style reuse is highly discouraged.
|
|
|
|
<p>
|
|
|
|
Your code should be efficient.
|
|
Performance is a quite serious issue for the Mercury compiler.
|
|
|
|
<p>
|
|
|
|
No fixed limits please!
|
|
(If you really must have a fixed limit,
|
|
include detailed documentation explaining why it was so hard to avoid.)
|
|
|
|
<p>
|
|
|
|
Only use DCG notation for parsing, not for threading implicit arguments.
|
|
|
|
Use state variables for threading the IO state etc.
|
|
The conventional IO state variable name is <code>!IO</code>.
|
|
|
|
<h2> Error handling </h2>
|
|
|
|
<p>
|
|
|
|
Code should check for both erroneous inputs from the user
|
|
and also invalid data being passed from other parts of the Mercury compiler.
|
|
You should also always check to make sure that
|
|
the routines that you call have succeed;
|
|
make sure you don't silently ignore failures.
|
|
(This last point almost goes without saying in Mercury,
|
|
but is particularly important to bear in mind
|
|
if you are writing any C code or shell scripts,
|
|
or if you are interfacing with the OS.)
|
|
|
|
<p>
|
|
|
|
Calls to error/1 should always indicate an internal software error,
|
|
not merely incorrect inputs from the user,
|
|
or failure of some library routine or system call.
|
|
In the compiler, use unexpected/2 or sorry/2 from compiler_util.m
|
|
rather than error/1. Use expect/3 from compiler_util rather than
|
|
require/2.
|
|
|
|
<p>
|
|
|
|
Error messages should follow a consistent format.
|
|
For compiler error messages, each line should start
|
|
with the source file name and line number in "%s:%03d: " format.
|
|
Compiler error messages should be complete sentences;
|
|
they should start with a capital letter and end in a full stop.
|
|
For error messages that are spread over more than one line
|
|
(as are most of them),
|
|
the second and subsequent lines should be indented two spaces.
|
|
If the `--verbose-errors' option was set,
|
|
you should print out additional text explaining in detail
|
|
what the error message means and what the likely causes are.
|
|
The preferred method of printing error messages
|
|
is via the predicates in error_util.m;
|
|
use prog_out__write_context and io__write_strings
|
|
only if there is no way to add the capability you require to error_util.m.
|
|
|
|
<p>
|
|
|
|
Error messages from the runtime system should begin with the text
|
|
"Mercury Runtime:", preferably by using the MR_fatal_error() routine.
|
|
|
|
<p>
|
|
|
|
If a system call or C library function that sets errno fails,
|
|
the error message should be printed with perror()
|
|
or should contain strerror(errno).
|
|
If it was a function manipulating some file,
|
|
the error message should include the filename.
|
|
|
|
<h2> Layout </h2>
|
|
|
|
<p>
|
|
|
|
Each module should be indented consistently,
|
|
with either 4 or 8 spaces per level of indentation.
|
|
The indentation should be consistently done,
|
|
either only with tabs or only with spaces.
|
|
A tab character should always mean 8 spaces;
|
|
if a module is indented using 4 spaces per level of indentation,
|
|
this should be indicated by four spaces,
|
|
not by a tab with tab stops set to 4.
|
|
|
|
<p>
|
|
|
|
Files that use 8 spaces per level of indentation
|
|
don't need any special setup.
|
|
Files that use 4 spaces per level of indentation
|
|
should have something like this at the top,
|
|
even before the copyright line:
|
|
<pre>
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
</pre>
|
|
|
|
<p>
|
|
|
|
No line should extend beyond 79 characters.
|
|
The reason we don't allow 80 character lines is that
|
|
these lines wrap around in diffs,
|
|
since diff adds an extra character at the start of each line.
|
|
|
|
<p>
|
|
|
|
Since "empty" lines that have spaces or tabs on them
|
|
prevent the proper functioning of paragraph-oriented commands in vi,
|
|
lines shouldn't have trailing white space.
|
|
They can be removed with a vi macro such as the following.
|
|
(Each pair of square brackets contains a space and a tab.)
|
|
|
|
<pre>
|
|
map ;x :g/[ ][ ]*$/s///^M
|
|
</pre>
|
|
|
|
<p>
|
|
|
|
String literals that don't fit on a single line should be split
|
|
by writing them as two or more strings concatenated using the "++" operator;
|
|
the compiler will evaluate this at compile time,
|
|
if --optimize-constant-propagation is enabled (i.e. at -O3 or higher).
|
|
|
|
<p>
|
|
|
|
Predicates that have only one mode should use predmode declarations
|
|
rather than having a separate mode declaration.
|
|
|
|
<p>
|
|
If-then-elses should always be parenthesized,
|
|
except that an if-then-else that occurs as the else
|
|
part of another if-then-else doesn't need to be parenthesized.
|
|
The condition of an if-then-else can either be on the same
|
|
line as the opening parenthesis and the `->',
|
|
|
|
<pre>
|
|
|
|
( test1 ->
|
|
goal1
|
|
; test2 ->
|
|
goal2
|
|
;
|
|
goal
|
|
)
|
|
|
|
</pre>
|
|
|
|
or, if the test is complicated, it can be on a line of its own:
|
|
|
|
<pre>
|
|
|
|
(
|
|
very_long_test_that_does_not_fit_on_one_line(VeryLongArgument1,
|
|
VeryLongArgument2)
|
|
->
|
|
goal1
|
|
;
|
|
test2a,
|
|
test2b,
|
|
->
|
|
goal2
|
|
;
|
|
test3 % would fit one one line, but separate for consistency
|
|
->
|
|
goal3
|
|
;
|
|
goal
|
|
).
|
|
|
|
</pre>
|
|
|
|
<p>
|
|
|
|
Disjunctions should always be parenthesized.
|
|
The semicolon of a disjunction should never be at the
|
|
end of a line -- put it at the start of the next line instead.
|
|
|
|
<p>
|
|
|
|
Predicates and functions implemented via foreign code should be formatted
|
|
like this:
|
|
|
|
<pre>
|
|
:- pragma foreign_proc("C",
|
|
int__to_float(IntVal::in, FloatVal::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
FloatVal = IntVal;
|
|
").
|
|
</pre>
|
|
|
|
The predicate name and arguments should be on a line on their own,
|
|
as should the list of annotations.
|
|
The foreign code should also be on lines of its own;
|
|
it shouldn't share lines with the double quote marks surrounding it.
|
|
|
|
<p>
|
|
|
|
Type definitions should be formatted in one of the following styles:
|
|
|
|
<pre>
|
|
:- type my_type
|
|
---> my_type(
|
|
some_other_type % comment explaining it
|
|
).
|
|
|
|
:- type my_struct --->
|
|
my_struct(
|
|
field1, % comment explaining it
|
|
...
|
|
).
|
|
|
|
:- type some_other_type == int.
|
|
|
|
:- type foo
|
|
---> bar(
|
|
int, % comment explaining it
|
|
float % comment explaining it
|
|
)
|
|
; baz
|
|
; quux.
|
|
|
|
</pre>
|
|
|
|
<p>
|
|
|
|
If an individual clause is long, it should be broken into sections,
|
|
and each section should have a "block comment" describing what it does;
|
|
blank lines should be used to show the separation into sections.
|
|
Comments should precede the code to which they apply, rather than following it.
|
|
|
|
<pre>
|
|
%
|
|
% This is a block comment; it applies to the code in the next
|
|
% section (up to the next blank line).
|
|
%
|
|
blah,
|
|
blah,
|
|
blahblah,
|
|
blah,
|
|
</pre>
|
|
|
|
If a particular line or two needs explanation, a "line" comment
|
|
|
|
<pre>
|
|
% This is a "line" comment; it applies to the next line or two
|
|
% of code
|
|
blahblah
|
|
</pre>
|
|
|
|
or an "inline" comment
|
|
|
|
<pre>
|
|
blahblah % This is an "inline" comment
|
|
</pre>
|
|
|
|
should be used.
|
|
|
|
<h2> Structuring </h2>
|
|
|
|
Code should generally be arranged so that
|
|
procedures (or types, etc.) are listed in top-down order, not bottom-up.
|
|
|
|
<p>
|
|
|
|
Code should be grouped into bunches of related predicates, functions, etc.,
|
|
and sections of code that are conceptually separate
|
|
should be separated with dashed lines:
|
|
|
|
<pre>
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
</pre>
|
|
|
|
Ideally such sections should be identified
|
|
by "section heading" comments identifying the contents of the section,
|
|
optionally followed by a more detailed description.
|
|
These should be laid out like this:
|
|
|
|
<pre>
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Section title
|
|
%
|
|
|
|
% Detailed description of the contents of the section and/or
|
|
% general comments about the contents of the section.
|
|
% This part may go one for several lines.
|
|
%
|
|
% It can even contain several paragraphs.
|
|
|
|
The actual code starts here.
|
|
|
|
</pre>
|
|
|
|
For example
|
|
|
|
<pre>
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Exception handling
|
|
%
|
|
|
|
% This section contains all the code that deals with throwing or catching
|
|
% exceptions, including saving and restoring the virtual machine registers
|
|
% if necessary.
|
|
%
|
|
% Note that we need to take care to ensure that this code is thread-safe!
|
|
|
|
:- type foo ---> ...
|
|
|
|
</pre>
|
|
|
|
Double-dashed lines, i.e.
|
|
|
|
<pre>
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
</pre>
|
|
|
|
can also be used to indicate divisions into major sections.
|
|
Note that these dividing lines should not exceed the 79 character limit
|
|
(see above).
|
|
|
|
<h2> Module imports </h2>
|
|
|
|
Each group of :- import_module items should list only one module per line,
|
|
since this makes it much easier to read diffs
|
|
that change the set of imported modules.
|
|
In the compiler, when e.g. an interface section imports modules
|
|
from both the compiler and the standard library,
|
|
there should be two groups of imports,
|
|
the imports from the compiler first and then the ones from the library.
|
|
For the purposes of this rule,
|
|
consider the modules of mdbcomp to belong to the compiler.
|
|
|
|
<p>
|
|
|
|
Each group of import_module items should be sorted,
|
|
since this makes it easier to detect duplicate imports and missing imports.
|
|
It also groups together the imported modules from the same package.
|
|
There should be no blank lines between
|
|
the imports of modules from different packages,
|
|
since this makes it harder to resort the group with a single editor command.
|
|
|
|
<h2> Standard library predicates </h2>
|
|
|
|
The descriptive comment for any predicate or function
|
|
that occurs in the interface of a standard library module
|
|
must be positioned above the predicate/function declaration.
|
|
It should be formatted like the following example:
|
|
|
|
<pre>
|
|
|
|
% Description of predicate foo.
|
|
%
|
|
:- pred foo(...
|
|
:- mode foo(...
|
|
</pre>
|
|
|
|
A group of related predicate, mode and function declarations
|
|
may be grouped together under a single description
|
|
provided that it is formatted as above.
|
|
If there is a function declaration in such a grouping
|
|
then it should be listed before the others.
|
|
|
|
For example:
|
|
|
|
<pre>
|
|
|
|
% Insert a new key and corresponding value into a map.
|
|
% Fail if the key already exists.
|
|
%
|
|
:- func map.insert(map(K, V), K, V) = map(K, V).
|
|
:- pred map.insert(map(K, V)::in, K::in, V::in, map(K, V)::out) is det.
|
|
|
|
</pre>
|
|
|
|
The reason for using this particular style is that
|
|
the reference manual for the standard library
|
|
is automatically generated from the module interfaces,
|
|
and we want to maintain a uniform appearance as much as is possible.
|
|
|
|
<h2> Testing </h2>
|
|
|
|
<p>
|
|
|
|
Every change should be tested before being committed.
|
|
The level of testing required depends on the nature of the change.
|
|
If this change fixes an existing bug,
|
|
and is unlikely to introduce any new bugs,
|
|
then just compiling it and running some tests by hand is sufficient.
|
|
If the change might break the compiler,
|
|
you should run a bootstrap check (using the `bootcheck' script)
|
|
before committing.
|
|
If the change means that old versions of the compiler
|
|
will not be able to compile the new version of the compiler,
|
|
you must notify all the other Mercury developers.
|
|
|
|
<p>
|
|
|
|
In addition to testing before a change is committed,
|
|
you need to make sure that the code will not get broken in the future
|
|
by adding tests to the test suite.
|
|
Every time you add a new feature,
|
|
you should add some test cases for that new feature to the test suite.
|
|
Every time you fix a bug, you should add a regression test to the test suite.
|
|
|
|
<h2> Committing changes </h2>
|
|
|
|
<p>
|
|
|
|
Before committing a change, you should get someone else to review your changes.
|
|
|
|
<p>
|
|
|
|
The file <a href="reviews.html">compiler/notes/reviews.html</a>
|
|
contains more information on review policy.
|
|
|
|
<hr>
|
|
<!-------------------------->
|
|
|
|
Last update was $Date: 2008-02-20 03:09:59 $ by $Author: wangp $@cs.mu.oz.au. <br>
|
|
</body>
|
|
</html>
|