Некоторые напирают на "самодокументируемость кода". И в чём-то они правы. Нужных путей и рекомендаций - я пока не выработал настолько, чтобы мог их описать. Ну кроме банальностей типа - "имя функции должно говорить о том, что она делает".
Приведу лишь практические изыскания на тему.
Ниже приведён файл, который разбирает один входной поток и строит - другой. (Полный текст тут - https://www.box.com/s/p7dzynlw7d9klk2gwez1)
Поскольку он "типа" самодокументируемый, то пока дальнейшие коммментарии "от себя" - опускаю.
----------------------------
USES
'W:\shared\models\NewSchool\Templates\MDATuning.tpl.script'
;
: "Ничего не делаем"
; // "Ничего не делаем"
: log
.
//DROP
; // log
WORDWORKER "начинается с" W-STRING IN aStr
WordToWork DO aStr WString:Starts
; // "начинается с"
// InitedVarProducer VAR-I
: "Обработать шаблоны MDA"
ARRAY "Обработанные файлы"
FORWARD "Обработать файл"
: "Обработать файл" STRING IN "Имя входного файла"
"Обработанные файлы" "Имя входного файла" array:HasText ? (
[[ 'duplicated: ' "Имя входного файла" ' skipped' ]] strings:Cat log
EXIT
) // "Обработанные файлы" "Имя входного файла" array:HasString ?
"Имя входного файла" >>>[] "Обработанные файлы"
STRING VAR "Путь к входному файлу"
"Имя входного файла" sysutils:ExtractFilePath =: "Путь к входному файлу"
"Путь к входному файлу" log
VAR "Имя выходного файла"
"Имя входного файла" '.script' Cat =: "Имя выходного файла"
CONST "Пробел" ' '
CONST "Пустая строка" ''
CONST "Кавычка" ''''
CONST "Открывающаяся скобка" '('
CONST "Закрывающаяся скобка" ')'
CONST "Запятая" ','
CONST "Знак процента" '%'
CONST "Спецсимволы" '\%[]{}<>#()'
CONST "Цифры" '1234567890'
CONST "Разделитель частей стереотипа" '::'
STRING VAR "Имя диска"
"Имя выходного файла" sysutils:ExtractFileDrive =: "Имя диска"
'\' string:SplitTo! "Имя выходного файла"
"Имя диска" ?== 'Имя файла не содержит указание диска' ASSERTS
[[ "Имя диска" '\NewSchool\' "Имя выходного файла" ]] strings:Cat =: "Имя выходного файла"
"Имя выходного файла" log
STRING VAR "Путь к выходному файлу"
"Имя выходного файла" sysutils:ExtractFilePath =: "Путь к выходному файлу"
"Путь к выходному файлу" log
"Путь к выходному файлу" sysutils:ForceDirectories 'Не удалось создать директории' ASSERTS
//script:FileName sysutils:ExtractFileName "Пустая строка" "Пробел" Cat "Имя выходного файла" sysutils:ExtractFileName Cat =: "Имя выходного файла"
FILE VAR "Входной файл"
"Имя входного файла" file:OpenRead =: "Входной файл"
TRY
FILE VAR "Выходной файл"
"Имя выходного файла" file:OpenWrite =: "Выходной файл"
TRY
W-STRING VAR "Текущая строка входного файла"
: "Строка пустая"
"Текущая строка входного файла" WString:IsNil
; // "Строка пустая"
WORDWORKER "Строка начинается с"
VAR l_Begin
WordToWork DO =: l_Begin
"Текущая строка входного файла" "начинается с" l_Begin
; // "Строка начинается с"
WORDWORKER "Строка равна"
VAR l_EQ
WordToWork DO =: l_EQ
"Текущая строка входного файла" l_EQ ?==
; // "Строка начинается с"
BOOLEAN VAR "Накапливаемая строка пустая"
BOOLEAN VAR "Была кавычка"
: "Вывести строку"
"Выходной файл" file:WriteStr
; // "Вывести строку"
: "Вывести кавычку"
"Кавычка" "Вывести строку"
; // "Вывести кавычку"
: "Закрыть кавычку, если была"
"Была кавычка" ? (
"Вывести кавычку"
false =: "Была кавычка"
) // "Была кавычка" ?
; // "Закрыть кавычку, если была"
: "Вывести пробел"
"Пробел" "Вывести строку"
; // "Вывести пробел"
: "Сбросить накопленную строку без перевода"
"Накапливаемая строка пустая" ! ? (
"Закрыть кавычку, если была"
"Вывести пробел"
true =: "Накапливаемая строка пустая"
false =: "Была кавычка"
) // "Накапливаемая строка" string:Len !=0 ?
; // "Сбросить накопленную строку без перевода"
BOOLEAN VAR "Был отступ"
: "Перевести строку"
"Закрыть кавычку, если была"
"Пустая строка" "Выходной файл" file:WriteLn
false =: "Был отступ"
"Была кавычка" ! 'Похоже не закрыли кавычку' ASSERTS
//false =: "Была кавычка"
; // "Перевести строку"
: "Сбросить накопленную строку"
"Накапливаемая строка пустая" ! ? (
"Закрыть кавычку, если была"
"Перевести строку"
true =: "Накапливаемая строка пустая"
) // "Накапливаемая строка" string:Len !=0 ?
; // "Сбросить накопленную строку"
: "Сбросить накопленную строку, чтобы кавычка случайно не переехала на другую строку"
"Сбросить накопленную строку"
; // "Сбросить накопленную строку, чтобы кавычка случайно не переехала на другую строку"
: "Вывести строку как есть"
"Текущая строка входного файла" "Выходной файл" file:WriteWStrLn
; // "Вывести строку как есть"
: "Добавить к строке / и вывести"
"Сбросить накопленную строку, чтобы кавычка случайно не переехала на другую строку"
'/' "Вывести строку"
"Вывести строку как есть"
; // "Добавить к строке / и вывести"
: "Вывести строку как комментарий. Чтобы в конечном файле было с чем сравнивать"
"Сбросить накопленную строку, чтобы кавычка случайно не переехала на другую строку"
"Был отступ" ? "Перевести строку"
'//' "Вывести строку"
"Вывести строку как есть"
false =: "Был отступ"
; // "Вывести строку как комментарий. Чтобы в конечном файле было с чем сравнивать"
BOOLEAN VAR "Был открыт стереотип"
false =: "Был открыт стереотип"
STRING VAR "Имя стереотипа"
"Пустая строка" =: "Имя стереотипа"
STRING VAR "Имя класса стереотипа"
"Пустая строка" =: "Имя класса стереотипа"
STRING VAR "Имя под-стереотипа"
"Пустая строка" =: "Имя под-стереотипа"
STRING VAR "Имя класса под-стереотипа"
"Пустая строка" =: "Имя класса под-стереотипа"
STRING VAR "Имя под-под-стереотипа"
"Пустая строка" =: "Имя под-под-стереотипа"
STRING VAR "Имя класса под-под-стереотипа"
"Пустая строка" =: "Имя класса под-под-стереотипа"
BOOLEAN VAR "Была открыта функция"
false =: "Была открыта функция"
STRING VAR "Имя функции"
"Пустая строка" =: "Имя функции"
BOOLEAN VAR "Был открыт трансформатор"
false =: "Был открыт трансформатор"
STRING VAR "Имя трансформатора"
"Пустая строка" =: "Имя трансформатора"
BOOLEAN VAR "Был открыт генератор"
false =: "Был открыт генератор"
STRING VAR "Имя генератора"
"Пустая строка" =: "Имя генератора"
CONST Разделители ' '
CONST "Двойная кавычка" '"'
CONST "Параметр Self" ' OBJECT IN %S'
CONST "Скобка закрытия функции" '; // '
CONST "Открываем строку стереотипа" '<<'
CONST "Закрываем строку стереотипа" '>>'
CONST "Табуляция" #9
: "Вывести строку с переводом строки"
"Вывести строку"
"Перевести строку"
; // "Вывести строку с переводом строки"
: "Вывести исходную строку"
"Текущая строка входного файла" "Выходной файл" file:WriteWStr
; // "Вывести исходную строку"
: "Записать имя стереотипа"
"Имя под-стереотипа" string:Len !=0 IF
':: ' "Вывести строку"
"Имя стереотипа" "Вывести строку"
"Пробел" "Вывести строку"
"Имя под-стереотипа" "Вывести строку"
"Имя под-под-стереотипа" string:Len !=0 IF
"Пробел" "Вывести строку"
"Имя под-под-стереотипа" "Вывести строку"
ENDIF // "Имя под-под-стереотипа" string:Len !=0 IF
' ;' "Вывести строку"
ELSE
"Имя стереотипа" "Вывести строку"
ENDIF // "Имя под-стереотипа" string:Len !=0
"Перевести строку"
; // "Записать имя стереотипа"
: "Записать имя функции"
"Имя функции" "Вывести строку"
; // "Записать имя функции"
: "Записать имя трансформатора"
"Имя трансформатора" "Вывести строку"
; // "Записать имя трансформатора"
: "Записать имя генератора"
"Имя генератора" "Вывести строку"
; // "Записать имя генератора"
FORWARD "Закрыть вложенные опеределения"
: "Закрыть стереотип"
"Был открыт стереотип" ?
(
"Закрыть вложенные опеределения"
'end. // ' "Вывести строку"
"Записать имя стереотипа"
"Перевести строку"
) // "Был открыт стереотип" ?
false =: "Был открыт стереотип"
; // "Закрыть стереотип"
INTEGER VAR "Отступ"
INTEGER VAR "Количество открытых IF"
INTEGER VAR "Количество открытых циклов"
INTEGER VAR "Количество открытых скобок параметров функции"
: "Закрыть все скобки"
0 =: "Отступ"
0 =: "Количество открытых IF"
0 =: "Количество открытых циклов"
0 =: "Количество открытых скобок параметров функции"
"Закрыть вложенные опеределения"
"Закрыть стереотип"
; // "Закрыть все скобки"
: "Закавычить имя стереотипа"
Разделители "Имя стереотипа" string:HasAnyOf ? (
[[ "Двойная кавычка" "Имя стереотипа" "Двойная кавычка" ]]
strings:Cat =: "Имя стереотипа"
)
"Имя класса стереотипа" 'MDAGenerator' ?!= ? (
[[ "Открываем строку стереотипа" "Имя стереотипа" "Закрываем строку стереотипа" ]]
strings:Cat =: "Имя стереотипа"
)
; // "Закавычить имя стереотипа"
: "Закавычить имя под-стереотипа"
"Имя под-стереотипа" string:Len !=0 ? (
Разделители "Имя под-стереотипа" string:HasAnyOf ? (
[[ "Двойная кавычка" "Имя под-стереотипа" "Двойная кавычка" ]]
strings:Cat =: "Имя под-стереотипа"
) // Разделители "Имя под-стереотипа" string:HasAnyOf ?
// "Имя класса стереотипа" 'MDAGenerator' ?!=
true ? (
[[ "Открываем строку стереотипа" "Имя под-стереотипа" "Закрываем строку стереотипа" ]]
strings:Cat =: "Имя под-стереотипа"
) // true ?
) // "Имя под-стереотипа" string:Len !=0 ?
; // "Закавычить имя под-стереотипа"
: "Открыть стереотип"
"Был открыт стереотип" ! ? (
'implementation @ ' "Вывести строку"
"Записать имя стереотипа"
true =: "Был открыт стереотип"
) // "Был открыт стереотип" !
; // "Открыть стереотип"
: "Разобрать заголовок стереотипа"
"Закрыть стереотип"
2 WString:+! "Текущая строка входного файла"
"Текущая строка входного файла" WString:ToString =: "Имя стереотипа"
"Имя стереотипа" "Разделитель частей стереотипа" string:Split
=: "Имя класса стереотипа"
=: "Имя стереотипа"
"Имя класса стереотипа" "Разделитель частей стереотипа" string:Split
=: "Имя под-стереотипа"
=: "Имя класса стереотипа"
"Имя под-стереотипа" "Разделитель частей стереотипа" string:Split
=: "Имя класса под-стереотипа"
=: "Имя под-стереотипа"
"Имя класса под-стереотипа" "Разделитель частей стереотипа" string:Split
=: "Имя под-под-стереотипа"
=: "Имя класса под-стереотипа"
"Закавычить имя стереотипа"
"Закавычить имя под-стереотипа"
"Открыть стереотип"
; // "Разобрать заголовок стереотипа"
: "Закрыть функцию"
"Была открыта функция" ? ( "Скобка закрытия функции" "Вывести строку" "Записать имя функции"
"Перевести строку"
"Перевести строку"
)
false =: "Была открыта функция"
; // "Закрыть функцию"
: "Закрыть трансформатор"
"Был открыт трансформатор" ? ( "Скобка закрытия функции" "Вывести строку" "Записать имя трансформатора"
"Перевести строку"
"Перевести строку"
)
false =: "Был открыт трансформатор"
; // "Закрыть трансформатор"
: "Закрыть генератор"
"Был открыт генератор" ? ( "Скобка закрытия функции" "Вывести строку" "Записать имя генератора"
"Перевести строку"
"Перевести строку"
)
false =: "Был открыт генератор"
; // "Закрыть генератор"
// : "Было открыто хоть одно вложенное определение"
// "Была открыта функция" %||
// "Был открыт трансформатор" %||
// "Был открыт генератор"
// ; // "Было открыто хоть одно вложенное определение"
: "Закрыть вложенные опеределения"
"Закрыть генератор"
"Закрыть функцию"
"Закрыть трансформатор"
false =: "Был отступ"
; // "Закрыть вложенные опеределения"
: "Записать параметры функции" BOOLEAN IN aGlobal
"Параметр Self" "Вывести строку"
; // "Записать параметры функции"
: "Записать параметры трансформатора" BOOLEAN IN aGlobal
"Параметр Self" "Вывести строку"
; // "Записать параметры трансформатора"
: "Разобрать заголовок функции" BOOLEAN IN aGlobal
"Закрыть вложенные опеределения"
aGlobal IF
"Закрыть стереотип"
ELSE
"Открыть стереотип"
ENDIF
aGlobal IF
2 WString:+! "Текущая строка входного файла"
// - отрезаем f
ELSE
3 WString:+! "Текущая строка входного файла"
// - отрезаем %f
ENDIF
"Строка начинается с" '_' ? WString:++! "Текущая строка входного файла"
// - отрезаем поддчёркивание
"Текущая строка входного файла" WString:ToString =: "Имя функции"
// - получаем имя текущей функции
': ' "Вывести строку"
"Записать имя функции"
aGlobal "Записать параметры функции"
"Перевести строку"
true =: "Была открыта функция"
; // "Разобрать заголовок функции"
: "Разобрать заголовок трансформатора" IN aGlobal
"Закрыть вложенные опеределения"
aGlobal IF
"Закрыть стереотип"
ELSE
"Открыть стереотип"
ENDIF
aGlobal IF
2 WString:+! "Текущая строка входного файла"
// - отрезаем t
ELSE
3 WString:+! "Текущая строка входного файла"
// - отрезаем %t
ENDIF
"Строка начинается с" '_' ? WString:++! "Текущая строка входного файла"
// - отрезаем поддчёркивание
"Текущая строка входного файла" WString:ToString =: "Имя трансформатора"
// - получаем имя текущего трансформатора
'<<transformator>> ' "Вывести строку"
"Записать имя трансформатора"
aGlobal "Записать параметры трансформатора"
"Перевести строку"
true =: "Был открыт трансформатор"
; // "Разобрать заголовок трансформатора"
: "Разобрать заголовок функции стереотипа"
false "Разобрать заголовок функции"
; // "Разобрать заголовок функции стереотипа"
: "Разобрать заголовок глобальной функции"
true "Разобрать заголовок функции"
; // "Разобрать заголовок глобальной функции"
: "Разобрать заголовок трансформатора стереотипа"
false "Разобрать заголовок трансформатора"
; // "Разобрать заголовок трансформатора стереотипа"
: "Разобрать заголовок глобального трансформатора"
true "Разобрать заголовок трансформатора"
; // "Разобрать заголовок глобального трансформатора"
: "Записать параметры генератора"
"Параметр Self" "Вывести строку"
; // "Записать параметры генератора"
: "Разобрать заголовок генератора"
"Закрыть вложенные опеределения"
2 WString:+! "Текущая строка входного файла"
"Текущая строка входного файла" WString:ToString =: "Имя генератора"
"Открыть стереотип"
'<<generator>> ' "Вывести строку"
"Записать имя генератора"
"Записать параметры генератора"
"Перевести строку"
true =: "Был открыт генератор"
; // "Разобрать заголовок генератора"
BOOLEAN FUNCTION "Обрабатываем незначащие строки" BOOLEAN IN "Надо переводить строку"
: "Вывести комментарий, котрый был в исходном файле"
"Сбросить накопленную строку, чтобы кавычка случайно не переехала на другую строку"
"Надо переводить строку" IF
"Перевести строку"
ELSE
"Был отступ" ? "Перевести строку"
ENDIF // "Надо переводить строку"
"Вывести строку как есть"
; // "Вывести комментарий, котрый был в исходном файле"
: "Сигнализировать о неуспехе"
false =: Result
; // "Сигнализировать о неуспехе"
true =: Result
// - будем оптимистами
RULES
"Строка пустая"
(
"Закрыть кавычку, если была"
"Надо переводить строку" ? "Перевести строку"
"Вывести строку как есть"
) // "Строка пустая"
"Строка начинается с" '//#UC END# *'
(
"Вывести комментарий, котрый был в исходном файле"
"Закрыть вложенные опеределения"
// - т.к. наверное функция, трансформатор или генератор - закончились
)
"Строка начинается с" '//'
"Вывести комментарий, котрый был в исходном файле"
"Строка начинается с" '/'
(
"Надо переводить строку" ? "Перевести строку"
"Добавить к строке / и вывести"
) // "Строка начинается с" '/'
DEFAULT
"Сигнализировать о неуспехе"
; // RULES
; // "Обрабатываем незначащие строки"
: "Обрабатываем незначащие строки без перевода строки перед ними"
false "Обрабатываем незначащие строки"
; // "Обрабатываем незначащие строки без перевода строки перед ними"
Полный текст тут - https://www.box.com/s/p7dzynlw7d9klk2gwez1
Я не предлагаю взять это всё и использовать в "готовом виде," тем более, что в "моём" готовом виде - это вряд ли востребовано. Я пытаюсь поделиться лишь одним из возможных направлений подходов к самодокументируемому коду и использованию не языков высокого уровня общего назначения, а использования языков ориентированных на предметные области решаемых задач (DSL).
Попробуйте подумать в этом направлении. Может быть вам понравится.
Похожая тема - http://18delphi.blogspot.com/2013/04/forth-vs-lisp.html
Комментариев нет:
Отправить комментарий