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: - тоже весело - позволяет вызывать функцию только один раз, а потом обращаться к её кешированному значению.
Жаль, нет присутствовавшей в следующих постах ссылки на предысторию. Хотел было докопаться до сути серии постов, но тут вот упёрся в отсутствие ссылки )
ОтветитьУдалить