Pull to refresh

Comments 25

Спасибо! В общих чертах представляю, но не использовал. Мы делаем идейно что-то подобное, но с другим назначением, и на входе немного другая модель, на выходе генерируется немного другой код.

Приходится часто сталкиваться со скепсисом. Для большинства людей EMFText, Xtext, QVTo и т.п. — это «какие-то сомнительные плагины, выдранные из не очень хорошей среды разработки Eclipse». И вообще, людям непонятно зачем нужны ещё какие-то языки, если то же самое можно написать на Java.
Приходится часто сталкиваться со скепсисом.

Такая особенность, понимаю…
Если группа специалистов пользуется удобным инструментом для решения своих задач, это не значит что эти инструменты будут популярными для всех. Для примера сравните популярность IDE Idea и MPS. Смиритесь и наслаждайтесь общением с теми кому полезно)

Тема действительно интересная!
Хорошая демонстрация возможностей Xtext — это язык Xtend.
Но все-таки сейчас основная тенденция для метамоделирования — это создание DSL-ей в рамках самого же языка. В основном используются три метода:
1. Создание DSL на основе системы типов языка и вспомогательных API (Builders). Scala особенно этим пестрит. Есть еще Groovy DSL, на основе которого построен Gradle, etc… Синтаксис Java не особо способствует созданию собственных DSL, хотя с появлением лямбд ситуация немного улучшилась.
2. Доступ к синтаксическому дереву на этапе компиляции. Для Scala есть scala.meta, в Java есть для этого AST-трансформации.
3. Генерация кода в рантайме. Очень популярно у многочисленных фреймворков. В основном служат для прозрачного добавления функционала к уже готовой модели.

Ну и еще один очень неплохой метод — использовать стандартные средства XML: XSD для метамоделирования, XML для моделирования и XSLT для трансформации.
Спасибо за комментарий, про Xtext я написал маловато. У него конечно больше отличий от EMFText. Для него есть язык описания выражений Xbase с трансляцией в Java-код. Xbase используется в Xtend, который вы упомянули. Также он используется в Xcore, о котором я писал немного раньше. И Xbase может использоваться в любом DSL, который транслируется в Java.

Вообще, если планируется создавать DSL на основе Java, то Xtext выглядит гораздо предпочтительней, чем EMFText. Но EMFText, на мой взгляд, проще и легче.

Я согласен, что DSL внутри языков сейчас очень популярны. Но не все DSL можно или нужно встраивать в какой-то язык программирования :) Например, SQL. В следующей статье я опишу парсер/генератор/редактор SQL на основе EMFText. А потом опишу транслятор из Anchor-моделей в SQL-код. Это как-раз пример задачи, в которой не нужно делать DSL внутри языка программирования.

XSLT отличная штука, но писать на нём сложные преобразования моделей не очень удобно. В одной из следующих статей я напишу про QVTo — это аналог XSLT для MOF-моделей. Кстати про отображение MOF-метамоделей в XSD-метамодели я тоже планирую статью. Если нужно парсить или генерить XML, то можно конечно делать что-то подобное, но можно проще.
UFO just landed and posted this here
Я сам в прошлом дотнетчик и тащился от linq :)
UFO just landed and posted this here
Не точно выразился, имел в виду встраивание SQL в чистом виде. LINQ — уже не совсем SQL, а какая-то вариация. Например, в следующей статье нам понадобятся выражения для создания таблиц, а в LINQ их как-раз нет.

Кстати, есть примеры DSL, которые встраиваются в другие языки без изменений. Например, OCL встроен в Acceleo, QVTo, ATL. Или XPath встраивается в XSLT, XSD. Арифметические выражения в разных языках примерно одинаковые. Такие микроDSL очень клёвые тем, что позволяют при создании нового языка не изобретать уже существующие вещи.

Это наверное обратный подход тому, который описал выше Throwable. Мы не строим DSL на основе языка программирования общего назначения. А наоборот, создаём новый язык в который встраиваем существующий микроDSL.
UFO just landed and posted this here
А вот такой вопрос, так как в проекте используется EMF, мы какую либо выгоду от этого имеем? Ну допустим вешая на какой либо класс emf адаптер, изменения будут слушаться? или как в Xtext модель постоянно уничтожается и создается заново?
Я не совсем понял вопрос :) Выгода от EMF или EMFText? Про смысл модельно-ориентированной разработки я планирую отдельную статью — в каких ситуациях стоит всё это использовать, в каких — нет.

Основная выгода от EMF — экономия времени на рутинном написании типового кода. Например, в одной из предыдущих статей мы описали модель в декларативном платформо-независимом виде:
image
Потратили на это не очень много времени. Затем нажали кнопку «сгенерировать исходный код» и получили целую кучу Java-классов, интерфейсов, фабрик со всякими геттерами, сеттерами и т.п.

Т.е. выгода:

  1. Экономия времени на написание типового кода.
  2. Сокращение вероятности ошибок в коде, потому что он генерится автоматически, уменьшена роль человеческого фактора.
  3. Упрощение сопровождения ПО. Например, через 50 лет (когда вместо Java будет какой-то более модный язык) мы просто снова нажмём кнопку «сгенерировать исходный код» и получим код уже на этом новом языке, не нужно будет переписывать тонны строк кода.
  4. Увеличение повторного использования. В этой статье мы использовали метамодель для генерации Java API и древовидного редактора, в этой статье эта же самая метамодель используется для создания графического редактора. Если мы захотим сделать DSL для таких моделей, то снова повторно используем ту же самую метамодель.
  5. Кросплатформенность. Можно генерить код на любом языке для любой платформы.
Про выгоду я понял, спасибо(имел ввиду EMF). Ну вот про адаптеры и отслеживания изменения в модели(через EAdapter).

Такой кейс: если мы перед запуском редактора (нашего DSL) помешаем слушателя(в понятиях EMF это EAdapter) на EntityModel.
Когда пользователь будет добавлять данные или еще как то изменить. Что будет происходить с моделью EntityModel? Она каждый раз будет заново создаваться (в xtext так)?
Да, судя по всему, при любом изменении исходного кода он полностью парсится и создаётся новая модель.

Тут люди спрашивали про инкрементальный парсинг, но из коробки этого нет.

Я в основном пользовался парсером и кодогенератором, чтобы делать транслятор с одного языка на другой:
1) парсим код на языке 1 в AST
2) преобразуем это AST в AST для языка 2
3) преобразуем второе AST в код на языке 2

Редактор использовал только для отладки (чтобы посмотреть правильно ли работает парсер и т.п.).

А зачем отслеживать изменения в модели? Можно сделать постобработчик, который принимает новую модель после парсинга и что-то с ней делает.
У меня задача стоит не совсем тривиальная. Необходим проекционный редактор в котором есть свой DSL, но не все данные можно ввести через этот DSL. И в самом редакторе когда мы встаем на какой либо объект(допустим в вашем примере пусть будет Entry) в PropertyView появляются редакторы таких скрытых сущностей. Ну и отсюда получается сложность: что если модель у нас перестаивается то сложно сохранять и сопоставлять такие данные. (не уверен что понятно описал)
А куда эти скрытые данные сохраняются?

Я бы попробовал разбить модель на две: 1) модель со скрытыми данными и 2) модель, которая генерится из исходного кода. Каждый раз при парсинге восстанавливал бы ссылки из 2-ой модели в 1-ую.
Да в данный момент все модели разбиты на 2 модели.
Сейчас реализовано с помощью Xtext + EMF Compare.
Вот только с восстановлением ссылок проблема есть. Не всегда можно после парсинга найти соответствие между моделями.
Допустим в языке есть конструкция |xxxx| и в один прекрасный момент мы изменили ее на |yyyy| не как взаимно однозначно найти не получиться нет не ID не какого то другого поля.
Ещё можно разрешать ссылки по контексту… Искать родительский объект с нужным ID, а потом дочерний нужного типа с определенным порядковым номером. Или искать не родительский, а предыдущий или последующий объект.

Или всё-таки сохранять эти скрытые данные в исходном коде, но скрывать средствами редактора, хотя я такого никогда не делал.

А что это за данные, если не секрет? Немного странно, что их можно редактировать в окне свойств, но нельзя в коде :)
Пишу редактор шаблонный конструкций (типа регулярок). Основные пользователи это лингвисты, поэтому слишком сложный язык им не нужен.

Простой пример: ищем слова со всеми возможными окончаниями, слово |писал|.
В шаблона нам нужно указать, что в конце может быть(а может и не быть) окончания, с длинной от 0 до 1. Или это слово должно быть зависимо от регистра. — примерно такие данные хранятся в «метаинформациии», там еще много всяких кейсов, которые сложно описать с помощью языка.


А можно пример с ID, EMFText после построения умеет выставлять ID? Как он отнесется к обмену 2 объектов местами?
Интересная штука, получается комбинированный редактор. Кстати, на что-то такое тут уже была ссылка (см. слайд на котором вместо switch/case в коде таблица).

EMFText обмен объектов местами не заметит: модель AST создаст с нуля, а о 2-ой модели со скрытыми данными он ничего не знает. Но в разрешателе ссылок можно реализовать какую угодно логику. В статье выше есть пример — класс FeatureTypeReferenceResolver. Метод resolve разрешает ссылку type у некоторого объекта класса Feature:

image

Для этого мы сначала от Feature (который передается в параметре container) переходим к EntityModel:

EntityModel model = (EntityModel) EcoreUtil.getRootContainer(container);


Потом находим в EntityModel некоторый Type с нужным идентификатором.

Но эта логика может быть совершенно другой. Во-первых, можем искать объект (на который хотим сослаться) в другой модели. Во-вторых, можем сделать что-то такое… Неважно какой идентификатор передали в параметре identifier. Вместо него смотрим порядковый номер текущего объекта класса Feature в AST. И потом ищем во второй модели нужный объект уже не по идентификатору, а с таким же порядковым номером.

Я не рекламирую EMFText, на самом деле в нём хватает косяков :) Но в Xtext, я думаю, это должно делаться аналогично.
По умолчанию Xtext (как и EMFText) разрешает ссылки по имени. Но это можно изменить, создав свой ILinkingService. Вот, обсуждение и пример.
Для Автора есть вопрос академического толка:
В статье (и не только в этой статье) понятие «метамодель языка UML» двойственно: в одном случае это язык описания моделей, а в другом — семантическая модель этого языка. Формально это не одно и то же.
Так вот вопрос, разделяет ли в статье Автор эти понятия (и может ли при помощи слов выразить разницу)?
Спасибо за вопрос! Я бы не сказал, что он сугубо академический. Это как раз один из ключевых моментов в данном цикле статей. У большинства людей UML ассоциируется с UML-диаграммами (классов, последовательностей, деятельности и т.п.) Хотя, в действительности, спецификация UML в основном описывает семантику языка. Диаграммы до версии 2.5 там приводились в основном для пояснения, иллюстрации. UML-модель может быть представлена в виде диаграммы, в виде человеко-читаемого текста, в виде XMI-файла или как-то ещё.

Причём, с этим связана одна серьёзная проблема. Например, мы создали UML-модель в одном инструменте моделирования и хотим открыть её в другом инструменте. Для этого можно использовать формат XMI. Спецификации UML и XMI единые, модель в принципе должна открываться в любом инструменте, который реализует эти спецификации. Но спецификация UML до версии 2.5 не описывала как UML-модели могут быть представлены в виде диаграмм. И в каждом инструменте используется какая-то своя метамодель для диаграмм. Т.е. UML-модель мы сможем открыть в любом инструменте, но представление этой модели в виде диаграммы придётся перерисовывать. Потому что UML-модель не содержит информацию о размере и расположении квадратиков и т.п.

Т.е. в случае с UML есть две метамодели:
1) «семантическая», которая содержит такие метаклассы как Class, Actor, Activity и т.п.
2) метамодель UML-диаграмм — UML Diagram Interchange (см. приложение B), которая содержит такие матаклассы как UMLDiaram, UMLDiagramElement, UMLLabel и т.п.

Когда я говорю о метамодели UML, я конечно имею в виду 1-ую. О разнице между этими двумя метамоделями я упоминал начиная с 1-ой статьи:
Если вы понимаете о чём идет речь, то до понимая того что такое метамодели вам остается ещё один шаг – понять чем являются прямоугольники и линии на диаграммах, и понять чем является xmi-файл с точки зрения моделирования.

Потом в этой статье мы разработали «семантическую» метамодель Anchor. А в следующей статье описали для Anchor одну из возможных нотаций — в виде диаграмм.

Т.е. граница между метамоделью, описывающей семантику, и метамоделью, описывающей синтаксис языка, совершенно чёткая.

Не очень чёткий термин «язык», потому что в нём есть и синтаксические и семантические составляющие. Например, я думаю на русском языке, но это же не значит мозг оперирует наборами каких-то кириллических символов. Или если я перепишу этот текст в транслите, он же всё-равно останется русским. Для меня термин «язык» всё-таки ближе к семантике. Т.е. UML-модель — это модель описанная в терминах классов, сценариев использования, актеров и т.п. Представлена эта модель может хоть в виде диаграммы, хоть в виде текста, всё-равно она остаётся UML-моделью. Поэтому я часто ставлю знак равенства между «метамоделью UML» и «языком UML» или «метамоделью языка UML». Для меня «язык описания моделей» — это не квадратики, стрелочки, кружочки, а набор терминов, концептов (классы, актёры и т.п.). Если речь идёт именно о конкретной форме представления этих (синтаксически нейтральных) концептов, то я обычно использую термин «нотация». В моём понимании диаграммы — это одна из возможных нотаций для языка UML, но не сам язык. С другой стороны, язык без нотации существовать не может, поэтому часто нотация и язык смешиваются, с чего я и начал этот безумно длинный комментарий :)

Всем этим занимается семиотика. Есть 1) некий объект, 2) есть концепт (абстракция, возникающая в мозге, соответствующая этому объекту) и 3) знак (последовательность букв, картинка, обозначающая этот объект). Спецификация UML описывает все возможные концепты. UML Diagram Interchange описывает все возможные знаки.
Иными словами тут несколько языков:

  1. Синтаксически нейтральный UML, который позволяет описывать объекты реального мира.
  2. UML Digram Interchange, который позволяет описывать UML-концепты, а не объекты реального мира, в терминах диаграмм, фигур, рёбер и т.п.
  3. PlantUML, который тоже позволяет описывать UML-концепты, но в виде текста, а не диаграмм.
  4. XMI, который тоже позволяет описывать UML-концепты, но в виде текста, предназначенного больше для машинной обработки, чем для человека.
Sign up to leave a comment.