
Our starting point will be the project, resulting in the writing of the
last article .
So, we have at our disposal a small module written in AS (two strings framed in different quotes), the language
myLanguages.escapedStrings , in which there are only two automation scripts related to the
Intentions aspect: one processes the string in single quotes, and the other - string in double quotes.

Perhaps, the implementation of this code cannot be called ideal, but it is a working example of a simple and effective solution of the task set before us: using the
Intentions language, we can easily add new functionality to the editor. The same way can be implemented slightly differently, but it is the
Intentions that is the fastest and easiest.
')
With a slight sadness, we look at our experimental string, flavored with a large number of slashes. On the one hand, the problem is solved, but on the other - somehow ugly, wrong. Why not suggest some simple way in which our string would remain the same, but would not cause the error "Incorrect string literal"? There is nothing easier. Recall that in some other languages ​​there is a similar functionality - for example, in C # for such there is a convenient
@ "..." construction, which would be quite suitable for us to port as a language extension in ActionScript.
Do not forget that in RASE, the source code of the application (taking into account all the extensions used) is first processed by the generator, which creates the source code that the ActionScript compiler understands. That is, we will be able to work with our line unchanged, but it will only undergo automatic screening at the time of generation.
Step 1. For the work, comrades!You must create a new expression. To do this, go to our language extension and in the
structure aspect create a new concept.

Enter the name of the concept -
EscapedString .

Then the question arises, which entity will it expand? To answer it, you can try a little research. If our string is enclosed in double quotes, then it is of type
StringLiteral , and if in single quotes, then
StringApostropheLiteral . This assumption is easily confirmed by calling the context menu of our line and selecting
Go to Concept Declaration (which is equivalent to the keyboard shortcut
Ctrl-Shift-S or
Cmd-Shift-S on the Mac).


In order to finally determine which concept will expand our
EscapedString , you can again look at the context menu of the
StringLiteralBase type and look at how it looks within the framework of the object hierarchy.


We see that
StringLiteralBase , for which
StringLiteral and
StringApostropheLiteral are children , is itself inherited from
Expression , implementing the IStringLiteral interface.

Having studied the structure and methods of the
StringLiteralBase concept, we decide to inherit from
Expression with the
IStringLiteral interface and get up one level with the
StringLiteralBase. Go back to our unfinished root and enter (note the spelling supported by the “smart” autocomplete by
Ctrl-Space ):

In the window with the hierarchy, the change will immediately be reflected in the displayed tree:

Moving on. The next step is to add an alias in the same window with our concept. It will be used for autocomplete (to add a construction to the code, the user must enter the “@” character). For the same purpose, add a
shortDescription (this is the description to the right of the alias in the auto-click menu).
Step 2. Creating an editorWe proceed to the creation of the editor (in the next tab).

We create in it a visual representation of our future construction - enclosed in quotes
value , before the quotes there is the symbol
@
Constant in our screenshot is a special cell in which the plain text is stored. “Const” and
“ctrl + space” will soon become your frequent action when creating an editor.
Add another cell (
Enter ) and select from the list of autocomplex
“{value}”
Add one more constant quotation.
At this stage, the new module makes sense to compile the first time. Press
Ctrl-F9 (
Cmd + F9 ) or select
Build> Make Module (s) in the main menu, then go to
Main () to create an example with a new line.
We enter the text starting with the
@ symbol (hooray! The autocompet is already running, which was set using the alias in the
Structure section at the end of the first step), but notice that our design looks somehow unexpectedly strange.

Step 3. Restoring orderTo remove extra spaces, go back to the tab in which the editor was created, and pay attention to the
Inspector window, in which the styles of each element appear. You may notice that each element of our design has its own set of properties.

Remove the space between the
@ and the opening quote. To do this, select the "doggy" symbol and add the following property to the basic style:

In order not to bother with the next invention of the bike when making quotes, we can look at the already working code and see how it is done in the similar tab in
StringLiteralBase .


There, these styles are called
StringQuotationOpen and
StringQuotationClose respectively . Copy them into your code. And for the properties of the
value field in our source, the following structure is responsible:

Again we compile the language extension module and go to the
Main () class. Quite another thing !.
Step 4. Code generationNow it would be curious to look at the AS code in which our expression is generated. From the context menu of the editor, select
Generate (obsolete)> Generate Text From Current Model (by the way, the same action is available at the bottom of the
Build section of the main menu).

The generated code can be viewed in the lower left corner of the screen in the
Output window. What do we see there?

The message “
TexGen not found ” means: the editor cannot find the generator corresponding to our language extension. Oh yes: we haven't written it yet.

Add a new generator in the same way that we created every new aspect of our expansion. Usually the name for the generator is chosen by the name of the target language, into which it will convert our code. In our case, this language will be ActionScript.

Obviously, the chosen name itself does not indicate its purpose, therefore, using the context menu, go to the properties of this aspect and in the lower window of the
Dependencies tab (full path
Generator Properties> Dependencies> Depends on Generator ) we specify its dependence on the ActionScript language.

In the third tab of the generator properties, we indicate at what stage in the chain of code generation of the entire project we will use it. In our case,
before ActionScript.

The settings are set, you can proceed to the description of the generator logic. We return to the
root EscapedString . Clicking on the empty field in the
Generator tab, we call
Template Declaration .

Two tabs open to our gaze: the first is called
main , and the second is
reduce_EscapedString . As you can guess, the first one contains the general rules for our design, and the second - direct operations on it.


Go to the
reduce_EscapedString tab and insert the following construction:

We receive the code of a usual line.
Template Fragment (available by pressing the
Ctrl-Shift-F key combination or via the
Alt-Enter drop-down menu), this is a piece of code or text that we later insert into the generated code.

A generator template annotation appeared around our line.

Now we need to place the value in the generated string, for which we add the
property macro to our line (we select the ready template from the intention list for
node.value ):


As a result, if the module was compiled and the code was generated from
Main (), we would get the following semi-finished product:

As we can see, the generator so far drives out normal unscreened text.
In order to add screening functionality, put the cursor on the
“$” symbol and open the
Inspector window. We start writing code that will change the value of our string when generating:

However, we will not describe the entire screening process in the
property macro , since it is better to create a method at the
EscapedString construction
itself and call it from a macro. To create methods for concepts, the
Behavior aspect is specifically designed, in which we will create the
escape () method.
Step 5. The Behavior AspectNow we need to add the
escape () method to our concept.
Using the familiar gesture through the context menu of our language
myLanguages.escapedStrings ,
we add the
Behavior aspect to the project
.
Our task is to get a valid line at the output, with all the necessary slashes.

Select
this. value , using the corresponding item from the refactor menu or using the keyboard shortcut
Ctrl-Alt-V (
Cmd-Alt-V ), we turn it into the local variable
result , which will be output by our method.



In order not to complicate the task, the working code will be posed from the example of
Intentions given in the previous article. In the editor, for this there is a keyboard shortcut Ctrl-E (
Cmd-E ), calling the window with a list of recently opened files.

Without further ado, we copy lines of code from one root to another (when copying, RASE will ask us about import, but we will choose
Import None ). If you created a project from scratch, and not based on a learning project, do not forget to import the
Regexp language using the
Ctrl-L shortcut (
Cmd-L ).
In the end, after several fixes, our source should look like this:

In order for the resulting code to work, it remains for us to return to the
Generator aspect, where we should change the
node in the Inspector
. value on
node. escape () .


Compile the module, generate the ActionScript and look at the result.
Step 6. Type for Node windowWe have achieved some success in creating educational language expansion, but it is impossible not to notice that the result was a bit strange. Why? Because from our line so far a little practical use, and even if you take a closer look, in the current intermediate result, we did not get a string (type
String ), but in general
it is
not clear what . Do not believe - see for yourself by trying to call some action first for the adjacent "normal" lines ...

... and then for ours:

You can confirm the unnatural nature of our line by calling the type system window (
Ctrl-Shift-T or
Cmd-Shift-T ), informing you that our expression has
no type:

The type system is not an easy area, especially for novice programmers. The type system creates a semantic layer that defines the rules for the interaction and mutual definition of elements. By analogy with the classification of the animal world, in which there are different entities with certain relationships, for example, "elephants", "dogs", "animals", etc. (at the same time both “elephant” and “dog” are both “animals”, but “elephant” is not a “dog”).
In order for the behavior of our string in different contexts to become more predictable (and useful), we need to bring it to the appropriate type. In order not to complicate your life, we will again go to the trick and try to
peek at the properties of the
typesystem aspect of the “real” line.
Opening the tab with the code of our favorite
StringLiteralBase , you can find the following constructions:

Yeah, before us is the
Intention rule , as if to say that the entity being represented is a type of
String . It uses a special language
Quotation (
"Citation" ), allowing you to insert, for example, code into ActionScript or MXML, thereby achieving compactness and semanticity.
We create in our educational language aspect
Typesystem .

We import with the help of
Ctrl-L (or
Cmd-L ) the Quotation language into our project and reproduce the same exact logic in our language extension.

In the body of the method, by analogy with
StringLiteralBase, we reproduce the following:

Then — this is important — insert the
ClassifierType ...

By the key combination
Ctrl-R (
Cmd-R ) we call import of the model.


And finally, you can add a
String .

For reference: something like this looks like a similar code
without using the
Quotation extension.

The module can be compiled - now our entity has found its place in the
ActionScript type system.
Step 7. Left TransformationsMeanwhile, there are still a few things that should be mentioned in this article. At the end of Step 1, we asked an alias for our expression:

The editor has two more important behaviors - these are left and right transformations (you can learn more about them in the introductory article about RASE). In simple terms, we must teach the editor to turn a regular line into a screened one.
Add a new aspect of
Action to the language with the command
transform menu actions .

We give this entity the name
makeStringEscaped and start making edits. We are interested in the left transformation of
StringLiteralBase to
EscapedString .


We add a
simple item and start filling out the following template:

As a result, we should get something like this code:

The project can be compiled. Now when you add the
@ character to any string, it will instantly turn into an
EscapedString .




It remains to add the opposite action - transformation of the
EscapedString entity into the source string when deleting
@ .
Step 8. Improving Editor BehaviorGo to the Editor, where we already have a certain structure:

It is required to add a certain keyword to it, if it were deleted, the reverse transformation would occur. Select
Create new> cell action map .

Now you should learn how to handle the event of deleting the
@ symbol. There are two ways - difficult (interception of input from the keyboard) and simple (
action map ).

Our choice is small, select
DELETE and enter the code that would replace
EscapedString with
StringLiteral.
In the adjacent tab, select the field containing the
@ symbol in order to assign an
action map to it in the
Inspector window.

To make our transformation fully workable, we add the
editable: false parameter to the properties of the neighboring field (the opening quote).

Learning language extension is completely ready.



9. ConclusionWe hope that after reading this article, the creation of language extensions has ceased to be something unrealistic for a regular developer. You can start small and automate your work through the
intenions without creating language constructs. And when there is confidence and real need, you can start writing your own languages ​​and DSL. It is only important to learn to understand simple principles of work in the MPS platform, to navigate it and find ready-made solutions in other languages. In the following articles we will try to open this topic even deeper.