1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
|
-*- mode: text; coding: utf-8 -*-
---------------------------------
CLISP sources coding style
==========================
Lisp developers are individuals, and every individual tends to have his
own preferred coding style. Nevertheless, on projects like CLISP where
several people come together to hack the same source, it is necessary to
adhere to a common coding style, so that other developers enjoy reading
your code.
A common coding style is a compromise for all participants, and it is also
an exercise in tolerance. When I contribute code to Linux, I adhere to the
Linux coding style (/usr/src/linux/Documentation/CodingStyle - very
recommended reading). When I contribute to GCC, I follow the GNU coding style
("info standards"), although I get nauseous when I look at the result.
When I write for XFree86, I follow their style; it's a somewhat neutral one.
As a general rule, don't reformat entire files other people have written;
that will make the other developers spit. Instead, adhere to the particular
file's predominant style (even if it is not the same as the general style
used in the project).
A lot of good advice about naming conventions and placement and contents of
comments can be found in other places; therefore I skip these issues here.
I'll mention only one rule about
Special variables
-----------------
All variables which are subject to 'defvar', 'defparameter' or 'declare
special' (even if only locally in a function) must be surrounded by asterisks.
I had once in a program a special variable called 'line', and it caused me
an hour of debugging time at least. I will not make this mistake again...
Tabs
----
In CLISP source, except for Makefiles and ChangeLog files, we don't use tabs.
This is because they have no functional advantage, and make "diff" output
harder to read and understand. And also, because some editors on Windows have
a default tab width of 4, whereas on Unix, the common consensus is a tab width
of 8. If you are using Emacs and want to contribute to CLISP, the best way to
ensure that you don't send us tabs by mistake is to add the following lines
to your <$HOME/.emacs> file:
;; Tabs are anachronistic.
(setq-default indent-tabs-mode nil)
Trailing whitespace
-------------------
Trailing whitespace pollutes diffs and should be avoided.
Emacs will highlight it if you do
(setq-default show-trailing-whitespace t)
and remove it if you do
(add-hook 'write-file-functions 'delete-trailing-whitespace)
Lisp indentation and parentheses placement
------------------------------------------
We try to keep things in 79 columns, because that's the default width of
Emacs windows. We urge you to use the Emacs 21 lisp-mode to indent
your lisp code, see file <clisp/emacs/clisp-indent.el>.
VIM users should put <clisp/emacs/lisp.vim> into <$HOME/.vim/after/syntax/>.
Parentheses should be set in the mainstream style (used in CLtL1, CLtL2
and the ANSI CL spec), with the closing parens at the end of the last
line, like this:
(defun get-funname-symbol (funname)
(if (atom funname)
funname
(get-setf-symbol (second funname))))
Elements of a list are indented by 2 spaces relative to the list, except
- for arguments of function calls, which often can be aligned to the first
argument,
- for elements of COND-clauses, which are usually indented by 1 space.
Some of the CLISP code still uses the "Bruno style". Its characteristic
is that closing parentheses are located either on the same line as the
corresponding opening paren, or on extra lines containing only closing
parentheses:
(defun get-funname-symbol (funname)
(if (atom funname)
funname
(get-setf-symbol (second funname))
) )
Please avoid adding code in this style.
C style
-------
Most of the C code of CLISP is stored in files with extension '.d'. It _is_
C code, but the file will be preprocessed a bit.
A comment until end of line is introduced by '# '. Other '#' signs, not
followed by a space, have the usual C meaning. Please avoid adding new
comments in this style, use the normal /* C comments */.
Preprocessor commands can start at any column, not necessarily at the first
column of a line.
These 'var' symbols that you encounter in every function introduce variable
declarations. We use one variable per declaration; the C syntax rules make
declarations of multiple variables on the same line hard to read and hard
to edit. 'var' is a preprocessor symbol which expands to nothing.
Writing 'var' not only makes it easier for a human reader to understand
the code; it also allows you to mix declarations and statements freely,
without the need for additional braces (see utils/varbrace.c).
C indentation
-------------
The general style is similar to K&R style or Linux kernel style, with a
tab width of 2 spaces. A typical 'if' or 'while' statement looks like this:
while (consp(keylistr)) {
if (eq(item,Car(keylistr)))
goto found;
keylistr = Cdr(keylistr);
}
When statements have to span lines, split them before the operator; this
is what the GNU standards recommend:
if (mconsp(Car(alist)) && simple_string_p(Car(Car(alist)))
&& string_equal(line,Car(Car(alist)))) {
Use <clisp/emacs/d-mode.el> to make Emacs indent and fontify the *.d files.
VIM users should put <clisp/emacs/d.vim> into <$HOME/.vim/syntax/>.
Comments
--------
Comments in front of a function definition describe the function's
specification, i.e. all a caller of the function needs to know.
Describe the function's behavior in a sentence with implicit subject
"this function", not as a command.
For algorithmic functions with non obvious complexity, the (worst-case)
complexity (= running time) is part of the function's specification.
Please follow the common format (UP stands for "Unterprogram"):
/* UP: brief description
> 1st input parameter
> 2nd input parameter
< return value */
Do not forget to list global variables accessed and modified, including STACK.
Comments about the inner working of a function belong inside the function.
Example:
;; (isqrt x) returns the largest integer <= x^(1/2).
;; x must be an integer >= 0.
;; Complexity: O(M(n) log n) if x has n digits.
(defun isqrt (x)
;; Use Newton's algorithm.
(let ((y (ash 1 (ash (integer-length x) -1))))
(loop (when (= y (setq y (ash (+ y (floor x y)) -1))) (return)))
y))
Comments about a variable belong in front of the variable.
German comments
---------------
When CLISP was written, it was not anticipated to have wide distribution.
We are sorry about the German comments. If you are a native German
speaker, you are welcome to faithfully translate them to English.
If not, please leave them alone and wait for someone to translate them
to English. Many files have been already translated by Stefan Kain
and Reini Urban; you may ask them (on <clisp-list>) to translate
the file you need.
German variable and function names are probably even more disturbing
than the comments, and much harder to handle. Use babelfish.
Remember: "fehler" == "error"; "zustand" == "state"
(this is where the 'z' suffix often comes from).
Please avoid "clever" tricks with Unicode in comments.
E.g., using #\SUBSET_OF_OR_EQUAL_TO (Unicode #x2286) instead of the
plain words "subclass of" or #\FULLWIDTH_SOLIDUS (Unicode #xff0f) &
#\FULLWIDTH_ASTERISK (Unicode #xff0a) to emulate nested C comments
breaks compilation in some language environments:
$ LANG=ja_JP.eucJP make clisp.h
...
../src/lispbibl.d:1028: error: stray '\217' in program
...
Remember, ASCII rules!
Variable names
--------------
Use descriptive variable names. Don't use names like "ll", "tem", "stri",
"comp"; if you want to participate in an obfuscated Lisp code contest, you
may, but don't put the resulting code into CLISP.
Variable initializations
------------------------
If you want to access a variable's value, first initialize it.
In Lisp, to initialize a list to be empty, write
(let ((l '()))
not
(let ((l nil)) ; this doesn't tell whether l is a list, boolean etc.
or
(let (l) ; worse - looks like an uninitialized variable.
In Lisp, if keyword arguments have a non-obvious default, write it down:
(defun f (sequence &key (start 0) (end nil))
not
(defun f (sequence &key (start 0) end)
In C, to initialize a static variable to 0, write
static int flag = 0;
not
static int flag;
To many people this advice seems obvious; I am sorry that I have to repeat
it here.
Macros and ABI
--------------
Macro expanders must not perform side effects; only the execution of the
macro expansion may perform side effects.
If a macro expansion needs to perform complex actions, try to move as much
of it as possible into functions that are then called from the macro
expansion. In particular, don't put literal strings into macro expansions.
This helps 1. keeping the size of compiled .fas files small, 2. reducing
the probability that O(version) needs to be bumped when you change the
effect of the macro.
Macro expansions can refer to documented symbols and functions from public
packages (COMMON-LISP, CLOS, EXT, FFI), as well as undocumented, unexported
functions. Both kinds of functions, together with their calling conventions,
form the ABI (= Application Binary Interface) of .fas files. When the ABI
changes, O(version) needs to be bumped, thus declaring previously compiled
.fas files as invalid. The second kind of function should be marked as
"; ABI" in the *.lisp source code or "/* ABI */" in constsym.d, to make the
developers aware.
Newline Output
--------------
All output by the system must start with a fresh-line and must be terminated
with an elastic newline. See doc/Newline-Convention.txt for the rationale.
Change Management
-----------------
Even though CLISP is kept under the CVS, all functional changes require
a ChangeLog entry. If there is no ChangeLog file in the current
directory, the entry goes into <clisp/src/ChangeLog>; you should refer
to the recent entries there for good examples of ChangeLog entries.
One should always use a high-level overview of the change (1-2 lines)
in the beginning of the entry, and use it as the CVS log message.
The file name should include a path relative to one of 3 "roots":
clisp/, clisp/src/ or clisp/modules/. E.g., <clisp/utils/clispload.lsp>
is recorded as <utils/clispload.lsp>, <clisp/modules/pcre/cpcre.c> as
<pcre/cpcre.c> and <clisp/src/lispbibl.d> as <lispbibl.d>.
The main requirement is that the record must be unambiguous.
We highly recommend using Emacs change-log mode with font-lock, as the
highlighting will give many valuable suggestions about the right format.
Use M-x add-change-log-entry RET to add an entry, and some information
will be put there for you automagically.
Never mix functional changes with formatting/translation changes!
If you are fixing indentation or translating comments, make a separate
CVS commit without a ChangeLog entry, then check in your functional
changes and add the ChangeLog entry.
You are encouraged to add a test case to a file in <clisp/tests/>
whenever you add a feature or fix a bug, the more tests, the better.
One requirement must be satisfied after every CVS commit:
$ cvs up -C; ./configure --cbc build-dir
must pass all tests, the old and the new alike.
Documentation and comment changes do not need a ChangeLog entry.
Do not abbreviate function, variable and file names
(e.g., using regular expressions).
All functionality should be documented.
When adding a new symbol, document it in the Implementation Notes and
add an appropriate mapping from the symbol to its XML ID in the impnotes
to the file doc/Symbol-Table.text (in the order of the impnotes' flow).
Source File Encoding
--------------------
All files are to be encoded with utf-8 and Unix line endings (LF, ASCII 10).
Please do make sure that you do not break non-ASCII characters
and do not replace line endings with the dos CR/LF.
|