Придумал, что делать с генерацией и переходом на "новые скрипты".
В общем - делаем "старые скрипты", которые генерируют "новые скрипты", которые генерируют код.
И так - итеративно. Пока "старых скриптов" не останется.
Чуть позже опишу идею.
"Код который сам себя пишет". Звучит ИДИОТСКИ - я знаю. Но это так.
Пока заготовочка:
В общем - делаем "старые скрипты", которые генерируют "новые скрипты", которые генерируют код.
И так - итеративно. Пока "старых скриптов" не останется.
Чуть позже опишу идею.
"Код который сам себя пишет". Звучит ИДИОТСКИ - я знаю. Но это так.
Пока заготовочка:
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
Комментариев нет:
Отправить комментарий