Эти рекомендации относятся только к оформлению исходных текстов Рефала-05, его рантайма и библиотеки встроенных функций, а также любых других программ, которые будут включаться в этот репозиторий (за исключением подключения других программ как подмодулей).
Рекомендации не навязываются как единственно верные при написании любых других программ на Рефале-05 или C.
Это рекомендации, т.е. применять их следует в соответствии со здравым смыслом. Например, длина строки не должна превышать 80 символов, но если написалась строчка длиной 82 символа и попытки её сократить или разбить на несколько ухудшают читабельность, то её лучше оставить такой «длинной».
Но злоупотреблять отступлениями от рекомендаций тоже нельзя.
*.md) следует использовать символы Юникода вместо их
суррогатов из ASCII: «, », ’, …, — и т.д. вместо ", ', ...,
-, --, ---. Неразрывный пробел, там где он должен быть (после коротких
союзов и предлогов, перед единицами измерения, частицами «бы» и «же» и т.д.),
должен быть всегда. Для правки документации следует использовать текстовые
редакторы, которые не портят неразрывные пробелы.Код не выравнивается по имени функции.
Хорошо:
+<FooBar
+ текст внутри идёт с отступом 2 пробела
+>
+void foo_bar(
+ int foo,
+ int bar
+) {
+x = bar_foo(
+ foo, bar
+);
Плохо:
-<FooBar текст выравнивается
- по имени функции>
-void foo_bar(int foo,
- int bar)
-{
-x = bar_foo(foo,
- bar);
temp, tmp, e.Temporary и т.д.
В остальных случаях имена типа temp или tmp являются недопустимыми.Func, Func1, Func2 следует давать имена вида Func
для «основной» функции и Func-Пояснение для вспомогательных. -Пояснение
должно отражать смысл этой вспомогательной функции, например,
ProcessFileNames-CheckInvalid. Часто, когда вспомогательная функция одна,
можно использовать суффикс -Aux.$EXTERN-объявлению должен предшествовать комментарий *$FROM,
содержащий имя файла (без расширения), в котором определены эти функции.
$EXTERN не следует включать имена функций,
импортируемых из разных файлов.$EXTERN-объявления пишутся в самом начале файла.$ENTRY Go, то её определение следует непосредственно
после всех $EXTERN объявлений.
CamelCase. Дефис используется для
отделения крупных смысловых частей, обычно для вспомогательных функций это имя
«главной» функции и пояснение предназначения вспомогательной.
Для поиска в ассоциативных списках началу и концу списка даётся одно и то же
имя, с суффиксами -B и -E, соответственно. Например:
e.Names-B (e.Name s.Index) e.Names-E
Если ассоциативный список содержит 3 компоненты, средняя получает суффикс
-M:
e.Names-B (e.Name s.Index1) e.Names-M (e.Name s.Index2) e.Names-E
Кстати, здесь оправдано использование чисел в именах переменных: два вхождения одинаковой по смыслу сущности.
Map, Reduce, MapAccum, начинаются
имени исходного файла в нижнем регистре, за которым следует прочерк
и содержательное имя функции с большой буквы. Например:
generator_GenTreeItem.ИмяФункции {
тело функции
}
=»=», «,» и «:», причём эти
знаки пишутся в начале строки.=», «,», «:» всегда ставится один пробел. Перед «=»
ставится пробел. Перед «,», «;» пробел не ставится.Условия, занимающие две строчки, для наглядности можно окружать пустыми строками.
Таким образом, предложение выглядит так:
ИмяФункции {
…
образец = результат;
длинный длинный образец
= длинный длинный результат;
длинный длинный длинный
длинный длинный образец
= длинный длинный длинный
длинный длинный результат;
образец, результат условия : образец условия = результат;
образец, результат условия : образец условия
= длинный результат;
длинный образец
, результат условия : образец условия
= результат;
длинный образец
, результат условия : образец условия
, результат условия : образец условия
, результат условия : образец условия
= результат;
длинный образец
, результат условия : образец условия
, длинный результат условия
: длинный образец условия
, результат условия : образец условия
= результат;
образец
, результат блока
: {
образец = результат;
образец
, результат условия : образец условия
= результат;
образец
, результат блока
: {
образец = результат;
…
};
};
}
Между соседними предложениями ставится пустая строка. Исключение: между двумя соседними предложениями, каждое из которых занимает одну строку, пустую строчку можно не ставить.
ИмяФункции {
образец = результат;
длинный образец
= длинный результат;
образец = результат;
образец, результат : образец = результат;
образец = результат;
длинный образец
= длинный результат;
}
Если выражение (образец или результат) слишком длинное, то разбивается по границам термов верхнего уровня.
Правильно (скобочные термы не разбиваются):
+ (e.ОднаждыВ t.Студёную s.Зимнюю) s.Пору
+ (t.ЯИзЛесу e.Вышел t.Был s.СильныйМороз)
Неправильно (один скобочный терм разбивается):
- (e.ОднаждыВ t.Студёную s.Зимнюю) s.Пору (t.ЯИзЛесу e.Вышел
- t.Был s.СильныйМороз)
Имя функции считаются частью открывающей скобки. Иногда первый терм круглых скобок мыслится как тег типа, он тоже «приклеивается» к круглой скобке.
Правильно:
+<НарезатьСалатРекурсивный
+ <ПомытьОвощи
+ e.Огурцы e.Помидоры t.Салат
+ >
+ (Специи
+ (
+ <Майонез>
+ <Сметана>
+ )
+ (
+ (Соль)
+ (Перец
+ Чёрный
+ Красный
+ )
+ )
+ )
+>
Неправильно:
-<НарезатьСалатРекурсивный <ПомытьОвощи e.Огурцы
- e.Помидоры t.Салат>
- (Специи (<Майонез>
- <Сметана>)
- ((Соль)
- (Перец Чёрный
- Красный)))>
Вспомогательные функции, реализующие цикл на хвостовой рекурсии
(остаточно-рекурсивный цикл), начинаются с префикса Do:
Fact {
0 = 1;
s.N = <DoFact 1 1 s.N>;
}
DoFact {
s.N s.Prod s.N = <* s.N s.Prod>;
s.K s.Prod s.N
= <DoFact <+ s.K 1> <* s.K s.Prod> s.N>;
}
Sw.Map, MapAccum или Reduce, если это не снижает
читабельность кода.До поддержки блоков и условий правила оформления кода были другими, в кодовой базе есть код, отформатированный вот так:
ИмяФункции {
длинный образец =
длинный результат;
}
Старый код не надо переформатировать просто так без необходимости, но можно и нужно изменять его оформление при внесении существенных правок в него. Для повышения читабельности истории можно переформатирование и последующее внесение изменений разбить на два соседних коммита.
в_нижнем_регистре_с_подчёркиваниями.typedef избегается, но если он нужен, синоним типа заканчивается на _t.в_нижнем_регистре_с_подчёркиваниями.БОЛЬШИМИ_БУКВАМИ.В фигурные скобки заключаются даже одиночные операторы:
if (x != 0) {
y = x;
}
Открывающая фигурная скобка пишется в той же строке, что и оператор.
Ключевое слово else пишется после закрывающей фигурной скобки. else-if
оформляется вот так:
if (x != 0) {
y = x;
} else if (y != 0) {
z = y;
} else {
x = z;
}
s_.switch должны быть явным образом перечислены все допустимые
варианты. Если переход на ветку default: никогда не должен происходить,
то в ней располагается вызов макроса
r05_switch_default_violation(выражение_внутри_switch),
который при передаче управления на него, выбрасывает исключение. Таким
образом выявляются ошибки в программе, связанные с передачей неверных данных.Директивы условной компиляции препроцессора, в отличие от обычного кода на C, работают на более низком семантическом уровне — оперируют с текстом как с набором строк и «нарезают» его в зависимости от макросов препроцессора.
Поэтому они не подчиняются обычным правилам отступов и пишутся сразу от начала строки
R05_NORETURN void r05_exit(int retcode) {
fflush(stderr);
fflush(stdout);
end_profiler();
#ifdef R05_SHOW_STAT
fprintf(stderr, "Step count %lu\n", s_step_counter);
#endif /* R05_SHOW_STAT */
free_memory();
fflush(stdout);
exit(retcode);
}
#endif должен располагаться комментарий с текстом условия
в соответствующем #if или #ifdef. Пример — см. выше.