Введение
MPS — это среда разработки языков программирования на платформе Intellij Idea. Она предоставляет возможность моделировать языки программирования, описывать структуры, сосредотачиваясь конкретно на дизайне и бизнес-логике, не отвлекаясь на парсеры, лексеры и различные сторонние фичи языка. Что нужно сразу обозначить: язык, который разрабатывается с помощью MPS, не компилируется в рабочую программу. Чаще всего он генерируется в модели других языков либо в текстовую форму.
Почему я решил написать этот пост? Я считаю, что это очень недооцененная возможность, а недооценена она потому что порог вхождения очень высок, плюс это один из самых непопулярных продуктов JetBrains.
Документация очень подробная, описывает все возможности, но если нет осознания «что я делаю и зачем мне это делать», то она вряд ли будет полезна. Также есть серия уроков от JetBrains на YouTube, но опять же, я более-менее начал понимать, что происходит, только после двух просмотров всей серии и досканального изучения предлагаемых sample проектов.
Я планирую написать серию постов об этой замечательной среде, чтобы по окончанию прочтения у энтузиастов оставалось как можно меньше вопросов «как сделать эту штуку», и как можно больше понимания структуры, чтобы можно было эффективно пользоваться документацией. Познавать MPS мы будем во время создания языка для описания закономерностей погоды. Почему, собственно говоря, и нет?
Концепция
MPS (дальше — среда / MPS) предоставляет возможность создавать модули двух типов — Language и Solution. Первый является описанием языка и его аспектов, второй используется для разработки каких-либо проектов, тестирования языка / языков, расширений языков.
Я начну с Language.
Самое важное, что нужно понять с начала, — это процесс разработки языка и что с ним происходит потом.
- Мы описываем модель языка и необходимые аспекты этого языка, например, систему типов, поведение в редакторе.
- Мы описываем, как модель нашего языка компилируется в текст или в модель другого языка.
- Мы собираем наш язык в плагин для Intellij Idea и используем его. Все переходы из одной модели в другую делаются за нас, в итоге мы получаем готовый скомпилированный код.
Следует заметить, что написание кода в формате MPS немного отличается от написания текста программы, потому что мы на самом деле редактируем AST (Abstract Syntax Tree), а то, что мы видим в редакторе кода — проекция AST.
Итак, 1 статья — 1 кусок конечного проекта.
Создаем проект в MPS
На данном этапе мы выбираем название проекта и название языка, также можно создать Sandbox solution — модуль, в котором мы будем смотреть, как работает наш язык.
У нас есть пустой проект. Совсем пустой. Но в языке WeatherPrediction есть вложенные директивы — structure, editor… Это аспекты языка — в них мы описываем поведение языка в разных ситуациях. Например, structure содержит основные концепты языка, а editor — то, как они будут отображаться в редакторе кода. Это должно звучать очень абстрактно, особенно если Вы еще не знакомы с MPS. Понимаю. Так что сразу в бой.
Сначала нам нужно объявить root концепт языка. В переводе на русский — мы создаем некую структуру, которая будет обобщать все другие структуры. В Java это был бы
public class Weather{
}
Чтобы создать концепт, тыкаем ЛКМ по WeatherPrediction -> New -> Concept.
У концепта есть 3 типа данных, которые он может содержать:
- properties — здесь можно хранить любые примитивные данные, аля строки, числа и boolean Абстрактный пример — целочисленная переменная, у которой должно быть name: string, value: integer, final: boolean
- children — здесь хранятся элементы других концептов. Как абстрактный пример, для концепта Program туда можно было бы пихнуть массив Statement
- references — здесь хранятся ссылки на другие реализованные концепты в AST, которые есть в текущем scope. Абстрактный пример — переменная, у которой значение — ссылка на другую переменную по имени( в реальности это не совсем так, но это же абстрактный пример).
Назовем его PredictionList, определим его как root концепт и наследуем интерфейс INamedConcept.
Что здесь происходит: Мы определяем концепт, называем его PredictionList, говорим, что его можно реализовать как root концепт и наследуемся от INamedConcept. Если посмотреть на его definition (Ctrl + B)
то мы увидим, что это interface concept, у которого есть property name: string, что, собственно говоря, логично из названия
Обратите внимание, что синтаксис похож на язык программирования. Это так: этот код написан на языке jetbrains.mps.lang.structure, который описывает концепты языка.
Если мы сейчас соберем проект и захотим посмотреть, что получилось, то нам нужно будет создать модель в модуле WeatherPrediction.sandbox.
ЛКМ на sandbox(generation required) -> New -> PredictionList
Заменим no name на Saint Petersburg
Бум! У нас есть дефолтная визуализация концепта. Чтобы посмотреть AST, нажмите на любое место в редакторе и нажмите хоткей Alt + X
Здесь видна структура всего всего, это очень круто и удобно отслеживать состояние дерева. Сразу видим, что name у PredictionList = Saint Petersburg. Так, это очень здорово, но мы же хотим чтобы все было по красоте, поэтому мы открываем редактор концепта PredictionList и создаем ему editor aspect. Нажимаем на зеленый плюсик в нижнем списке, прямо под кодом нашего концепта, выбираем Editor -> Concept Editor
Здесь мы можем описать то, как будет отображаться наш PredictionList в редакторе кода.
Пока не будем вдаваться в подробности, как тут это все сделано, просто пишем [- и у нас создается массив ячеек. Все просто: в каждой ячейке — какой то константный текст / property / reference / children. И да, отображение описывается другим языком — jetbrains.mps.lang.editor.
Мы хотим, чтобы наш список предсказаний погоды выглядел следующим образом:
Weather prediction rules for %name%.
Так и пишем.
В первой ячейке — константный текст, во второй — {name}, обращение к property по ключу name.
Пересобираем наш язык (Ctrl + F9) и смотрим в Sandbox solution, где мы до этого создали пустой PredicitonList по имени Saint Petersburg.
Все работает, AST то же самое, что и до наших модификаций.
На этом я, наверное, остановлюсь пока что, чтобы получить фидбек. В следующем посте я планирую добавить еще парочку концептов, а так же генерацию кода на Java.
Спасибо за внимание! Пожалуйста, все пожелания, непонятки и вопросы и пишите в комменты. Если вопросы конкретные и простые, отвечу в комментариях, иначе добавлю в следующий пост.
Автор: enchantinggg