Child pages
  • Implementing generators for BaseLanguage's extensions

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This article showcase an idiomatic way for writing generators for BaseLanguage's extensions that operate with lvalue-expressions. We say that some BaseLanguage expression is lvalue if it can be used in the left-hand side of an assignment expression. Concepts that introduce such expressions should override either instance method Expression#isLValue() or static method Expression#lvalue() in behaviour aspect. 

The study consists of two independent languages that both of them are small extensions to BaseLanguage. The source code can be found in BlReference sample project in MPS distribution.

...

In this language, we show the way to generate custom BaseLanguage extensions that introduce new lvalue-expressions. The presented technique can be used for generating expressions like smodel property access or custom collection's element access by index.

The box BaseLanguage's extensions introduce extension introduces a new "box" type that wraps a variable and provides read & write operations over it. The whole language consists of three concepts:

  • BoxType that represents "box" type in a model.
  • BoxCreator that can be used in the new expression to create "box" instances
  • Box_ValueOperation that can be used as an operation of dot expression when its operand is of "box" type.

Image Added

We treat a dot-expression with "value" operation as lvalue-expression, so we override IOperation#lvalue() method in Box_ValueOperation's behaviour aspect. Once we've overridden this method, the dot-expression with "value" operation can be used at the left-hand side of the assignment. Along with it now this operation can be used in compound assignments (e.g. +=, -=) and increment and decrement operations. Our goal is to write a generator for Box_ValueOperation concept.

...

For instance, it will hard to transform "value" operation into Java lvalue-expression if at runtime "box" type is represented with Box interface that provides two methods - getValue and setValue. To overcome this issue we can use BaseLanguage's generation-time concept of "generic lvalue expression" into we can transform our expression: 

Image Added

Image Added

The "generic lvalue expression" consists of two obligatory roles: type and reference. The former role specifies the type of our original lvalue-expression while the latter role specifies the expression of type jetbrains.mps.references.Reference<T>. This type provides two methods: #get() in order to read value from evaluated variable and #set() - to assign new value to evaluated variable.

Also "generic lvalue expression" contains two optional roles: get value and assign value. These expressions are used to simplify the generated code and to produce fewer memory allocations of Reference<T> objects during execution. The first is used in case if the generated expression is used not in lvalue position while the second expression is used only when a generated expression is in left-hand side role of assignment. Note that there is special "value" keyword available in assign value expression and this keyword should be used exactly once in the expression.

jetbrains.mps.baseLanguage.date

TODO

In this language, we show how to generate custom BaseLanguage extensions that are introducing new expressions or customising existent ones that aggregate lvalue-expression in some role.

The date BaseLanguage's extension introduces new "date" type and several operations on "date" instances.

Image Added

At runtime, we will represent our "date" type with java.time.LocalDate:

Image Added

The "date" extension overloads plus operator for "date" and "int" instances so that this operation adds days (which amount is evaluated from right sub-expression) to a date that is evaluated from left sub-expression. At generation we transform this plus operator into a simple static method call:

Image Added

Image Added

To make our extension consistent, we also want overload plus assignment expression likewise we overloaded plus operator. The significant difference between plus operator and plus assignment expression is that in plus assignment a left sub-expression should be an lvalue so this expression has to be evaluated to a variable to which we can assign computed values. However, in Java, we can not pass variables through method invocations so we can not transform our expression into just a method call.

To approach this problem MPS provides "@byRef" generation time-concept. This expression wraps an lvalue-expression and during generation transforms it into an expression of jetbrains.mps.references.Reference<T> type. Given an instance of this type, you can produce get & set operations to a variable that is evaluated from wrapped lvalue-expression. 

With "@byRef" expression the plus assignment expression can be easily generated in the following way:

Image Added

Image Added

A composition of independent extensions 

Two extensions shown above do not depend on each other. Their both generators are designed with the use of generation-time concept provided with BaseLanguage. By their own, these generation-time facilities make generators consistent and less boiler-plate. In addition to it, extensions which generators are designed in a shown way can safely aggregate one another without having dependencies on each other:

Image Added