Введение
Спасибо всем за критику в комменте под первым постом, где я хотел попробовать написать про MPS, не затрагивая важные темы, чтобы можно было потом более качественно начать писать по порядку.
Зачем нам нужен язык Weather?
В комментариях к 1 посту было следующее высказывание
С этой точки зрения, DSL — это как фреймворк, только с более удобным интерфейсом. Ясное дело, под один проект фреймворк делать никто не будет, за исключением совсем уж монструозных случаев. А сделать его под конкретную предметную область — почему бы и нет?..
В принципе, так оно все и работает. Хорошие языки похожи по сути на хорошие фреймворки: они позволяют писать что-то важное, не заморачиваясь о том, что мы не хотим писать. По ходу повествования я буду периодически обращаться к другим языкам для аналогий и сравнений.
Синтаксис
Язык Weather, который мы хотим реализовать, должен выполнять следующую задачу: мы должны уметь лаконично выражать условия (погода сегодня, например) и следствия (погода завтра, послезавтра...).
В языке Weather мы будем делать наши прогнозы отталкиваясь от 1 фактора: от температуры на сегодняшний день(массив объектов время + погодные условия).
const weatherInput = [
{
time: 1501179579253,
temperature: {
unit: "celsius",
value: 23.7
}
},
{
time: 1501185944759,
temperature: {
unit: "fahrenheit",
value: 15.3
}
}
]
Думаю сойдет.
Weather prediction rules for Saint Petersburg
data Today:
[21:23]{
temperature = 23.7 °C
}
[23:06]{
temperature = 15.3 °F
}
У нас очень простые данные — время + температура в единицах измерения. Создадим абстрактный концепт WeatherTimedData — он нам нужен для хранения времени измерения и самой температуры.
Теперь нужно определить, что такое Temperature и Time.
Time реализован очень просто — у нас есть время в часах и минутах, а отображается оно как hh : mm
.
Если с Time все понятно, то с Temperature немного нет. Во-первых — value это какой-то _FPNumber_String
. На самом деле это MPS'овский double, так что ничего страшного. Но вопрос — как из интерфейса Temperature сделать реализации температуры в разных единицах измерения, да так чтобы это еще и красиво было? И вообще, что такое интерфейс концепт?
У таких концептов не может быть реализации в AST. То есть, вообще никакой. Только если другой концепт расширяет его, и никак иначе. Делается это, как и в ООП, для того, чтобы обобщить несколько классов под одно общее начало.
Вот как я реализовал отображение в редакторе для Temperature:
Здесь у нас первая ячейка — 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. Все, что он может делать — добавлять новые методы к концепту. То есть добавить переменную мы не можем, поэтому будем использовать абстрактный метод.
И вот после этого мы можем у каждой реализации концепта Temperature вызывать этот метод. Но где же его вызывать? Как вообще кодить в этом MPS?..
Снова практика
Мы остановились на том, что у нас есть непонятная ячейка в Editor аспекте — ReadOnly model access. Все очень просто — если нужно как-то логически обработать proeprty/children/reference перед тем, как его показывать, и на это не хватает встроенных приколов, то мы можем сами получить нужную строку из контекста редактора и реализации концепта. Если просто — нам дают текущий объект концепта, то есть реализованный, и мы можем из него получить все, что мы там понапихали. В данном случае мы хотим получить единицу измерения, поэтому мы нажимаем на ячейку R/O model access и пишем
Кстати, в любом месте кода вы можете тыкнуть на штучку, что Вас интересует и нажать Ctrl + Shift + Enter и получить информацию о типе этой штучки. Например, если мы нажмем на node в скрине выше и узнаем его тип, то мы получим
node<Название Концепта>
= какая-то реализация концепта
concept<Название Концепта>
= класс концепта
Так! Мы уже умеем составлять температуру по значению и единице измерения, но откуда мы возьмем, какая единица измерения нам нужна? Из дочерних реализаций, естественно.
Создаем пустой CelsiusTemperature концепт, расширяем Temperature и создаем для него behavior.
Как видно на последнем скрине, мы переопределяем метод getUnit(он имеется в зоне видимости из-за того, что мы наследовали концепт от Temperature) и возвраещем "°C"
. Все просто!
Остается только собрать все вместе в WeatherTimedData:
Собираем язык и смотрим на результат:
Вроде похоже на правду. Еще, конечно, нет самих предсказаний погоды, нет подсветки, к тому же часы у нас могут быть больше 24 и меньше нуля, минуты тоже не ограничены ничем, кроме размерности integer… В следующем посте ждите разъяснений по новому аспекту — constraints и еще чего-нибудь. А пока — пишите фидбек в комментариях, все как всегда, если вопрос простой — отвечаю там же, если он обширен и скорее как пожелание — то я постараюсь с каждым постом писать все качественнее. Спасибо за внимание!
//UPDATE\
Завел кривой репозиторий с проектом, где каждая ветка — новый туториал на Хабре. Это он!!!
Комментарии (16)
isden
28.07.2017 09:15Вы пишете в комменте под первым постом:
> Например, потому что можно будет не переписывать код на другой ЯП в зависимости от платформы (на JavaScript, например, а писать на 1 языке и писать для него языки -расширения, которые будут переводить AST Weather в AST другого языка.
Т.е. вот то, что мы написали, это можно автоматически транслировать в другой язык? Я правильно понимаю?enchantinggg
28.07.2017 12:07Да, если модель языка описана в MPS.Например, уже описана Java, она называется baseLanguage
elmal
28.07.2017 12:26Мне вот одно интересно, я один считаю, что MPS в текущем виде пользоваться практически невозможно? Ибо текст программы по существу графический, хоть и выглядит текстовым. Банально невозможно скопипастить текст чтоб спросить на форуме. Даже в этой статье в качестве примеров идут картинки, хотя Java класс Temperature идет текстом.
enchantinggg
28.07.2017 12:37Скопировать текст можно без проблем, а вот со вставлением могут возникнуть небольшие проблемы: нужно будет вручную все dependencies зарезолвить. Я прикрепляю картинки чтобы читатель был в контексте MPS, а текстовая форма это как то… Отдаленно.
GooRoo
28.07.2017 21:43Пользоваться им и правда не всегда удобно. Только это проблема не MPS, а устаревших прочих инструментов.
enchantinggg
28.07.2017 23:17Вообще, если покодить в нормальном режиме(не в режиме разработки нового языка, а в режиме разработки программ на языке из MPS), то через недельку шпилишь уже как в обычном текстовом редакторе.
elmal
28.07.2017 13:02Можно спросить, как мне скопипастить? Только что я поставил MPS 2017.1.2. У меня при старте открылся класс Main с тестовым примером. Я мечтаю его текст вставить сюда. И я не могу даже выделение сделать. Единственное что я смог сделать — это нажать preview generated text, но это не совсем то, что мне хочется.
enchantinggg
28.07.2017 13:45+1Используйте хоткей ctrl + w для выделения. Каждое новое нажатие ctrl + w выделяет текущий узел AST и родительский.
Weather prediction rules for Saint Petersburg
[ 21 : 23 ] {
temperature = 23.3 °C
}
[ 22 : 15 ] {
temperature = 80.2 °F
}
elmal
28.07.2017 14:27Да ужжж. Конечно радует, что это можно сделать. Но очень не интуитивно, без подсказки я б точно не догадался. А мышкой это никак нельзя сделать?
enchantinggg
28.07.2017 14:35+1Я думаю, это сделано специально в силу того, что при копировании куска AST и вставления в другой редактор не было «пропавших кусков AST». То есть можно выделить только узлы. Ну и еще есть такая штука как кастомная проекция(Например, в sample проекте multipleProjections)
Я думаю не все текстовые редакторы поддерживают таблицы, но вот, как выглядел бы текст этой программы, если бы Вы его скопировали:
@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
GooRoo
28.07.2017 21:44Ctrl+^/v
enchantinggg
28.07.2017 23:16У меня работает только с ctrl + ^ :c
BOOTor
Самое интересное в погоде — ее предсказание. Расскажите, пожалуйста, будут ли у Вас свои модели, или данные будут браться из доступных «чужих» данных, NOAA, например?
enchantinggg
Я не хочу делать предсказания осмысленными — цель уроков задеть как можно больше актуальных тем в MPS, а не написать готовый продукт.