JetBrains MPS для интересующихся #1

  • Tutorial

Введение


Спасибо всем за критику в комменте под первым постом, где я хотел попробовать написать про MPS, не затрагивая важные темы, чтобы можно было потом более качественно начать писать по порядку.


Зачем нам нужен язык Weather?


В комментариях к 1 посту было следующее высказывание


С этой точки зрения, DSL — это как фреймворк, только с более удобным интерфейсом. Ясное дело, под один проект фреймворк делать никто не будет, за исключением совсем уж монструозных случаев. А сделать его под конкретную предметную область — почему бы и нет?..

В принципе, так оно все и работает. Хорошие языки похожи по сути на хорошие фреймворки: они позволяют писать что-то важное, не заморачиваясь о том, что мы не хотим писать. По ходу повествования я буду периодически обращаться к другим языкам для аналогий и сравнений.


Синтаксис


Язык Weather, который мы хотим реализовать, должен выполнять следующую задачу: мы должны уметь лаконично выражать условия (погода сегодня, например) и следствия (погода завтра, послезавтра...).
В языке Weather мы будем делать наши прогнозы отталкиваясь от 1 фактора: от температуры на сегодняшний день(массив объектов время + погодные условия).


Пример массива входных данных на JS
const weatherInput = [
  {
    time: 1501179579253,
    temperature: {
        unit: "celsius",
        value: 23.7
     }
  },
 {
    time: 1501185944759,
    temperature: {
        unit: "fahrenheit",
        value: 15.3
     }
  }
]

Думаю сойдет.


Реализация на Weather
Weather prediction rules for Saint Petersburg
data Today:
  [21:23]{
    temperature = 23.7 °C
  }
  [23:06]{
    temperature = 15.3 °F
  }

У нас очень простые данные — время + температура в единицах измерения. Создадим абстрактный концепт WeatherTimedData — он нам нужен для хранения времени измерения и самой температуры.


image


Теперь нужно определить, что такое Temperature и Time.


image


Time реализован очень просто — у нас есть время в часах и минутах, а отображается оно как hh : mm.


image


Если с Time все понятно, то с Temperature немного нет. Во-первых — value это какой-то _FPNumber_String. На самом деле это MPS'овский double, так что ничего страшного. Но вопрос — как из интерфейса Temperature сделать реализации температуры в разных единицах измерения, да так чтобы это еще и красиво было? И вообще, что такое интерфейс концепт?
У таких концептов не может быть реализации в AST. То есть, вообще никакой. Только если другой концепт расширяет его, и никак иначе. Делается это, как и в ООП, для того, чтобы обобщить несколько классов под одно общее начало.


Вот как я реализовал отображение в редакторе для Temperature:


image


Здесь у нас первая ячейка — double значение, величина температуры, а вторая — Read-Only model access. Здесь мы немного отдаляемся от практики и переходим к теории.


Теория


В MPS все строится на концептах, если проводить прямую параллель с ООП, то концепты — это классы. Они могут расширять другие концепты, реализовывать интерфейсы, но еще они могут иметь какую-то логику. Например, если мы описываем абстрактный класс температуры, то нужно предусмотреть возможность задания собственных единиц измерения.


abstract class Temperature{
  abstract double value;
  public abstract String getUnit();

  override String toString(){
    return value + this.getUnit();
  }
}

Можно было бы задать unit как переменную, а не писать абстрактный метод, но…
Есть аспект, называется Behavior. Все, что он может делать — добавлять новые методы к концепту. То есть добавить переменную мы не можем, поэтому будем использовать абстрактный метод.


image


И вот после этого мы можем у каждой реализации концепта Temperature вызывать этот метод. Но где же его вызывать? Как вообще кодить в этом MPS?..


Снова практика


Мы остановились на том, что у нас есть непонятная ячейка в Editor аспекте — ReadOnly model access. Все очень просто — если нужно как-то логически обработать proeprty/children/reference перед тем, как его показывать, и на это не хватает встроенных приколов, то мы можем сами получить нужную строку из контекста редактора и реализации концепта. Если просто — нам дают текущий объект концепта, то есть реализованный, и мы можем из него получить все, что мы там понапихали. В данном случае мы хотим получить единицу измерения, поэтому мы нажимаем на ячейку R/O model access и пишем


image


Кстати, в любом месте кода вы можете тыкнуть на штучку, что Вас интересует и нажать Ctrl + Shift + T и получить информацию о типе этой штучки. Например, если мы нажмем на node в скрине выше и узнаем его тип, то мы получим


image


node<Название Концепта> = какая-то реализация концепта
concept<Название Концепта> = класс концепта
Так! Мы уже умеем составлять температуру по значению и единице измерения, но откуда мы возьмем, какая единица измерения нам нужна? Из дочерних реализаций, естественно.
Создаем пустой CelsiusTemperature концепт, расширяем Temperature и создаем для него behavior.


image


image


Как видно на последнем скрине, мы переопределяем метод getUnit(он имеется в зоне видимости из-за того, что мы наследовали концепт от Temperature) и возвраещем "°C". Все просто!


Остается только собрать все вместе в WeatherTimedData:


image


Собираем язык и смотрим на результат:


image


Вроде похоже на правду. Еще, конечно, нет самих предсказаний погоды, нет подсветки, к тому же часы у нас могут быть больше 24 и меньше нуля, минуты тоже не ограничены ничем, кроме размерности integer… В следующем посте ждите разъяснений по новому аспекту — constraints и еще чего-нибудь. А пока — пишите фидбек в комментариях, все как всегда, если вопрос простой — отвечаю там же, если он обширен и скорее как пожелание — то я постараюсь с каждым постом писать все качественнее. Спасибо за внимание!


//UPDATE\
Завел кривой репозиторий с проектом, где каждая ветка — новый туториал на Хабре. Это он!!!

Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 17

    0
    Самое интересное в погоде — ее предсказание. Расскажите, пожалуйста, будут ли у Вас свои модели, или данные будут браться из доступных «чужих» данных, NOAA, например?
      0

      Я не хочу делать предсказания осмысленными — цель уроков задеть как можно больше актуальных тем в MPS, а не написать готовый продукт.

      0
      Вы пишете в комменте под первым постом:

      > Например, потому что можно будет не переписывать код на другой ЯП в зависимости от платформы (на JavaScript, например, а писать на 1 языке и писать для него языки -расширения, которые будут переводить AST Weather в AST другого языка.

      Т.е. вот то, что мы написали, это можно автоматически транслировать в другой язык? Я правильно понимаю?
        0

        Да, если модель языка описана в MPS.Например, уже описана Java, она называется baseLanguage

        0

        Мне вот одно интересно, я один считаю, что MPS в текущем виде пользоваться практически невозможно? Ибо текст программы по существу графический, хоть и выглядит текстовым. Банально невозможно скопипастить текст чтоб спросить на форуме. Даже в этой статье в качестве примеров идут картинки, хотя Java класс Temperature идет текстом.

          0

          Скопировать текст можно без проблем, а вот со вставлением могут возникнуть небольшие проблемы: нужно будет вручную все dependencies зарезолвить. Я прикрепляю картинки чтобы читатель был в контексте MPS, а текстовая форма это как то… Отдаленно.

            0

            Пользоваться им и правда не всегда удобно. Только это проблема не MPS, а устаревших прочих инструментов.

              0
              Вообще, если покодить в нормальном режиме(не в режиме разработки нового языка, а в режиме разработки программ на языке из MPS), то через недельку шпилишь уже как в обычном текстовом редакторе.
            0

            Можно спросить, как мне скопипастить? Только что я поставил MPS 2017.1.2. У меня при старте открылся класс Main с тестовым примером. Я мечтаю его текст вставить сюда. И я не могу даже выделение сделать. Единственное что я смог сделать — это нажать preview generated text, но это не совсем то, что мне хочется.

              +1
              Используйте хоткей ctrl + w для выделения. Каждое новое нажатие ctrl + w выделяет текущий узел AST и родительский.

              Weather prediction rules for Saint Petersburg
              [ 21 : 23 ] {
              temperature = 23.3 °C
              }
              [ 22 : 15 ] {
              temperature = 80.2 °F
              }
                0

                Да ужжж. Конечно радует, что это можно сделать. Но очень не интуитивно, без подсказки я б точно не догадался. А мышкой это никак нельзя сделать?

                  +1
                  Я думаю, это сделано специально в силу того, что при копировании куска AST и вставления в другой редактор не было «пропавших кусков AST». То есть можно выделить только узлы. Ну и еще есть такая штука как кастомная проекция(Например, в sample проекте multipleProjections)
                  image
                  Я думаю не все текстовые редакторы поддерживают таблицы, но вот, как выглядел бы текст этой программы, если бы Вы его скопировали:
                  @export(namespace = fdfd)
                  workflow container org.jetbrains.workflow
                  tabular workflow simpleIssueTracking
                  event Close; event Reopen;

                  structural workflow advancedIssueTracking
                  event Close; event Verify; event Reopen;

                  state Open; -> Closed
                  state Open; -> Open

                  state Closed; -> Open
                  state WaitingVerification; -> Closed
                  -> Open

                  state Closed; -> Open

                    0

                    Ctrl+↑/↓

                      0
                      У меня работает только с ctrl + ↑ :c
                        0

                        Вверх — расширение выделения, вниз — наоборот.

                          0
                          И действительно, спасибо.
                0
                Не могли бы вы перелинковать статьи для более удобной навигации. Спасибо.

                Only users with full accounts can post comments. Log in, please.