Original in Russian: http://programmingmindstream.blogspot.ru/2015/08/blog-post_88.html
The previous series was here – Code generation. Iterators and lambdas in use.
Now let us place each test’s output in the own subdirectory.
The result is as follows:
https://bitbucket.org/lulinalex/mindstream/src/7eddcb6df86621092ff1ee580f5c36a4e4c4aea3/Examples/Scripts/CodeGeneration/CodeGen59.ms.script?at=B284
The previous series was here – Code generation. Iterators and lambdas in use.
Now let us place each test’s output in the own subdirectory.
The result is as follows:
https://bitbucket.org/lulinalex/mindstream/src/7eddcb6df86621092ff1ee580f5c36a4e4c4aea3/Examples/Scripts/CodeGeneration/CodeGen59.ms.script?at=B284
USES metaMACRO.ms.dict classRelations.ms.dict ; Test CodeGen %REMARK ' CodeGen - function to test functionality ' %REMARK ' %SUMMARY is meta information that allows binding the documentation to the code elements. Consequently, the documentation is available from the script engine. ' %SUMMARY ' 'That is where we test meta-model building, model building and then code generation. ' ; // %SUMMARY // --------------------------------------------------------------------------- meta-meta-model-begin 'That is where we determine axiomatic of meta-meta model and extract it in a separate dictionary later. ' StereotypeStereotypeProducer meta %SUMMARY ' Base element of meta-model determined This is the element that allows us to pull the rest “by hair out of the swamp” Other primitives are derived from this one ' ; // %SUMMARY ; // meta meta-meta-model-end // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- meta-model-begin 'That is where we determine axiomatic of meta model and then separate it in a dictionary. Next we will determine the UML concepts – https://en.wikipedia.org/wiki/Unified_Modeling_Language There are CATEGORIES and CLASSES in it Actually, they merely differ from each other, however, let it be so for it was so decided by some wise men Let’s start with them: ' <<@meta>> UMLCategory %SUMMARY ' Category on UML ' ; // %SUMMARY ; // UMLCategory <<@meta>> UMLClass %SUMMARY ' Class on UML ' ; // %SUMMARY ; // UMLClass meta-model-end // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- concrete-model-begin 'Templates model' ' This is where we determine axiomatic of the specific model. For now let’s determine axiomatic of “templates model” We will separate it in a dictionary later. ' <<UMLCategory>> Project %SUMMARY ' We probably bump into projects here and there when developing. The Project is a stereotype describing our projects. ' ; // %SUMMARY ; // Project <<UMLCategory>> Library %SUMMARY ' We probably bump into design libraries here and there when developing. The Library is a stereotype describing our libraries. ' ; // %SUMMARY ; // Library <<UMLCategory>> Program %SUMMARY ' We probably bump into programs here and there when developing. The Program is a stereotype describing our programs. ' ; // %SUMMARY ; // Program <<UMLClass>> Class %SUMMARY ' We probably bump into design classes here and there when developing. The Class is a stereotype describing our design classes. ' ; // %SUMMARY ; // Class <<UMLClass>> Interface %SUMMARY ' We probably bump into interfaces here and there when developing. The Interface is a stereotype describing our interfaces. ' ; // %SUMMARY ; // Interface %REMARK ' Some time later, when we start to use these we will find out whether the Library can be embedded in Project and, vise versa, the Project embedded in the Library or whether the Program can be embedded in the Class and, vise versa, the Class embedded in the Library as well as other relations between stereotypes. ' model-end // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- concrete-model-begin 'Model of the specific project Project1' ' This is where we determine axiomatic of the specific model of the specific project We will separate it in a dictionary later. ' <<Project>> Project1 %SUMMARY ' This is our first project - Project1 ' ; // %SUMMARY <<Library>> Library1 %SUMMARY ' Probably, there are design libraries in our project. The Library1 is our first design library. ' ; // %SUMMARY ; // Library1 <<Library>> Library2 %SUMMARY ' Our project is probably serious enough and has MORE THAN ONE library. The Library2 is our second design library. ' ; // %SUMMARY ; // Library2 <<Library>> Library3 %SUMMARY ' Our project is probably SO serious that it has even MORE THAN TWO libraries. The Library3 is our third design library. ' ; // %SUMMARY ; // Library3 <<Program>> Program1 %SUMMARY ' Our project probably implements some program. Otherwise, why would we need it? The Program1 is a program in our Project1. ' ; // %SUMMARY <<Class>> Class1 %SUMMARY ' Our program probably has some implementation classes. Otherwise, how would we implement our functionality? The Class1 is our FIRST implementation class in our Program1. ' ; // %SUMMARY ; // Class1 <<Interface>> Interface1 %SUMMARY ' Our program is probably SO serious that implements some interfaces. The Interface1 is our FIRST interface. ' ; // %SUMMARY ; // Interface1 <<Interface>> Interface2 %SUMMARY ' Our program is probably SO serious that it implements MORE THAN ONE interface. The Interface2 is our second interface. ' ; // %SUMMARY ; // Interface2 <<Class>> Class2 %SUMMARY ' Our program is probably serious enough and has MORE THAN ONE implementation class. The Class2 is our second implementation class in Program1. ' ; // %SUMMARY %INHERITS @ Class1 %REMARK 'Perhaps the design Class2 is inherited from Class1' ; // %INHERITS %IMPLEMENTS @ Interface1 %REMARK 'Perhaps the design Class2 implements Interface1' @ Interface2 %REMARK 'Perhaps the design Class2 implements Interface2, too' ; // %IMPLEMENTS ; // Class2 <<Class>> Class3 %SUMMARY ' Our program is probably so complex that it has even more than TWO implementation classes. The Class3 is the THIRD implementation class within the Program1. ' ; // %SUMMARY ; // Class3 <<Class>> Class4 %SUMMARY ' We are probably so cool that we have even more than THREE implementation classes. The Class4 is the FOURTH implementation class within the Program1. ' ; // %SUMMARY %INHERITS @ Class2 @ Class3 %REMARK ' We are probably cool enough to use MULTIPLE INHERITANCE and, moreover, to UNDERSTAND WHY we need it. The Class4 is inherited from Class2 and Class3. ' ; // %INHERITS ; // Class4 ; // Program1 ; // Project1 %REMARK ' These words should “probably” be based on requirements specification and UseCase. Well, we will talk it over later. ' model-end // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- concrete-model-begin 'Model of the specific project Project2' ' This is where we determine axiomatic of the specific model of the specific project We will separate it in a dictionary later. ' <<Project>> Project2 %SUMMARY ' This is our second project - Project2 ' ; // %SUMMARY ; // Project2 model-end // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- concrete-model-begin 'Model of the specific project Project3' ' This is where we determine axiomatic of the specific model of the specific project We will separate it in a dictionary later. ' <<Project>> Project3 %SUMMARY ' This is our third project - Project3 ' ; // %SUMMARY ; // Project3 model-end // --------------------------------------------------------------------------- USES CodeDump.ms.dict // - the CodeDump.ms.dict is loaded so we can “see” the DumpElement word ; @SELF DumpElement %REMARK ' - the CodeGen element and its contents are dumped in a standard output devise. We only do it to debug what we’ve written. ' help %REMARK ' The available axiomatic is output to a standard output device. We only do it to debug what we’ve written. ' %REMARK ' Now, what can we do with our project? To begin with, let us output its name to a standard device. ' // --------------------------------------------------------------------------- %REMARK 'All this staff is needed to be separated to a dictionary later' TtfwWord TYPE ModelElement %REMARK 'Model’s element' PROCEDURE do_elem_func STRING IN aName TtfwWord IN aSelf TtfwWord IN aModifier %SUMMARY 'Implementation of do_elem_func, elem_proc and elem_generator' ; aSelf Ctx:SetWordProducerForCompiledClass axiom:PushSymbol : aName Ctx:Parser:PushLeftDottedSymbol axiom:PushSymbol ModelElement if ( aModifier <> nil ) then ( aModifier |N Ctx:Parser:PushSymbol ) axiom:PushSymbol in 'Self' Ctx:Parser:PushSymbol ; // do_elem_func MACRO elem_func Literal IN aName %SUMMARY 'Function on model’s element' ; aName |N @SELF nil do_elem_func ; // elem_func PROCEDURE do_elem_proc STRING IN aName TtfwWord IN aSelf TtfwWord IN aModifier %SUMMARY 'Implementation of elem_proc and elem_generator' ; Ctx:ClearTypeInfo axiom:PushSymbol VOID aName aSelf aModifier do_elem_func ; // do_elem_proc MACRO elem_proc Literal IN aName %SUMMARY 'Procedure on model’s element' ; aName |N @SELF nil do_elem_proc ; // elem_proc MACRO elem_generator Literal IN aName %SUMMARY 'Element content generator' ; aName |N @SELF nil do_elem_proc ; // elem_generator MACRO elem_ref_proc Literal IN aName %SUMMARY 'Procedure on model’s element passed by reference' ; aName |N @SELF @ ^@ do_elem_proc ; // elem_ref_proc BOOLEAN elem_func IsSummary %SUMMARY ' Defines aWord as the documentation for the element ' ; // %SUMMARY ( Self |N ) = '%SUM' >>> Result ; // IsSummary BOOLEAN elem_func IsModelElement %SUMMARY ' Defines aWord as the element of the model ' ; // %SUMMARY NOT ( Self .IsSummary ) >>> Result ; // IsModelElement ARRAY elem_func Children %SUMMARY ' Returns child iterator aWord in terms of the specific model ' ; ( Self MembersIterator ) >filter> .IsModelElement >>> Result ; // Children INTEGER VAR g_Indent %REMARK 'Current indent' g_Indent := 0 BOOLEAN elem_func IsElementNeedIndent %SUMMARY 'Defines that the indent is needed' ; true >>> Result ; // IsElementNeedIndent elem_proc EnterElement %SUMMARY 'Begins element output' ; Self .IsElementNeedIndent ? INC g_Indent ; // EnterElement elem_proc LeaveElement %SUMMARY 'Ends element output' ; Self .IsElementNeedIndent ? DEC g_Indent ; // LeaveElement FILE VAR g_OutFile g_OutFile := nil STRING INTEGER ARRAY TYPE PRINTABLE PROCEDURE OutToFile PRINTABLE IN aValue %SUMMARY ' Outputs the value to the current output file and returns the carriage ' ; // %SUMMARY STRING VAR l_String if ( aValue IsArray ) then ( aValue strings:Cat >>> l_String ) else ( aValue ToPrintable >>> l_String ) [ g_Indent ' ' char:Dupe l_String ] strings:Cat g_OutFile File:WriteLn %REMARK '- outputs model’s elements to file instead of a standard device.' ; //OutToFile FUNCTOR TYPE GENERATOR %REMARK 'Element content generator' elem_proc Child.CallGen GENERATOR right aGen %SUMMARY 'Calls generator aGen on a CHILD element with indents' ; Self .EnterElement TRY Self aGen %REMARK 'Calls generator aGen' FINALLY Self .LeaveElement END // TRY..FINALLY ; // Child.CallGen CONST GEN_PROPERTY_PREFIX 'gp' %REMARK 'Prefix for generator property name' MACRO %GEN_PROPERTY Literal IN aName %SUMMARY 'Generator property' ; @SELF Ctx:SetWordProducerForCompiledClass axiom:PushSymbol CONST GEN_PROPERTY_PREFIX (+) ( aName |N ) Ctx:Parser:PushSymbol ; // %GEN_PROPERTY MACRO %GP Literal IN aName %SUMMARY 'The member of getting the generator property' ; axiom:PushSymbol :: GEN_PROPERTY_PREFIX (+) ( aName |N ) Ctx:Parser:PushSymbol ; // %GP STRING FUNCTION OutFileName STRING right aGeneratorName %SUMMARY 'File name for output' ; STRING VAR l_OutPath %REMARK 'Output path' sysutils:GetCurrentDir >>> l_OutPath [ l_OutPath script:FileName %REMARK 'Path to the current script' sysutils:ExtractFileName %REMARK 'Extracts the file name from the path' '' sysutils:ChangeFileExt %REMARK 'Remove .script' '' sysutils:ChangeFileExt %REMARK 'Remove .ms' ] '\' strings:CatSep >>> l_OutPath l_OutPath sysutils:ForceDirectories ?ASSURE ['Failed to create directory' l_OutPath ] %REMARK 'Creates directory recursively, if there is none' [ l_OutPath aGeneratorName ] '\' strings:CatSep >>> Result ; // OutFileName STRING VAR g_CurrentGeneratorName %REMARK 'Name of the current generator' g_CurrentGeneratorName := '' elem_proc CallGen GENERATOR RIGHT IN aGen %SUMMARY ' Calls aGen generator on the element and opens the “right files". ' ; // %SUMMARY aGen %GP Name >>> g_CurrentGeneratorName g_OutFile := ( OutFileName ( Self |N (+) '.' (+) g_CurrentGeneratorName ) File:OpenWrite ) TRY Self ( aGen DO ) %REMARK 'Calls aGen generator on the element' FINALLY g_OutFile := nil END // TRY..FINALLY ; // CallGen // --------------------------------------------------------------------------- elem_proc DumpAsIs %SUMMARY ' Printing procedure for model element content. Recursive. ' ; // %SUMMARY [ g_CurrentGeneratorName ':' %REMARK 'Outputs the name of the current generator for debugging' Self |S %REMARK 'Outputs the stereotype of the element' Self |N %REMARK 'Outputs the element name' ] ' ' strings:CatSep OutToFile TRY for ( Self .Children ) .Child.CallGen call.me %REMARK 'Outputs the element’s children with the same generator' FINALLY [ '; // ' Self |N ] OutToFile %REMARK 'Outputs the closing bracket of the element' END ; // DumpAsIs elem_generator dump %SUMMARY 'Output generator for of the model’s element’s dump.' ; %GEN_PROPERTY Name 'dump' Self .DumpAsIs ; // dump elem_generator pas %SUMMARY 'Generator to output model’s elements on Pascal.' ; %GEN_PROPERTY Name 'pas' Self .DumpAsIs ; // pas PROCEDURE CallGens ARRAY IN anElements %SUMMARY 'Calls specific generators on array elements anElements' ; for anElements ( ModelElement IN anElement anElement .CallGen .dump %REMARK 'Calls generator .dump on the element' anElement .CallGen .pas %REMARK 'Calls generator .pas on the element' ) ; // CallGens ARRAY VAR Generators Generators := [ @ .dump @ .pas ] ARRAY VAR Projects Projects := [ @ Project1 @ Project2 @ Project3 ] Projects CallGens %REMARK '- launches all the staff on the list of array elements.' ; // CodeGen CodeGen
Комментариев нет:
Отправить комментарий