четверг, 20 августа 2015 г.

#1114. Пример того, что мы можем сделать с описанной моделью

Предыдущая серия была тут - Минимальный пример того, что мы можем сделать с описанной моделью.

Теперь расширим наш пример:

https://bitbucket.org/lulinalex/mindstream/src/1993baa5f2b16ac3f3e1bca85658740b3df8eb60/Examples/Scripts/CodeGeneration/CodeGen39.ms.script?at=B284


USES
 metaMACRO.ms.dict
;

Test CodeGen
 REMARK
  '
  CodeGen - это функция в которой мы будем тестировать наш функционал
  '

 REMARK
  '
  %SUMMARY это мета-информация, которая позволяет привязывать документацию
  к элементам кода. Эта документация доступна потом из скриптовой машины.
  '
 %SUMMARY '
 Тут будем тестировать построение сначала мета-модели, потом модели, а потом и
 кодогенерации
 '
 ; // %SUMMARY

// ---------------------------------------------------------------------------

meta-meta-model-begin
 'Тут будем определять аксиоматику мета-мета-модели, а потом вынесем её 
  в отдельный словарь.
 '

StereotypeStereotypeProducer meta
 %SUMMARY '
 Определяем базовый элемент мета-модели
 Тот самый который позволяет тащить всё остальное "за волосы из болота"
 Через этот примитив выводятся все остальные
 '
 ; // %SUMMARY 
; // meta

meta-meta-model-end

// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------

meta-model-begin
 'Тут будем определять аксиоматику мета-модели, а потом вынесем её 
  в отдельный словарь.

  Дальше будем определять понятия из UML - https://ru.wikipedia.org/wiki/UML

  Там бывают КАТЕГОРИИ и КЛАССЫ (Category и Class)

  На самом деле разница между ними - "призрачна", но раз умные дяди так решили, 
  то так тому и быть

  Вот с них и начнём:
  '
<<@meta>> UMLCategory
 %SUMMARY '
 Категория в терминах UML
 ' 
 ; // %SUMMARY 
; // UMLCategory

<<@meta>> UMLClass
 %SUMMARY '
 Класс в терминах UML
 ' 
 ; // %SUMMARY 
; // UMLClass

meta-model-end

// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------

concrete-model-begin 'Модель шаблонов'
 'Тут будем определять аксиоматику конкретной модели.
  Пока - "модели шаблонов". 
  А потом вынесем её 
  в отдельный словарь.
 '

<<UMLCategory>> Project
 %SUMMARY '
 Наверное у нас при разработке встречаются проекты.
 Так вот Project это стереотип, который описывает наши проекты.
 '
 ; // %SUMMARY
; // Project

<<UMLCategory>> Library
 %SUMMARY '
 Наверное у нас при разработке встречаются проектные библиотеки.
 Так вот Library это стереотип, который описывает наши библиотеки.
 '
 ; // %SUMMARY
; // Library

<<UMLCategory>> Programm
 %SUMMARY '
 Наверное у нас при разработке встречаются программы.
 Так вот Programm это стереотип, который описывает наши программы.
 '
 ; // %SUMMARY
; // Programm

<<UMLClass>> Class
 %SUMMARY '
 Наверное у нас при разработке встречаются проектные классы.
 Так вот Class это стереотип, который описывает наши проектные классы.
 '
 ; // %SUMMARY
; // Class

REMARK
 '
 Могут ли Library вкладываться в Project, а Project в Library
 Или могут ли Programm вкладываться в Class, а Class в Programm
 И прочие отношения между стереотипами - мы определим несколько позже.
 Когда начнём использовать их.
 '

model-end

// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------

concrete-model-begin 'Модель конкретного проекта'
 'Тут будем определять аксиоматику конкретной модели конкретного проекта.
  А потом вынесем её 
  в отдельный словарь.
 '
<<Project>> Project1
 %SUMMARY '
 Это наш первый проект - Project1
 '
 ; // %SUMMARY

 <<Library>> Library1
  %SUMMARY '
  Наверное наш проект содержит какие-то проектные библиотеки.
  Так вот Library1 - это наша первая проектная библиотека
  '
  ; // %SUMMARY
 ; // Library1

 <<Library>> Library2
  %SUMMARY '
  Наверное наш проект достаточно серьёзен и содержит НЕ ОДНУ библиотеку.
  Так вот Library2 - это наша вторая проектная библиотека.
  '
  ; // %SUMMARY
 ; // Library2

 <<Library>> Library3
  %SUMMARY '
  Наверное наш проект НАСТОЛЬКО серьёзен, что содержит даже НЕ ДВЕ библиотеки.
  Так вот Library3 - это наша третья проектная библиотека.
  '
  ; // %SUMMARY
 ; // Library3

 <<Programm>> Programm1
  %SUMMARY '
  Наверное наш проект реализует какую-то программу.
  Иначе - зачем бы он нам был бы нужен?
  Так вот Programm1 - это программа внутри нашего проекта Project1.
  '
  ; // %SUMMARY

  <<Class>> Class1
   %SUMMARY '
   Наверное наша программа содержит какие-то классы реализации.
   Иначе - кто будет реализовывать наш функционал?
   Так вот Class1 - это наш ПЕРВЫЙ класс реализации внутри нашей программы Programm1.
   '
   ; // %SUMMARY
  ; // Class1

  <<Class>> Class2
   %SUMMARY '
   Наверное наша программа достаточно серьёзна и содержит НЕ ОДИН классы реализации.
   Так вот Class2 - это наш ВТОРОЙ класс реализации внутри нашей программы Programm1.
   '
   ; // %SUMMARY
  ; // Class2

 ; // Programm1

; // Project1

REMARK
 '
  РЕМАРКА.
  Все эти слова "наверное" вообще говоря должны проистекать из требований, ТЗ и UseCase
  Но мы про это позже поговорим.
 '  
model-end

// ---------------------------------------------------------------------------

USES
 CodeDump.ms.dict
 // - тут подключаем словарь CodeDump.ms.dict, чтобы "увидеть" слово DumpElement
;

@SELF DumpElement
REMARK
 '
 - тут дампим элемент CodeGen и его содержимое
   в стандартное устройство вывода.
   Чисто для отладки того, что мы сейчас написали.
 '

help
REMARK
 '
 Выводим всю доступную аксиоматику в стандартное устройство вывода.
 Чисто для отладки того, что мы сейчас написали.
 '

REMARK
 '
 Теперь, что мы можем сделать с нашим проектом?
 Ну для начала выведем его содержимое на стандартное устройство вывода.
 '

TtfwWord TYPE ModelElement
REMARK 'Элемент модели'

BOOLEAN FUNCTION IsSummary
 ModelElement IN aWord
 %SUMMARY 
 '
  Определяет тот факт, что aWord является документацией к элементу
 '
 ; // %SUMMARY
 ( aWord |N ) = '%SUM' >>> Result
; // IsSummary

BOOLEAN FUNCTION IsModelElement
 ModelElement IN aWord
 %SUMMARY 
 '
  Определяет тот факт, что aWord является "элементом модели"
 '
 ; // %SUMMARY
 aWord IsSummary ! >>> Result
; // IsModelElement

ARRAY FUNCTION Children
 ModelElement IN aWord
 %SUMMARY 
 '
 Возвращает итератор детей aWord в "терминах определённой модели"
 '
 ;
 ( aWord MembersIterator ) >filter> IsModelElement >>> Result
; // Children

INTEGER VAR g_Indent
REMARK 'Текущий отступ'
g_Indent := 0

BOOLEAN FUNCTION IsElementNeedIndent
 ModelElement IN anElement
 %SUMMARY 'Определяет тот факт, что элементу нужен отступ' ;
 true >>> Result
; // IsElementNeedIndent

PROCEDURE EnterElement
 ModelElement IN anElement
 %SUMMARY 'Начинает вывод элемента' ;
 anElement IsElementNeedIndent ? INC g_Indent
; // EnterElement

PROCEDURE LeaveElement
 ModelElement IN anElement
 %SUMMARY 'Заканчивает вывод элемента' ;
 anElement IsElementNeedIndent ? DEC g_Indent
; // LeaveElement

FILE VAR g_OutFile
g_OutFile := nil

PROCEDURE OutToFile
 STRING IN aString 
 %SUMMARY 
 '
 Выводит строку в текущий файл вывода.
 С переводом каретки.
 '
 ; // %SUMMARY 
 [ g_Indent ' ' char:Dupe aString ] strings:Cat g_OutFile File:WriteLn
 REMARK '- выводим элементы модели в файл, а не в стандартный вывод.'
; //OutToFile

FORWARD DumpModelElement
REMARK 'FORWARD DumpModelElement используем для того, чтобы можно было вызывать DumpModelElement рекурсивно'
 
PROCEDURE DumpModelElement
 ModelElement IN aWord
 %SUMMARY 
 '
 Процедура печатающая содержимое элемента модели.
 Рекурсивно.
 '
 ; // %SUMMARY
 aWord |S OutToFile
 REMARK 'Выводим стереотип элемента'
 aWord |N OutToFile
 REMARK 'Выводим имя элемента'
 TRY
  for ( aWord Children ) (
   REMARK 'Выводим детей элемента'
   ModelElement IN aWord
   aWord EnterElement 
   TRY
    aWord DumpModelElement
    REMARK 'Вызываем рекурсивно сами себя'
   FINALLY
    aWord LeaveElement 
   END
  )
 FINALLY
  '; // ' (+) ( aWord |N ) OutToFile
  REMARK 'Выводим закрывающую скобку элемента'
 END
; // DumpModelElement

STRING FUNCTION OutFileName
 %SUMMARY 'Имя файла для вывода' ;
 script:FileName sysutils:ExtractFileName (+) '.dump' >>> Result
; // OutFileName

g_OutFile := ( OutFileName File:OpenWrite )
TRY
 @ Project1 DumpModelElement
 REMARK 'Выводим содержимое элемента'
FINALLY
 g_OutFile := nil
END

OutFileName Print
REMARK 'Выводим имя файла скрипта в тестовых целях'

; // CodeGen

CodeGen

Комментариев нет:

Отправить комментарий