Придумал, что делать с генерацией и переходом на "новые скрипты".
В общем - делаем "старые скрипты", которые генерируют "новые скрипты", которые генерируют код.
И так - итеративно. Пока "старых скриптов" не останется.
Чуть позже опишу идею.
"Код который сам себя пишет". Звучит ИДИОТСКИ - я знаю. Но это так.
Пока заготовочка:
В общем - делаем "старые скрипты", которые генерируют "новые скрипты", которые генерируют код.
И так - итеративно. Пока "старых скриптов" не останется.
Чуть позже опишу идею.
"Код который сам себя пишет". Звучит ИДИОТСКИ - я знаю. Но это так.
Пока заготовочка:
PROGRAM GenerateUnit.ms.script
CONST cPathSep '\'
STRING FUNCTION OutDir
sysutils:GetCurrentDir >>> Result
[ Result
script:FileName
%REMARK 'Путь к текущему скрипту'
sysutils:ExtractFileName
%REMARK 'Вырезаем из пути только имя файла'
'' sysutils:ChangeFileExt
%REMARK 'Убираем .script'
'' sysutils:ChangeFileExt
%REMARK 'Убираем .ms'
] cPathSep strings:CatSep >>> Result
; // OutDir
STRING FUNCTION MakeOutPath
OutDir >>> Result
Result sysutils:ForceDirectories ?ASSURE [ 'Не удалось создать директорию ' Result ]
; // MakeOutPath
USES
CompileTimeVar.ms.dict
;
FILE CompileTime-VAR g_OutFile nil
%REMARK 'Текущий файл'
INTEGER CompileTime-VAR g_Indent 0
%REMARK 'Текущий отступ'
STRING INTEGER ARRAY TYPE OUTABLE
CONST cIndentChar ' '
FORWARD ValueToString
STRING FUNCTION ValueToString
OUTABLE IN aValue
if ( aValue IsArray ) then
( [ aValue .for> ValueToString ] strings:Cat >>> Result )
else
( aValue ToPrintable >>> Result )
; // ValueToString
PROCEDURE OutToFile
OUTABLE IN aValue
%SUMMARY
'
Выводит значение в текущий файл вывода.
БЕЗ перевода каретки.
'
; // %SUMMARY
[ g_Indent cIndentChar char:Dupe aValue ValueToString ] strings:Cat g_OutFile File:WriteStr
%REMARK '- выводим элементы модели в файл, а не в стандартный вывод.'
; // OutToFile
CONST \n #13#10
PROCEDURE OutToFileLn
OUTABLE IN aValue
%SUMMARY
'
Выводит значение в текущий файл вывода.
С переводом каретки.
'
; // %SUMMARY
aValue OutToFile
%REMARK '- выводим элементы модели в файл, а не в стандартный вывод.'
\n g_OutFile File:WriteStr
%REMARK '- выводим перевод каретки'
; // OutToFileLn
PROCEDURE array:OutToFileLn
ARRAY IN aValue
%SUMMARY 'Выводит значения элементов массива построчно' ;
aValue .for> OutToFileLn
; // array:OutToFileLn
USES
SaveVarAndDo.ms.dict
;
: ExpandLambda
FUNCTOR IN aLambda
ARRAY VAR l_LambdaCode
[ aLambda DO ] >>> l_LambdaCode
if ( l_LambdaCode Array:Count <> 0 ) then
begin
[
l_LambdaCode .for> (
IN aValue
aValue
\n
)
]
end
; // ExpandLambda
ARRAY CompileTime-VAR g_OutedUnits []
ARRAY CompileTime-VAR g_OutedClasses []
PROCEDURE GenerateUnit
STRING IN aUnitName
^ IN anInterfaceLambda
^ IN anImplementationLambda
aUnitName IsNil ?FAIL 'Имя модуля не может быть пустым'
aUnitName g_OutedUnits array:Has ?FAIL [ 'Модуль ' aUnitName ' уже генерировался' ]
aUnitName array:AddTo g_OutedUnits
STRING VAR l_UnitFileName
[ aUnitName '.pas' ] strings:Cat >>> l_UnitFileName
STRING VAR l_UnitPath
MakeOutPath >>> l_UnitPath
[ l_UnitPath cPathSep l_UnitFileName ] strings:Cat >>> l_UnitPath
l_UnitPath Print
TF g_OutedClasses (
[] >>> g_OutedClasses
l_UnitPath File:OpenWrite >>> g_OutFile
TF g_OutFile (
[
[ 'unit' ' ' aUnitName ';' ]
''
'interface'
''
anInterfaceLambda ExpandLambda
'implementation'
''
anImplementationLambda ExpandLambda
'end.'
] array:OutToFileLn
) // TF g_OutFile
) // TF g_OutedClasses
; // GenerateUnit
: GenerateClass
STRING IN aClassName
aClassName g_OutedClasses array:Has ?FAIL [ 'Класс ' aClassName ' уже генерировался' ]
aClassName array:AddTo g_OutedClasses
aClassName IsNil ?FAIL 'Имя класса не может быть пустым'
'type'
aClassName
'end;'
''
; // GenerateClass
USES
Testing.ms.dict
;
Test&Dump GenerateUnitTest
TF g_OutedUnits (
'Unit1' GenerateUnit (
'TTest1' GenerateClass
'TTest2' GenerateClass
'TTest3' GenerateClass
) ()
g_OutedClasses Print
'Unit2' GenerateUnit ( 'test' ) ( 'test' )
g_OutedClasses Print
'Unit3' GenerateUnit () ()
'Unit4' GenerateUnit () ()
g_OutedUnits Print
)
; // GenerateUnitTest
GenerateUnitTest
Комментариев нет:
Отправить комментарий