Mps jetbrains что такое
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Open with Desktop
- View raw
- Copy raw contents Copy raw contents
Copy raw contents
Copy raw contents
Design your own Domain Specific Language with full development environment. Get code editor with completion, semantics and type checking with one click. Write generators to compile your DSL into multiple target languages, such as Java, C, XML, and many more.
Building MPS from sources
Download IntelliJ IDEA from the JetBrains website. Community edition will work just fine.
- Fork the MPS GitHub repository into your own space using the GitHub UI (go to the MPS repo and press the fork button at the top. This will create a fork of the repository in your github space).
- Clone your fork to your local machine: git clone git@github.com:/MPS.git. Depending on your internet connection, this may take a long time, MPS is big. Consider using the --depth git parameter to clone only part of the history of the project to save time and space.
- It is preferable to work in your own branch, so create a new branch to work in git checkout -b my_branch_name
- Open the project in IntelliJ IDEA (either Community or Ultimate Edition)
- Attach JB JDK 11 to the project
- Download latest JB JDK 11 for your OS and your version of MPS. Go to the MPS TeamCity site, scroll to the build configuration that corresponds to the MPS version that you are trying to build and locate the JDK distribution (e.g. 2021.3 -> Distribution -> Get Resources). Click on the Artifacts symbol of the last successful build of Get Resources and choose the distribution that you need. Make sure you grab jbrsdk not jbsdk.
- Main menu -> File -> Project Structure opens the Project Structure dialog
- Under Platform Settings -> SDK, add a new JDK named "JB JDK 11"
If you'd prefer a ready-to-use build, please head over to the Download page and grab an installation package of your choice.
MPS is licensed under the Apache 2 open-source license. See the complete MPS license agreement for full details.
To build JetBrains MPS from sources you need JDK 11. Older JDK versions are currently not supported for building MPS from sources.
IntelliJ IDEA Community or Ultimate edition shall be used to open the project. The versions of IntelliJ IDEA must reflect the version (branch) of the MPS project that you are opening:
MPS — это среда разработки языков программирования на платформе Intellij Idea. Она предоставляет возможность моделировать языки программирования, описывать структуры, сосредотачиваясь конкретно на дизайне и бизнес-логике, не отвлекаясь на парсеры, лексеры и различные сторонние фичи языка. Что нужно сразу обозначить: язык, который разрабатывается с помощью MPS, не компилируется в рабочую программу. Чаще всего он генерируется в модели других языков либо в текстовую форму.
Почему я решил написать этот пост? Я считаю, что это очень недооцененная возможность, а недооценена она потому что порог вхождения очень высок, плюс это один из самых непопулярных продуктов JetBrains.
Я планирую написать серию постов об этой замечательной среде, чтобы по окончанию прочтения у энтузиастов оставалось как можно меньше вопросов «как сделать эту штуку», и как можно больше понимания структуры, чтобы можно было эффективно пользоваться документацией. Познавать MPS мы будем во время создания языка для описания закономерностей погоды. Почему, собственно говоря, и нет?
Зачем нам нужен язык Weather?
С этой точки зрения, DSL — это как фреймворк, только с более удобным интерфейсом. Ясное дело, под один проект фреймворк делать никто не будет, за исключением совсем уж монструозных случаев. А сделать его под конкретную предметную область — почему бы и нет.
В принципе, так оно все и работает. Хорошие языки похожи по сути на хорошие фреймворки: они позволяют писать что-то важное, не заморачиваясь о том, что мы не хотим писать. По ходу повествования я буду периодически обращаться к другим языкам для аналогий и сравнений.
Теория
В MPS все строится на концептах, если проводить прямую параллель с ООП, то концепты — это классы. Они могут расширять другие концепты, реализовывать интерфейсы, но еще они могут иметь какую-то логику. Например, если мы описываем абстрактный класс температуры, то нужно предусмотреть возможность задания собственных единиц измерения.
Можно было бы задать unit как переменную, а не писать абстрактный метод, но…
Есть аспект, называется Behavior. Все, что он может делать — добавлять новые методы к концепту. То есть добавить переменную мы не можем, поэтому будем использовать абстрактный метод.И вот после этого мы можем у каждой реализации концепта Temperature вызывать этот метод. Но где же его вызывать? Как вообще кодить в этом MPS.
Снова практика
Мы остановились на том, что у нас есть непонятная ячейка в Editor аспекте — ReadOnly model access. Все очень просто — если нужно как-то логически обработать proeprty/children/reference перед тем, как его показывать, и на это не хватает встроенных приколов, то мы можем сами получить нужную строку из контекста редактора и реализации концепта. Если просто — нам дают текущий объект концепта, то есть реализованный, и мы можем из него получить все, что мы там понапихали. В данном случае мы хотим получить единицу измерения, поэтому мы нажимаем на ячейку R/O model access и пишем
Кстати, в любом месте кода вы можете тыкнуть на штучку, что Вас интересует и нажать Ctrl + Shift + T и получить информацию о типе этой штучки. Например, если мы нажмем на node в скрине выше и узнаем его тип, то мы получим
node = какая-то реализация концепта
concept = класс концепта
Так! Мы уже умеем составлять температуру по значению и единице измерения, но откуда мы возьмем, какая единица измерения нам нужна? Из дочерних реализаций, естественно.
Создаем пустой CelsiusTemperature концепт, расширяем Temperature и создаем для него behavior.Как видно на последнем скрине, мы переопределяем метод getUnit(он имеется в зоне видимости из-за того, что мы наследовали концепт от Temperature) и возвраещем "°C" . Все просто!
Остается только собрать все вместе в WeatherTimedData:
Собираем язык и смотрим на результат:
Вроде похоже на правду. Еще, конечно, нет самих предсказаний погоды, нет подсветки, к тому же часы у нас могут быть больше 24 и меньше нуля, минуты тоже не ограничены ничем, кроме размерности integer… В следующем посте ждите разъяснений по новому аспекту — constraints и еще чего-нибудь. А пока — пишите фидбек в комментариях, все как всегда, если вопрос простой — отвечаю там же, если он обширен и скорее как пожелание — то я постараюсь с каждым постом писать все качественнее. Спасибо за внимание!
//UPDATE\
Завел кривой репозиторий с проектом, где каждая ветка — новый туториал на Хабре. Это он.Design your own Domain Specific Language with full development environment. Get code editor with completion, semantics and type checking with one click. Write generators to compile your DSL into multiple target languages, such as Java, C, XML, and many more.
Building MPS from sources
Download IntelliJ IDEA from the JetBrains website. Community edition will work just fine.
- Fork the MPS GitHub repository into your own space using the GitHub UI (go to the MPS repo and press the fork button at the top. This will create a fork of the repository in your github space).
- Clone your fork to your local machine: git clone git@github.com:/MPS.git. Depending on your internet connection, this may take a long time, MPS is big. Consider using the --depth git parameter to clone only part of the history of the project to save time and space.
- It is preferable to work in your own branch, so create a new branch to work in git checkout -b my_branch_name
- Open the project in IntelliJ IDEA (either Community or Ultimate Edition)
- Attach JB JDK 11 to the project
- Download latest JB JDK 11 for your OS and your version of MPS. Go to the MPS TeamCity site, scroll to the build configuration that corresponds to the MPS version that you are trying to build and locate the JDK distribution (e.g. 2021.3 -> Distribution -> Get Resources). Click on the Artifacts symbol of the last successful build of Get Resources and choose the distribution that you need. Make sure you grab jbrsdk not jbsdk.
- Main menu -> File -> Project Structure opens the Project Structure dialog
- Under Platform Settings -> SDK, add a new JDK named "JB JDK 11"
If you'd prefer a ready-to-use build, please head over to the Download page and grab an installation package of your choice.
MPS is licensed under the Apache 2 open-source license. See the complete MPS license agreement for full details.
To build JetBrains MPS from sources you need JDK 11. Older JDK versions are currently not supported for building MPS from sources.
IntelliJ IDEA Community or Ultimate edition shall be used to open the project. The versions of IntelliJ IDEA must reflect the version (branch) of the MPS project that you are opening:
Концепция
MPS (дальше — среда / MPS) предоставляет возможность создавать модули двух типов — Language и Solution. Первый является описанием языка и его аспектов, второй используется для разработки каких-либо проектов, тестирования языка / языков, расширений языков.
Я начну с Language.
Самое важное, что нужно понять с начала, — это процесс разработки языка и что с ним происходит потом.
- Мы описываем модель языка и необходимые аспекты этого языка, например, систему типов, поведение в редакторе.
- Мы описываем, как модель нашего языка компилируется в текст или в модель другого языка.
- Мы собираем наш язык в плагин для Intellij Idea и используем его. Все переходы из одной модели в другую делаются за нас, в итоге мы получаем готовый скомпилированный код.
Итак, 1 статья — 1 кусок конечного проекта.
Синтаксис
Язык Weather, который мы хотим реализовать, должен выполнять следующую задачу: мы должны уметь лаконично выражать условия (погода сегодня, например) и следствия (погода завтра, послезавтра. ).
В языке Weather мы будем делать наши прогнозы отталкиваясь от 1 фактора: от температуры на сегодняшний день(массив объектов время + погодные условия).У нас очень простые данные — время + температура в единицах измерения. Создадим абстрактный концепт WeatherTimedData — он нам нужен для хранения времени измерения и самой температуры.
Теперь нужно определить, что такое Temperature и Time.
Time реализован очень просто — у нас есть время в часах и минутах, а отображается оно как hh : mm .
Если с Time все понятно, то с Temperature немного нет. Во-первых — value это какой-то _FPNumber_String . На самом деле это MPS'овский double, так что ничего страшного. Но вопрос — как из интерфейса Temperature сделать реализации температуры в разных единицах измерения, да так чтобы это еще и красиво было? И вообще, что такое интерфейс концепт?
У таких концептов не может быть реализации в AST. То есть, вообще никакой. Только если другой концепт расширяет его, и никак иначе. Делается это, как и в ООП, для того, чтобы обобщить несколько классов под одно общее начало.Вот как я реализовал отображение в редакторе для Temperature:
Здесь у нас первая ячейка — double значение, величина температуры, а вторая — Read-Only model access. Здесь мы немного отдаляемся от практики и переходим к теории.
Концепция
MPS (дальше — среда / MPS) предоставляет возможность создавать модули двух типов — Language и Solution. Первый является описанием языка и его аспектов, второй используется для разработки каких-либо проектов, тестирования языка / языков, расширений языков.
Я начну с Language.
Самое важное, что нужно понять с начала, — это процесс разработки языка и что с ним происходит потом.
- Мы описываем модель языка и необходимые аспекты этого языка, например, систему типов, поведение в редакторе.
- Мы описываем, как модель нашего языка компилируется в текст или в модель другого языка.
- Мы собираем наш язык в плагин для Intellij Idea и используем его. Все переходы из одной модели в другую делаются за нас, в итоге мы получаем готовый скомпилированный код.
Итак, 1 статья — 1 кусок конечного проекта.
Создаем проект в MPS
На данном этапе мы выбираем название проекта и название языка, также можно создать Sandbox solution — модуль, в котором мы будем смотреть, как работает наш язык.
У нас есть пустой проект. Совсем пустой. Но в языке WeatherPrediction есть вложенные директивы — structure, editor… Это аспекты языка — в них мы описываем поведение языка в разных ситуациях. Например, structure содержит основные концепты языка, а editor — то, как они будут отображаться в редакторе кода. Это должно звучать очень абстрактно, особенно если Вы еще не знакомы с MPS. Понимаю. Так что сразу в бой.
Сначала нам нужно объявить root концепт языка. В переводе на русский — мы создаем некую структуру, которая будет обобщать все другие структуры. В Java это был бы
Чтобы создать концепт, тыкаем ЛКМ по WeatherPrediction -> New -> Concept.
У концепта есть 3 типа данных, которые он может содержать:
-
properties — здесь можно хранить любые примитивные данные, аля строки, числа и boolean Абстрактный пример — целочисленная переменная, у которой должно быть name: string, value: integer, final: boolean
Что здесь происходит: Мы определяем концепт, называем его 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%.В первой ячейке — константный текст, во второй — , обращение к property по ключу name.
Пересобираем наш язык (Ctrl + F9) и смотрим в Sandbox solution, где мы до этого создали пустой PredicitonList по имени Saint Petersburg.
Все работает, AST то же самое, что и до наших модификаций.
На этом я, наверное, остановлюсь пока что, чтобы получить фидбек. В следующем посте я планирую добавить еще парочку концептов, а так же генерацию кода на Java.
Спасибо за внимание! Пожалуйста, все пожелания, непонятки и вопросы и пишите в комменты. Если вопросы конкретные и простые, отвечу в комментариях, иначе добавлю в следующий пост.
DSL-и (domain specific languages или языки для специфичных областей) известны программистам давно. Несмотря на это, они редко используются в реальных системах. В этой статье будет рассмотрено, что такое DSL-и, и почему они не получили широкого распространения. Также будет описано, как система JetBrains MPS решает проблемы, препятствующие их широкому использованию.
Так что же такое DSL? DSL это язык, созданный для решения задач в определенной предметной области. DSL-ями являются большинство декларативных языков, которые решают задачки в узких предметных областях. Например, SQL, регулярные выражения, XPath, Prolog, формулы в Excel. К сожалению, на этом список широко используемых DSL-ей заканчивается. Основное достоинство таких языков в том, что благодаря близости их конструкций к предметной области, код на этих языках очень ясен и краток. Более того, чтобы редактировать код на таких языках, не обязательно быть программистом. Если человек разбирается в предметной области, то он легко может писать код на таких языках благодаря своим знаниям.
В теории все выглядит просто: мы берем предметную область, скажем, бухгалтерский учет, пишем язык и даем его экспертам или используем сами для более краткого описания предметной области. К сожалению, такой подход не получил широкого распространения. Давайте посмотрим почему.
Почему DSL-и не получили широкого распространения?Давайте посмотрим на причины того, почему DSL-и не используются широко. Первая причина — авторы таких языков фокусируются на замкнутых языках только для одной конкретной проблемы, вместо того, чтобы расширять существующие языки программирования общего назначения, такие как Java, PHP, JavaScript. На это существует причина: возможность появления неоднозначностей при совмещении таких расширений друг с другом. Другая причина — сложность создания языковой инфраструктуры, необходимой для реализации языка, и комфортной работы с ним.
Большинство усилий в сообществе специалистов по DSL-ям направлено на работу с замкнутыми языками. Во многих случаях было бы полезней добавлять новые конструкции в существующие языки, например в Java. Представьте себе, что вы можете использовать расширения языков, так же, как вы используете библиотеки сейчас. При таком подходе разработчики смогут одновременно использовать выразительную силу DSL-ей и универсальность языков типа Java, что невозможно при использовании существующих технологий.
При создании расширений, для того, чтобы использовать их так же, как мы сейчас используем библиотеки, необходимо сделать языки совместимыми друг с другом. Это означает, что если мы добавляем в наш язык одно расширение, например, поддержку денег: тип для денег, литералы типа $10 или 100р, и другое расширение, которое добавляет в язык математические обозначения: суммы, произведения, итп, то мы сможем их использовать вместе, даже если они были созданы разными авторами.
К сожалению, все популярные языки программирования общего назначения основаны на текстовых грамматиках. У этих грамматик есть одно неприятное свойство: они могут быть неоднозначными, те возможно несколько интерпретаций одной и той же строки. Более того, если мы добавляем к Java новые конструкции при помощи расширения A, и добиваемся однозначности грамматики, а потом делаем то же самое с расширением B, может получиться так, что если мы возьмем Java и оба расширения, результирующая грамматика будет неоднозначной.
Давайте рассмотрим пример. Допустим, 2 компании решили добавить поддержку интерполяции строк (интерполяция строк позволяет писать выражения внутри строковых литералов) в Java. Допустим, первая компания использует такой синтаксис:
""
А вторая такой:
"$"
Если мы будем использовать оба расширения одновременно, и введем такую программу:
«Account balance is $»
то ее интерпретация неоднозначна. Является ли $ частью синтаксиса интерполяции, или частью строкового литерала? Пример несколько искусственен, но позволяет понять общую проблему неоднозначности, которая возникает при наличии похожего синтаксиса для разных конструкций.Чтобы добиться высокой производительности разработчика, необходимы интеллектуальные средства разработки. C появлением интеллектуальных редакторов, таких как в IntelliJ IDEA или в Eclipse, разработчикам бывает трудно переключится на редактирование текста в обычных редакторах. Текстовые редакторы не подсвечивают ошибки, не предоставляют контекстную помощь, не показывают меню с доступными вариантами, в них нет поддержки рефакторингов. Существуют фреймворки для создания интеллектуальных редакторов, например, IntelliJ IDEA Language API, XText, Oslo, но ни один из этих фреймворков не поддерживает расширяемые языки на должном уровне. Даже если нам не нужна расширяемость, создание поддержки языка с использованием этих средств требует хороших знаний в области языков программирования и занимает очень много времени. Как видно, инструментальная поддержка очень важна, но реализовать ее непросто.
Давайте подведем итог: люди занимаются не тем типом DSL-ей; для достижения увеличения производительности необходимо расширять существующие языки программирования общего назначения. Создавать же такие расширения сложно из-за того, что широко распространенные технологии не поддерживают совместимость расширений друг с другом.
Как JetBrains MPS решает указанные проблемыДавайте теперь посмотрим на то, как MPS решает указанные проблемы. Для того, чтобы поддержать совместимость расширений друг с другом, MPS не работает с программами как с текстом. Вместо этого, MPS хранит их как синтаксическое дерево, и редактирование происходит напрямую, без промежуточного использования текста. Такой подход позволяет существенно упростить создание IDE, поскольку постоянное наличие синтаксического дерева позволяет легко реализовать подсветку ошибок, автоматическое дополнение, контекстные подсказки итп.
MPS решает проблему неоднозначности радикальным способом: если у нас нет текстовой грамматики, то у нас нет и неоднозначности. Такой подход, однако, не означает, что в MPS не используются грамматики. Вместо конкретного синтаксиса, в определении языка в MPS определяется абстрактный синтаксис (структура синтаксического дерева). Если вы знакомы с XML, то наверное знаете об XML Schema, которая напоминает способ описания синтаксиса, используемый в MPS.
- collections language, который позволяет более просто работать с коллекциями
- dates language, который добавляет поддержку дат напрямую в Java
- math language, которые позволяет писать суммы, произведения, итп математически конструкции
Поскольку мы избавились от текстового представления, мы не можем использовать обычный текстовый редактор. Для работы с кодом мы используем специальный проекционный редактор. Для каждого узла синтаксического дерева, он создает проекцию — часть экрана с которой может взаимодействовать пользователь. При разработке MPS были приложены огромные усилия для того, чтобы такой редактор вел себя настолько близко к тестовому редактору, насколько это возможно. Например, если вы введете 1 + 2 + 3 в MPS, вы получите тоже синтаксическое дерево, которое было бы получено при разборе этой строки в Java. Конечно, проекционный редактор отличается от текстового, и существуют вещи, которые возможны в одном и невозможны в другом, и наоборот. Несмотря на это, к этим различиям можно привыкнуть, не теряя в производительности. По нашему опыту, требуется около 2-х недель чтобы стать продуктивным в проекционном редакторе.
Создание поддержки интеллектуального редактирования при работе с синтаксическим деревом напрямую сильно упрощается. Более того, во многих местах, интеллектуальные возможности предоставляются MPS IDE без каких либо усилий со стороны автора языка. Такие возможности, как автоматическое дополнение, поиск использований, переименование, работают автоматически. При разработке IntelliJ IDEA, была реализована поддержка интеллектуального редактирования для многих языков. Реализация такой поддержки потребовала больших усилий: несколько человеко месяцев на язык. С MPS аналогичные возможности могут быть реализованы в считанные дни. Это возможно, поскольку для разработки языков используются специальные языки, которые конфигурируют существующую языковую инфраструктуру. MPS это не просто редактор. Вы можете создать полноценную IDE с его помощью.
Внутри JetBrains мы используем MPS для разработки коммерческих проектов. Наша новая система учета ошибок, с кодовым именем Харизма, создана полностью на MPS, и это только начало.
ЗаключениеШирокому использованию DSL-ей мешают 2 проблемы: невозможность их повторного использования в системах на основе текстовых грамматик, и сложность создания интеллектуальных средств работы с ними. MPS решает обе эти проблемы путем работы с синтаксическим деревом напрямую, без промежуточного текстового представления, и предоставляя инфраструктуру для создания интеллектуальных средств работы с такими языками.
MPS 1.0 был выпущен в июле. Большая часть кода доступна под лицензией Apache 2.0 (за исключение JetBreains IDE Framework, лицензия которой позволяет использовать MPS в продуктах на основе MPS, не покупая каких бы то ни было лицензий у JetBrains).
P.S. Мы ищем старшего разработчика в проект. Подробности в вакансии в моем профиле.
Спасибо всем за критику в комменте под первым постом, где я хотел попробовать написать про MPS, не затрагивая важные темы, чтобы можно было потом более качественно начать писать по порядку.
Читайте также: