среда, 9 декабря 2015 г.

#1145. Пример реальной генерации. Развитие. Только код

UNIT Generation.ms.dict

USES
 axiom_push.ms.dict
;

USES
 core.ms.dict
;

USES
 WordsRTTI.ms.dict
;

USES 
 ElementsRTTI.ms.dict
;

USES
 CompileTimeVar.ms.dict
;

USES
 SaveVarAndDo.ms.dict
;

CONST GEN_PROPERTY_PREFIX 'gp'
%REMARK 'Префикс имени свойства генератора'

MACRO %GEN_PROPERTY
 Literal IN aName
 %SUMMARY 'Свойство генератора' ;
 this.method.addr Ctx:SetWordProducerForCompiledClass
 axiom:PushSymbol CONST
 GEN_PROPERTY_PREFIX (+) ( aName |N ) Ctx:Parser:PushSymbol
; // %GEN_PROPERTY

USES
 RefDeepest.ms.dict
 FieldByNameDeepest.ms.dict
;

MACRO %GP
 Literal IN aName
 %SUMMARY 'Метод получения свойства генератора' ;
 axiom:PushSymbol FieldByNameDeepest
 GEN_PROPERTY_PREFIX (+) ( aName |N ) Ctx:Parser:PushSymbol
; // %GP

CONST cPathSep '\'

FILE CompileTime-VAR g_OutFile nil
%REMARK 'Текущий файл'

INTEGER CompileTime-VAR g_Indent 0
%REMARK 'Текущий отступ'

CONST cIndentChar ' '

STRING FUNCTION IndentStr
 g_Indent cIndentChar char:Dupe >>> Result
; // IndentStr

OBJECT STRING INTEGER ARRAY BOOLEAN TYPE OUTABLE

STRING FUNCTION ValueToString
  OUTABLE IN aValue

 if ( aValue IsArray ) then
 begin
  [ aValue .for> call.me ] strings:Cat >>> Result
 end 
 else
 if ( aValue .IsWord ) then
 begin
  aValue |N >>> Result
 end
 else
 begin
  aValue ToPrintable >>> Result
 end 
; // ValueToString

STRING FUNCTION ValueToStringOrName
  OUTABLE IN aValue
 
 if ( aValue .IsWord ) then
 begin
  aValue .Name >>> Result
  if ( Result = '' ) then
  begin
   aValue pop:Word:Name >>> Result
  end
 end
 else
 begin
  aValue ValueToString >>> Result
 end
; // ValueToStringOrName

CONST \n #13#10

PROCEDURE .Out
 OUTABLE IN aValue
 [ IndentStr aValue ValueToString ] strings:Cat g_OutFile File:WriteStr
 \n g_OutFile File:WriteStr
; // .Out

PROCEDURE Indented:
  ^ IN aLambda
  
 TF g_Indent (
  INC g_Indent
  aLambda DO
 ) 
; // Indented:

PROCEDURE Bracketed
  ^ IN aLambda
  
 '{' .Out
 Indented: ( aLambda DO ) 
 '}' .Out
; // Bracketed

USES
 axiom:SysUtils
;

USES
 arrays.ms.dict
;

TtfwWord FUNCTION .FindMemberRecur
  STRING IN aName
  TtfwWord IN aGen

 TtfwKeyWord VAR l_Member
 aName aGen pop:Word:FindMember >>> l_Member

 if ( l_Member IsNil ) then
  ( nil >>> Result )
 else
  ( l_Member pop:KeyWord:Word >>> Result )

 if ( Result IsNil ) then
  ( 
   aGen .Inherited.Words .for> ( 
    IN anItem 
    TtfwWord VAR l_Found 
    aName anItem call.me >>> l_Found
    ( Result IsNil ) 
    OR ( l_Found IsNil ) 
    OR ( Result = l_Found ) 
     ?ASSURE [ 'Multiply inheritance. Word: ' aName ' generator ' aGen pop:Word:Name ' parent generator ' anItem pop:Word:Name ]
    l_Found >>> Result
   ) 
  )

; // .FindMemberRecur

ARRAY CompileTime-VAR g_GeneratedFiles []
%REMARK 'Ранее сгенерированные файлы'

TtfwWord VAR g_CurrentGenerator
%REMARK 'Текущий генератор'

WordAlias Cached: CacheMethod
WordAlias GenCached: CacheMethod

: .?
  ^ IN aWord

 TtfwWord VAR l_Word

 aWord |N g_CurrentGenerator .FindMemberRecur >>> l_Word

 if ( l_Word IsNil ) then
  ( aWord DO )
 else
  ( l_Word DO )
; // .?

STRING FUNCTION Ext
 '.dump' >>> Result
; // Ext

PROCEDURE .GenerateWordToFile
 ModelElement IN Self
 ^ IN aLambda
 
 TF g_Indent (
  0 >>> g_Indent
  STRING VAR l_FileName 
  [ Self pop:Word:Name .? Ext ] strings:Cat >>> l_FileName
 
  STRING VAR l_TempPath
  'C:\Temp\GenScripts\' >>> l_TempPath
  l_TempPath sysutils:ForceDirectories ?ASSURE [ 'Не удалось создать директорию ' l_TempPath ]
  
  STRING VAR l_RealPath
  'W:\common\GenScripts\' >>> l_RealPath
  l_RealPath sysutils:ForceDirectories ?ASSURE [ 'Не удалось создать директорию ' l_RealPath ]
  
  STRING VAR l_TempFileName
  
  [ l_TempPath l_FileName ] cPathSep strings:CatSep >>> l_TempFileName
  
  STRING VAR l_RealFileName
  
  [ l_RealPath l_FileName ] cPathSep strings:CatSep >>> l_RealFileName
  
  if ( g_GeneratedFiles l_TempFileName array:HasText ! ) then
  begin
   l_TempFileName array:AddTo g_GeneratedFiles
   TF g_OutFile (
    l_TempFileName File:OpenWrite >>> g_OutFile
    Self aLambda DO
   )
   
   if (
       ( l_RealFileName sysutils:FileExists ! )
       OR ( '' l_RealFileName l_TempFileName CompareFiles ! ) 
      ) then
   begin
    $20 l_RealFileName l_TempFileName CopyFile
   end 
  end // g_GeneratedFiles l_TempFileName array:HasText !
 ) 
; // .GenerateWordToFile

PROCEDURE .DeleteWordFile
 ModelElement IN Self
 
  STRING VAR l_FileName 
  [ Self pop:Word:Name .? Ext ] strings:Cat >>> l_FileName
  
  STRING VAR l_RealPath
  'W:\common\GenScripts\' >>> l_RealPath
  
  STRING VAR l_RealFileName
  
  [ l_RealPath l_FileName ] cPathSep strings:CatSep >>> l_RealFileName
  
  if ( l_RealFileName sysutils:FileExists ) then
  begin
   l_RealFileName DeleteFile DROP
  end
; // .DeleteWordFile

BOOLEAN elem_func IsScriptKeyword
 Self .IsStereotype st_ScriptKeyword >>> Result
; // IsScriptKeyword

BOOLEAN elem_func IsSimpleClass
 Cached:
 (
  RULES
   ( Self .IsStereotype st_SimpleClass ) 
    true
   ( Self .IsStereotype st_Service ) 
    true
   ( Self .IsStereotype st_ServiceImplementation ) 
    true
   ( Self .IsScriptKeyword ) 
    true
   ( Self .IsStereotype st_TestCase ) 
    true
   ( Self .IsStereotype st_GuiControl ) 
    true
   ( Self .IsStereotype st_VCMForm ) 
    true
   ( Self .IsStereotype st_VCMFinalForm ) 
    true
   ( Self .IsStereotype st_VCMContainer ) 
    true
   ( Self .IsStereotype st_VCMFinalContainer ) 
    true
   DEFAULT
    false 
  ; // RULES
 )  
 >>> Result
; // IsSimpleClass
 
BOOLEAN elem_func IsUtilityPack
 Cached:
 (
  RULES
   ( Self .IsStereotype st_UtilityPack )
    true
   ( Self .IsStereotype st_ScriptKeywordsPack ) 
    true
   DEFAULT
    false
  ; // RULES 
 ) 
 >>> Result
; // IsUtilityPack

BOOLEAN elem_func IsInterfaces
 Cached:
 (
  RULES
   ( Self .IsStereotype st_Interfaces ) 
    true
   ( Self .IsStereotype st_InternalInterfaces )
    true
   DEFAULT
    false
  ; // RULES 
 )
 >>> Result
; // IsInterfaces

BOOLEAN elem_func IsMixIn
 Self .IsStereotype st_Impurity >>> Result
; // IsMixIn

BOOLEAN elem_func IsPureMixIn
 Self .IsStereotype st_PureMixIn >>> Result
; // IsPureMixIn

BOOLEAN elem_func IsTypedef
 Self .IsStereotype st_Typedef >>> Result
; // IsTypedef

BOOLEAN elem_func IsTagTable
 Self .IsStereotype st_TagTable >>> Result
; // IsTagTable

BOOLEAN elem_func IsTarget
 Cached:
 (
  RULES
   ( Self .IsStereotype st_ExeTarget ) 
    true
    
   ( Self .IsStereotype st_AdapterTarget ) 
    true
    
   ( Self .IsStereotype st_TestTarget ) 
    true
    
   DEFAULT
    false
  ; // RULES
 )
 >>> Result
; // IsTarget

BOOLEAN FUNCTION NeedOwnFile
 ModelElement IN Self
 Cached:
 (
  RULES
   ( Self .IsStereotype st_ScriptKeywords ) 
    false 
    
   ( Self .IsStereotype st_TestClass ) 
    true
    
   ( Self .IsStereotype st_Atom ) 
    true
    
   ( Self .IsStereotype st_Tag ) 
    true
    
   ( Self .IsTarget ) 
    true
    
   ( Self .IsStereotype st_TestResults ) 
    true
    
   ( Self .IsTagTable ) 
    true
    
   ( Self .IsInterfaces )
    true
   
   ( Self .IsUtilityPack )
    true
   
   ( Self .IsMixIn )
    true
   
   ( Self .IsSimpleClass )
   begin
    RULES
     ( Self .Visibility = ProtectedAccess )
      false
     ( Self .Visibility = PrivateAccess )
      false
     DEFAULT
      ( 
       ModelElement VAR l_Parent
       Self .Parent >>> l_Parent
       if (
           ( l_Parent .IsSimpleClass ) 
           OR ( l_Parent .IsMixIn )
           OR ( l_Parent .IsUtilityPack )
           OR ( l_Parent .IsInterfaces )
          ) then
       begin
        false
       end 
       else
       begin
        true
       end 
      )
    ; // RULES
   end
   
   DEFAULT
    false
  ; // RULES
 )
 >>> Result
; // NeedOwnFile

PROCEDURE .CurrentGenerator
 ModelElement IN Self
 Self g_CurrentGenerator DO
; // .CurrentGenerator

USES
 CallInherited.ms.dict
;

USES
 classRelations.ms.dict
;

BOOLEAN elem_func NeedOwnFile
 Self .? NeedOwnFile >>> Result
; // NeedOwnFile

elem_proc dump
 Self .Out
 Bracketed (
  Self MembersIterator .for> ( 
    OBJECT IN aCode
    
   STRING VAR l_Out  
   STRING VAR l_Name
   aCode pop:Word:Name >>> l_Name
   [ l_Name ' : ' ] strings:Cat >>> l_Out 
   [ aCode DO ] .for> ( 
     IN anItem
     
    if ( anItem .IsSequence ) then
     ( anItem .SequenceCode.It >>> anItem )
    if ( anItem IsArray ) then
    begin
     if ( 
         ( l_Name = 'Children' )
        ) then
     begin
      '' >>> l_Out
      l_Name .Out
      Bracketed (
       ARRAY VAR l_Items
       anItem 
        .filter> ( .NeedOwnFile ! ) 
        >>> l_Items 
       l_Items .filter> ( .Visibility = PrivateAccess ) .for> call.me
       l_Items .filter> ( .Visibility = ProtectedAccess ) .for> call.me
       l_Items .filter> ( .Visibility = PublicAccess ) .for> call.me
       l_Items .filter> ( .Visibility = UnknownAccess ) .for> call.me
      ) // Bracketed
     end
     else
     if ( 
         ( l_Name = 'Attributes' )
         OR ( l_Name = 'Operations' )
         OR ( l_Name = 'Constants' )
         OR ( l_Name = 'Dependencies' )
         OR ( l_Name = 'Parameters' )
        ) then
     begin
      '' >>> l_Out
      l_Name .Out
      Bracketed (
       ARRAY VAR l_Items
       anItem 
        // .filter> ( .NeedOwnFile ! ) 
        >>> l_Items 
       l_Items .filter> ( .Visibility = PrivateAccess ) .for> call.me
       l_Items .filter> ( .Visibility = ProtectedAccess ) .for> call.me
       l_Items .filter> ( .Visibility = PublicAccess ) .for> call.me
       l_Items .filter> ( .Visibility = UnknownAccess ) .for> call.me
      ) // Bracketed
     end
     else
     begin
      l_Out [ anItem .for> ValueToStringOrName ] ' ' strings:CatSep Cat >>> l_Out
     end
    end // anItem IsArray
    else
    begin
     l_Out anItem ValueToStringOrName Cat >>> l_Out
    end // anItem IsArray
     
    if ( l_Out <> '' ) then
    begin
     l_Out .Out
    end // l_Out <> ''
   ) // [ aCode DO ] .for>
  ) // Self MembersIterator
 ) // Bracketed
; // dump

PROCEDURE OutLn
 '' .Out
; // OutLn

elem_proc WithDelim
  STRING IN aDelim
  TtfwWord IN aVar
  TtfwWord IN aLambda
 [ 
  if ( aVar DO ! ) then
  begin
   true aVar pop:Word:SetValue
  end
  else
  begin
   aDelim
  end
  Self 
 ] aLambda DO
; // WithDelim

elem_proc WithComma:
  ^ IN aVar
  ^ IN aLambda
 Self ', ' aVar aLambda .WithDelim
; // WithComma:

STRING FUNCTION .CutT
  STRING IN aName
 aName >>> Result
 if ( 'T' Result StartsStr ) then
 begin
  Result 'T' '' string:ReplaceFirst >>> Result
 end // 'T' Result StartsStr
; // .CutT

STRING elem_func UnitName
 GenCached:
 (
  STRING VAR l_Path
  Self .GetUP 'intf.pas:Path' >>> l_Path
  RULES
   ( l_Path <> '' )
    ( 'w:\' 
      // - это потому, что в пути нету диска, а для ExtractFileName он нужен
      l_Path Cat sysutils:ExtractFileName '' sysutils:ChangeFileExt 
      'NOT_FINISHED_' '' string:ReplaceFirst
    )
   ( Self IsNil )
     ''
   ( Self .IsTagTable )
    ( Self .Name '_Schema' Cat )
   ( Self .IsScriptKeyword )
    ( Self .Name .CutT )
   ( Self .IsSimpleClass )
    ( Self .Name .CutT )
   DEFAULT
    ( Self .Name )
  ; // RULES
 )
 >>> Result
; // UnitName

ModelElement elem_func UnitProducer
 GenCached:
 (
  RULES
   ( Self IsNil )
    nil
   ( Self IsString )
    Self
   ( Self .NeedOwnFile )
    Self
   DEFAULT 
    ( Self .Parent call.me )
  ; // RULES
 )
 >>> Result
; // UnitProducer

ARRAY FUNCTION .filterNil>
  ARRAY IN anArray
 anArray
 .filter> ( IsNil ! ) 
 >>> Result
; // .filterNil>

ARRAY FUNCTION .filterMixIns>
  ARRAY IN anArray
 anArray
 .filter> ( .IsMixIn ! ) 
 // .filter> ( .IsPureMixIn ! )
 >>> Result
; // .filterMixIns>

elem_proc OutUses:
  ^ IN aUsed
  ^ IN aLambda
  
 ARRAY VAR l_Used
 aUsed DO >>> l_Used
  
 ARRAY FUNCTION .filterUsed>
   ARRAY IN anArray
  anArray
  .filter> ( 
    IN anItem 
   if ( anItem l_Used array:Has ! ) then
   begin
    anItem array:AddTo l_Used
    true
   end
   else
   begin
    false
   end 
  ) >>> Result  
 ; // .filterUsed> 
  
 'uses' .Out
   BOOLEAN VAR l_NeedComma
   false >>> l_NeedComma
   Indented: ( 
    aLambda DO 
     .map> .UnitProducer 
     .filterNil> 
     .filterMixIns>
     .filter> ( Self ?!= )
     .filter> ( .UnitName Self .UnitName ?!= )
     .filter> ( .UnitName 'System' ?!= )
     .map> .UnitName 
     .filterUsed> 
     .for> ( .WithComma: l_NeedComma .Out ) 
   ) // Indented:
 ';' .Out
 OutLn
; // OutUses:

ARRAY FUNCTION .mapToTarget>
  ARRAY IN anArray
 anArray .map> .Target >>> Result
; // .mapToTarget>

ARRAY FUNCTION .joinWithLambded>
  ARRAY IN anArrayToJoin
  ^ IN anArrayToIterate
  ^ IN aLambda
  
 anArrayToJoin 
 anArrayToIterate DO .for> ( IN aChild .join> ( aChild aLambda DO ) )
 >>> Result
; // .joinWithLambded>

ARRAY FUNCTION .mapToTargetAndValueType>
  ARRAY IN anArray
 anArray .mapToTarget>
 .join> ( anArray .map> .ValueType )
 >>> Result
; // .mapToTargetAndValueType>

elem_iterator AttributesAndOperations
 Cached:
 (
  Self .Attributes
  .join> ( Self .Operations )
 )
 >>> Result
; // AttributesAndOperations

elem_iterator ChildrenWithoutOwnFile
 Cached:
 ( 
  Self .Children .filter> ( .NeedOwnFile ! ) 
 )
 >>> Result
; // ChildrenWithoutOwnFile

elem_iterator ConstantsAndChildrenWithoutOwnFile
 Cached:
 ( 
  Self .Constants
  .join> ( Self .ChildrenWithoutOwnFile )
 )
 >>> Result
; // ConstantsAndChildrenWithoutOwnFile

elem_iterator AllOwnChildren
 Cached:
 ( 
  Self .ConstantsAndChildrenWithoutOwnFile
  .join> ( Self .AttributesAndOperations )
 )
 >>> Result
; // AllOwnChildren

ARRAY FUNCTION .OperationsNeededElements
  ARRAY IN anArray
 anArray .mapToTargetAndValueType>
 .joinWithLambded> anArray ( .Parameters .mapToTargetAndValueType> )
 .joinWithLambded> anArray ( .AttributesAndOperations call.me )
 >>> Result 
; // .OperationsNeededElements

elem_iterator NeededElements
 ( Self .Inherits )
 .join> ( Self .Implements )
 .join> ( Self .AttributesAndOperations .OperationsNeededElements )
 
 if ( Self .IsTypedef ! ) then
 begin
 .join> ( Self .Implemented .OperationsNeededElements )
 .join> ( Self .Overridden .OperationsNeededElements )
 end // Self .IsTypedef !
 
 >>> Result
; // NeededElements

elem_iterator NeededElementsTotal
 Self .NeededElements
 .joinWithLambded> ( Self .ConstantsAndChildrenWithoutOwnFile ) call.me
 >>> Result
; // NeededElementsTotal

BOOLEAN elem_func IsForInterface
 Cached:
 (
  Self .Visibility PublicAccess == 
 ) 
 >>> Result
; // IsForInterface

BOOLEAN elem_func IsForImplementation
 Cached:
 (
  Self .IsForInterface ! 
 ) 
 >>> Result
; // IsForImplementation

elem_iterator IntfUses
 [ 'l3IntfUses' ]
 if ( Self .IsForInterface ) then
 begin
  .join> ( Self .NeededElementsTotal )
 end // Self .IsForInterface
 >>> Result
; // IntfUses

BOOLEAN elem_func IsInterface
 Self .IsStereotype st_Facet >>> Result
; // IsInterface

elem_iterator InjectedElements
 Self .Injected .filter> ( .IsStereotype st_injects::Dependency ) .map> .Parent
 >>> Result
; // InjectedElements

BOOLEAN elem_func IsClassImplementable
 Cached:
 (
  RULES
   ( Self .IsPureMixIn )
    false
   ( Self .IsMixIn )
    false
   ( Self .IsStereotype st_Atom )
    false 
   DEFAULT
    true
  ; // RULES
 )
 >>> Result
; // IsClassImplementable

elem_iterator Used
 Cached:
 (
  Self .Dependencies .filter> ( .IsStereotype st_uses::Dependency ) .mapToTarget> 
  if ( Self .IsInterface ! ) then
  begin
   .join> ( Self .InjectedElements )
  end // Self .IsInterface !
 )
 >>> Result
; // Used

elem_iterator UsedTotal
 Self .Used
 .joinWithLambded> ( Self .AllOwnChildren ) call.me
 >>> Result
; // UsedTotal

elem_iterator ImplUses
 [ 'l3ImplUses' ]
 if ( Self .IsForImplementation ) then
 begin
  .join> ( Self .NeededElementsTotal )
 end // Self .IsForImplementation
 .join> ( Self .UsedTotal ) 
 >>> Result
; // ImplUses

STRING elem_func TypeName
 Cached:
 (
  STRING VAR l_ExtName
  Self .GetUP 'extprop:pas:TypeName' >>> l_ExtName
  RULES
   ( l_ExtName <> '' )
    l_ExtName
   DEFAULT
    ( Self .Name )
  ; // RULES
 )
 >>> Result
; // TypeName

BOOLEAN elem_func IsClass
 Self .IsSimpleClass >>> Result
; // IsClass

ModelElement elem_func MainAncestor
 Cached:
 (
  ModelElement VAR l_Found
  nil >>> l_Found
  Self .Inherits .trunc> ( DROP l_Found IsNil ) .for> ( >>> l_Found )
  l_Found
 )
 >>> Result
; // MainAncestor

: .With()
  OUTABLE IN aValue
 if ( aValue IsNil ! ) then
  [ '(' aValue ')' ]
; // .With()

elem_proc OutDocumentation
 STRING VAR l_Doc
 Self .Documentation >>> l_Doc
 if ( l_Doc IsNil ! ) then
 begin
  l_Doc '{' '[' string:Replace >>> l_Doc
  l_Doc '}' ']' string:Replace >>> l_Doc
  Indented: ( [ '{* ' l_Doc ' }' ] .Out )
 end // l_Doc IsNil !
; // OutDocumentation

elem_proc OutClass
 [ Self .TypeName ' = class' 
  [ Self .MainAncestor ] 
  .join> ( 
   Self .Implements 
   .filter> .IsClassImplementable
  ) 
  .map> .TypeName
  ', ' strings:CatSep
  .With() 
 ] .Out
 
 Self .OutDocumentation
 
 [ 'end;//' Self .TypeName ] .Out
; // OutClass

elem_proc OutInterface
 [ Self .TypeName ' = interface' Self .MainAncestor .TypeName .With() ] .Out
 [ 'end;//' Self .TypeName ] .Out
; // OutInterface

elem_proc OutType
 RULES
  ( Self .IsClass )
   ( Self .OutClass )
  ( Self .IsInterface )
   ( Self .OutInterface )
  DEFAULT
   ( [ '// ' Self .TypeName ] .Out )
 ; // RULES 
 OutLn
; // OutType

BOOLEAN elem_func IsType
 Cached:
 (
  RULES
   ( Self .IsUtilityPack )
    false
   ( Self .IsInterfaces )
    false
   ( Self .IsTarget )
    false
   DEFAULT
    true
  ; // RULES
 )
 >>> Result
; // IsType

elem_proc OutTypes
  ^ IN aValid
  
 BOOLEAN VAR l_WasType 
 
 false >>> l_WasType
 
 elem_proc DoOutTypes
  Self .ChildrenWithoutOwnFile .for> call.me
  if ( Self aValid DO ) then
  begin
   if ( Self .IsType ) then
   begin
    if ( l_WasType ! ) then
    begin
     'type' .Out
     true >>> l_WasType
    end
    Indented: ( Self .OutType )
   end // Self .IsType
  end 
 ; // DoOutTypes
 
 Self .DoOutTypes
; // OutTypes

elem_proc OutInterfaceSection

 Self .OutTypes .IsForInterface
 
; // OutInterfaceSection

elem_proc OutImplementationSection

 Self .OutTypes .IsForImplementation
 
; // OutImplementationSection

elem_proc OutUnit
 [ 'unit ' Self .UnitName ';' ] .Out
 OutLn
 'interface' .Out
 OutLn
 
 ARRAY VAR l_Used
 [] >>> l_Used
 
 Self .OutUses: l_Used ( Self .IntfUses )
 
 Self .OutInterfaceSection
 
 'implementation' .Out
 OutLn
 
 Self .OutUses: l_Used ( Self .ImplUses )
 
 Self .OutImplementationSection
 
 'end.' .Out
; // OutUnit

elem_proc OutMixIn
 Self .Name .Out
; // OutMixIn

elem_generator pas
 
 CONST Ext '.pas'

 RULES
  ( Self .IsMixIn )
   ( Self .OutMixIn )
   
  ( Self .IsInterfaces )
   ( Self .OutUnit )
  ( Self .IsSimpleClass )
   ( Self .OutUnit )
  ( Self .IsUtilityPack )
   ( Self .OutUnit )
  ( Self .IsStereotype st_TestClass ) 
   ( Self .OutUnit )
  ( Self .IsTarget ) 
   ( Self .OutUnit )
  ( Self .IsTagTable ) 
   ( Self .OutUnit )
  DEFAULT
   ( Self .dump )
 ; // RULES
; // pas

elem_generator res.cmd
 
 Inherits .pas

 CONST Ext '.res.cmd'
 
 BOOLEAN FUNCTION NeedOwnFile
   ModelElement IN Self
   
  Self .UPisTrue "needs script" >>> Result 
 ; // NeedOwnFile
  
 [ 'MakeCo ' Self .Name '.rc.script' ] .Out
 [ 'brcc32 ' Self .Name '.rc' ] .Out
 //call.inherited
; // res.cmd

elem_generator rc
 
 Inherits .res.cmd

 CONST Ext '.rc'
 
 [ Self .Name ' RCDATA LOADONCALL MOVEABLE DISCARDABLE ' Self .Name '.rc.script.co' ] .Out
 //call.inherited
; // rc

ARRAY CompileTime-VAR g_GeneratedElements []
%REMARK 'Ранее сгенерированные элементы'

PROCEDURE .GenerateWithChildren
 ModelElement IN Self
 Sequence IN aGenerators
 
 if ( Self g_GeneratedElements array:Has ! ) then
 begin
  Self array:AddTo g_GeneratedElements
  aGenerators CodeIterator .for> (
  // - цикл по генераторам для Self
   TtfwWord IN aGenerator
   TF g_CurrentGenerator (
    aGenerator >>> g_CurrentGenerator
    if ( Self .NeedOwnFile ) then
     ( Self .GenerateWordToFile .CurrentGenerator )
    else
     ( Self .DeleteWordFile ) 
   ) // TF g_CurrentGenerator
  ) // aGenerators CodeIterator .for>
  
  Self .Children 
 //  .filter> ( .NeedOwnFile )
    .for> ( aGenerators call.me )
  // - тут генерируем детей  
 end // Self g_GeneratedElements array:Has !
; // .GenerateWithChildren

PROCEDURE .call.generators.in.list
 ModelElement IN Self
 Sequence ^ IN aGenerators
 Self aGenerators .GenerateWithChildren
; // .call.generators.in.list

PROCEDURE .Generate
 ModelElement IN Self
 
 g_GeneratedFiles = nil ?FAIL 'Массив g_GeneratedFiles не инициализирован'
 g_GeneratedElements = nil ?FAIL 'Массив g_GeneratedElements не инициализирован'
 
 Self .call.generators.in.list ( .pas .res.cmd .rc )
 
; // .Generate

Функциональщина....

.filter>, .map> и .join> меня особенно "заводят".

Они позволяют работать с коллекциями элементов без их копирования.

Ну и Cached: - тоже весело - позволяет вызывать функцию только один раз, а потом обращаться к её кешированному значению.

1 комментарий:

  1. Жаль, нет присутствовавшей в следующих постах ссылки на предысторию. Хотел было докопаться до сути серии постов, но тут вот упёрся в отсутствие ссылки )

    ОтветитьУдалить