Thank you all for the criticism in the comments under the first post , where I wanted to try to write about MPS, without touching on important topics, so that you can then begin to write better in order.
In the comments to post 1 was the following statement
From this point of view, DSL is like a framework, only with a more user-friendly interface. It's clear that no one will do the framework for a single project, except for very monstrous cases. And to make it under a specific subject area - why not? ..
In principle, this is how it all works. Good languages ​​are in fact similar to good frameworks: they allow you to write something important without bothering about what we don’t want to write. In the course of the story, I will periodically refer to other languages ​​for analogies and comparisons.
The Weather language that we want to implement must fulfill the following task: we must be able to concisely express the conditions (the weather today, for example) and the consequences (the weather tomorrow, the day after tomorrow ...).
In the Weather language, we will make our forecasts based on one factor: temperature today (an array of objects, time + weather conditions).
const weatherInput = [ { time: 1501179579253, temperature: { unit: "celsius", value: 23.7 } }, { time: 1501185944759, temperature: { unit: "fahrenheit", value: 15.3 } } ]
I think come down.
Weather prediction rules for Saint Petersburg data Today: [21:23]{ temperature = 23.7 °C } [23:06]{ temperature = 15.3 °F }
We have very simple data - time + temperature in units of measurement. Let's create an abstract concept WeatherTimedData - we need it to store the measurement time and the temperature itself.
Now we need to determine what Temperature and Time are .
Time is implemented very simply - we have time in hours and minutes, and it is displayed as hh : mm
.
If everything is clear with Time , there is little with Temperature . First, value is some kind of _FPNumber_String
. In fact, this is MPS'ovskih double, so do not worry. But the question is how to make temperature implementations in different units of measure from the Temperature interface, so much so that it is also beautiful? And in general, what is the interface concept?
Such concepts can not be implemented in the AST. That is, none at all. Only if another concept expands it, and nothing else. This is done, as in the PLO, in order to summarize several classes under one common beginning.
Here is how I implemented the display in the editor for Temperature :
Here we have the first cell - a double value, a temperature value, and the second is a Read-Only model access . Here we move away a bit from practice and move on to theory.
In MPS, everything is built on concepts; if we draw a direct parallel with OOP, then concepts are classes. They can extend other concepts, implement interfaces, but they can also have some kind of logic. For example, if we describe an abstract temperature class, then we need to provide for the possibility of specifying our own units of measurement.
abstract class Temperature{ abstract double value; public abstract String getUnit(); override String toString(){ return value + this.getUnit(); } }
It would be possible to set unit as a variable, and not to write an abstract method, but ...
There is an aspect called Behavior . All he can do is add new methods to the concept. That is, we cannot add a variable, so we will use an abstract method.
And after that we can call this method on every implementation of the Temperature concept. But where is it to call? How do you code in this MPS? ..
We stopped at the fact that we have an incomprehensible cell in the Editor aspect - ReadOnly model access. It's very simple - if you need to somehow logically handle proeprty / children / reference before showing it, and the built-in jokes are not enough, then we can get the necessary string from the editor context and the concept implementation. If it is simple - they give us the current object of the concept, that is, a realized one, and we can get from it everything that we have there. In this case, we want to get a unit of measurement, so we click on the R / O model access cell and write
By the way, anywhere in the code you can poke a little thing that interests you and press Ctrl + Shift + T and get information about the type of this thing. For example, if we click on node in the screenshot above and find out its type, we will get
node< >
= some kind of concept implementation
concept< >
= concept class
So! We already know how to compile temperature by value and unit of measurement, but where do we get from, what unit of measurement do we need? From child implementations, naturally.
Create an empty CelsiusTemperature concept, extend the Temperature, and create a behavior for it.
As seen on the last screenshot, we override the getUnit method (it is in view of the fact that we inherit the concept from Temperature ) and return "°C"
. It's simple!
It remains only to put everything together in WeatherTimedData :
Putting the language and looking at the result:
It seems to be true. Still, of course, there are no weather predictions themselves, no backlighting, besides, we can have more than 24 hours and less than zero, minutes are also not limited by anything except the integer dimension ... In the next post, wait for explanations on the new aspect - constraints and something someday In the meantime, write feedback in the comments, everything is as usual, if the question is simple, I answer there, if it is extensive and more like a wish, then I will try to write with every post more qualitatively. Thanks for attention!
// UPDATE \
I got a curve repository with a project, where each branch is a new tutorial on Habré. It's him!!!
Source: https://habr.com/ru/post/334308/